Harden CI runner and release gate security (#320)
## Summary - run untrusted pull-request jobs on ephemeral `ubuntu-24.04` runners - reserve the local backend runner pool for trusted branch pushes - remove world-writable Docker-socket fallbacks - pin core GitHub Actions and disable checkout credential persistence - remove the release-manager PHP parse-error fail-open path ## Why Pull-request code previously ran on persistent self-hosted runners with Docker access, and CI contained permission weakening and a release-gate break-glass success path. Those behaviors were unsafe for autonomous intake. ## Validation - workflow YAML parsed - backend AI workflow outputs are in sync - pinned action SHAs match the current v4 tags - `git diff --check` ## Risk and activation This is an R4 CI/release-policy change. Keep the PR draft for human review and let required CI prove the hosted-runner path before merge.
This commit is contained in:
+35
-49
@@ -19,7 +19,9 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
php:
|
php:
|
||||||
name: PHP ${{ matrix.suite }} (required)
|
name: PHP ${{ matrix.suite }} (required)
|
||||||
runs-on: [self-hosted, Linux, X64, pleno, backend, docker]
|
# Pull requests are untrusted and must use an ephemeral GitHub-hosted runner.
|
||||||
|
# Trusted branch pushes may use the local backend pool for throughput.
|
||||||
|
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-24.04' || 'backend' }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -29,25 +31,21 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Ensure Docker access
|
- name: Ensure Docker access
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
if docker ps >/dev/null 2>&1; then
|
docker ps >/dev/null 2>&1 || {
|
||||||
exit 0
|
echo "Docker is unavailable to the runner identity. Fix the isolated runner configuration; the workflow will not weaken /var/run/docker.sock permissions." >&2
|
||||||
fi
|
exit 1
|
||||||
test -S /var/run/docker.sock || (echo "Docker socket is not available." >&2; exit 1)
|
}
|
||||||
if command -v sudo >/dev/null 2>&1; then
|
|
||||||
sudo -n chmod 666 /var/run/docker.sock
|
|
||||||
else
|
|
||||||
chmod 666 /var/run/docker.sock
|
|
||||||
fi
|
|
||||||
docker ps >/dev/null
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
if: ${{ matrix.suite == 'unit' }}
|
if: ${{ matrix.suite == 'unit' }}
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
|
|
||||||
@@ -61,7 +59,7 @@ jobs:
|
|||||||
- name: Upload PHP suite logs
|
- name: Upload PHP suite logs
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||||
with:
|
with:
|
||||||
name: php-${{ matrix.suite }}-logs
|
name: php-${{ matrix.suite }}-logs
|
||||||
path: .tmp/ci-logs/${{ matrix.suite }}
|
path: .tmp/ci-logs/${{ matrix.suite }}
|
||||||
@@ -70,14 +68,16 @@ jobs:
|
|||||||
|
|
||||||
edge-agent:
|
edge-agent:
|
||||||
name: Edge Agent (required)
|
name: Edge Agent (required)
|
||||||
runs-on: [self-hosted, Linux, X64, pleno, backend]
|
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-24.04' || 'backend' }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
|
|
||||||
@@ -115,25 +115,21 @@ jobs:
|
|||||||
|
|
||||||
edge-broker:
|
edge-broker:
|
||||||
name: Edge Broker (required)
|
name: Edge Broker (required)
|
||||||
runs-on: [self-hosted, Linux, X64, pleno, backend, docker]
|
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-24.04' || 'backend' }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Ensure Docker access
|
- name: Ensure Docker access
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
if docker ps >/dev/null 2>&1; then
|
docker ps >/dev/null 2>&1 || {
|
||||||
exit 0
|
echo "Docker is unavailable to the runner identity. Fix the isolated runner configuration; the workflow will not weaken /var/run/docker.sock permissions." >&2
|
||||||
fi
|
exit 1
|
||||||
test -S /var/run/docker.sock || (echo "Docker socket is not available." >&2; exit 1)
|
}
|
||||||
if command -v sudo >/dev/null 2>&1; then
|
|
||||||
sudo -n chmod 666 /var/run/docker.sock
|
|
||||||
else
|
|
||||||
chmod 666 /var/run/docker.sock
|
|
||||||
fi
|
|
||||||
docker ps >/dev/null
|
|
||||||
|
|
||||||
- name: Materialize CI compose env files
|
- name: Materialize CI compose env files
|
||||||
run: |
|
run: |
|
||||||
@@ -147,7 +143,7 @@ jobs:
|
|||||||
docker compose -f docker-compose.example.yml config > /dev/null
|
docker compose -f docker-compose.example.yml config > /dev/null
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
|
|
||||||
@@ -161,7 +157,7 @@ jobs:
|
|||||||
|
|
||||||
edge-gateway-backend:
|
edge-gateway-backend:
|
||||||
name: Edge Gateway Backend (required)
|
name: Edge Gateway Backend (required)
|
||||||
runs-on: [self-hosted, Linux, X64, pleno, backend, docker]
|
runs-on: ${{ github.event_name == 'pull_request' && 'ubuntu-24.04' || 'backend' }}
|
||||||
env:
|
env:
|
||||||
COMPOSE_FILE: docker-compose.yml:.github/docker-compose.ci.yml
|
COMPOSE_FILE: docker-compose.yml:.github/docker-compose.ci.yml
|
||||||
COMPOSE_PROJECT_NAME: edge-gateway-backend-${{ github.run_id }}-${{ github.run_attempt }}
|
COMPOSE_PROJECT_NAME: edge-gateway-backend-${{ github.run_id }}-${{ github.run_attempt }}
|
||||||
@@ -175,21 +171,17 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Ensure Docker access
|
- name: Ensure Docker access
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
if docker ps >/dev/null 2>&1; then
|
docker ps >/dev/null 2>&1 || {
|
||||||
exit 0
|
echo "Docker is unavailable to the runner identity. Fix the isolated runner configuration; the workflow will not weaken /var/run/docker.sock permissions." >&2
|
||||||
fi
|
exit 1
|
||||||
test -S /var/run/docker.sock || (echo "Docker socket is not available." >&2; exit 1)
|
}
|
||||||
if command -v sudo >/dev/null 2>&1; then
|
|
||||||
sudo -n chmod 666 /var/run/docker.sock
|
|
||||||
else
|
|
||||||
chmod 666 /var/run/docker.sock
|
|
||||||
fi
|
|
||||||
docker ps >/dev/null
|
|
||||||
|
|
||||||
- name: Allocate CI ports
|
- name: Allocate CI ports
|
||||||
run: |
|
run: |
|
||||||
@@ -240,7 +232,7 @@ jobs:
|
|||||||
printf '\nEDGE_PUBLIC_BROKER_URL=http://edge-broker:4300/edge-broker\n' >> .env
|
printf '\nEDGE_PUBLIC_BROKER_URL=http://edge-broker:4300/edge-broker\n' >> .env
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
|
|
||||||
@@ -411,12 +403,6 @@ jobs:
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if printf '%s' "$response_body" | grep -qi '<b>Parse error</b>'; then
|
|
||||||
echo "::warning::Release Manager API returned a PHP parse error while recording the gate. Treating this as a break-glass pass so a fix can be deployed."
|
|
||||||
printf '%s\n' "$response_body"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf '%s\n' "$response_body"
|
printf '%s\n' "$response_body"
|
||||||
echo "Release Manager gate failed with HTTP $http_code." >&2
|
echo "Release Manager gate failed with HTTP $http_code." >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
Reference in New Issue
Block a user