From e1549465c2247292837b52d65191547249030086 Mon Sep 17 00:00:00 2001 From: Simon Scatton Date: Mon, 12 Oct 2026 14:54:43 +0200 Subject: [PATCH 1/3] refactor(ci): extract release qualification and serialize Codex reviews Signed-off-by: Simon Scatton --- .agents/skills/watch-github-actions/SKILL.md | 10 +- .github/workflows/codex-compatibility.yml | 2 +- .github/workflows/codex-security.yml | 4 +- .github/workflows/release-qualification.yml | 241 +++++++++++++++++++ .github/workflows/release-tag.yml | 199 +-------------- CI.md | 18 +- 6 files changed, 269 insertions(+), 205 deletions(-) create mode 100644 .github/workflows/release-qualification.yml diff --git a/.agents/skills/watch-github-actions/SKILL.md b/.agents/skills/watch-github-actions/SKILL.md index 41b9a3fcff..11482d62ad 100644 --- a/.agents/skills/watch-github-actions/SKILL.md +++ b/.agents/skills/watch-github-actions/SKILL.md @@ -163,7 +163,9 @@ During `0.x`, a minor train permits compatibility findings as warnings; a patch train or no active train rejects them. Compare the current train's version with the latest stable release; commit messages are irrelevant. Compilation, baseline, and tool errors remain fatal. The `protobuf_compatibility` suite participates in -the `release-tag-v1` qualification profile. Both tagged pre-release and stable +the `release-tag-v1` qualification profile. Release Tag calls the reusable +`release-qualification.yml` workflow to run the checks and collect their results. +Both tagged pre-release and stable publication require this profile to pass. Failed, cancelled, or skipped suites block publication; build artifacts and qualification evidence remain in Actions storage for diagnosis. Source-SHA images are staging inputs for qualification. @@ -175,8 +177,10 @@ For `Codex Compatibility Review`, inspect its job summary and the candidate and baseline SHAs before interpreting findings. `complete` describes execution and coverage, not compatibility: also read the assessment and findings. An `error`, incomplete coverage, or missing artifact means no clean review is -available. The job is advisory and independent of publication gates; the -qualification summary points to it without waiting for completion. Do not +available. Its findings are advisory and do not affect the qualification result. +The review starts after Security Scan finishes, and the two Codex workflows share +the `codex-release-review` concurrency group to prevent overlapping API usage +across runs. The qualification caller waits for both reviews to finish. Do not rerun Release Tag to debug this reviewer. Use its dedicated manual workflow with an existing candidate tag; that path does not publish release artifacts. diff --git a/.github/workflows/codex-compatibility.yml b/.github/workflows/codex-compatibility.yml index b465916bfd..8b2dfebb56 100644 --- a/.github/workflows/codex-compatibility.yml +++ b/.github/workflows/codex-compatibility.yml @@ -28,7 +28,7 @@ permissions: contents: read concurrency: - group: codex-compatibility-${{ inputs.candidate_ref }}-${{ github.run_id }} + group: codex-release-review cancel-in-progress: false jobs: diff --git a/.github/workflows/codex-security.yml b/.github/workflows/codex-security.yml index 91426db468..4ffc350b8c 100644 --- a/.github/workflows/codex-security.yml +++ b/.github/workflows/codex-security.yml @@ -71,8 +71,8 @@ permissions: security-events: write concurrency: - group: codex-security-release-qualification - cancel-in-progress: true + group: codex-release-review + cancel-in-progress: false env: CODEX_SECURITY_MAX_CONCURRENT_THREADS: "8" diff --git a/.github/workflows/release-qualification.yml b/.github/workflows/release-qualification.yml new file mode 100644 index 0000000000..3406951eb3 --- /dev/null +++ b/.github/workflows/release-qualification.yml @@ -0,0 +1,241 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +name: Release Qualification + +on: + workflow_call: + inputs: + release-tag: + description: Release tag identifying the candidate + required: true + type: string + source-sha: + description: Source commit of the candidate artifacts in the calling run + required: true + type: string + is-prerelease: + description: Whether the candidate is a pre-release + required: true + type: boolean + outputs: + artifact-name: + description: Artifact containing the qualification result + value: ${{ jobs.qualification-result.outputs.artifact-name }} + current-profile-passed: + description: Whether every required qualification suite passed + value: ${{ jobs.qualification-result.outputs.current-profile-passed }} + secrets: + CODEX_SECURITY_API_KEY: + required: true + CACHIX_AUTH_TOKEN: + required: false + +permissions: + contents: read + packages: read + +env: + RELEASE_TAG: ${{ inputs.release-tag }} + +defaults: + run: + shell: bash + +jobs: + security: + name: Security Scan + permissions: + actions: read + contents: read + packages: read + security-events: write + uses: ./.github/workflows/security-scan.yml + with: + candidate_ref: ${{ inputs.release-tag }} + fail-on-codex-findings: true + fail-on-static-findings: false + images: | + ghcr.io/nvidia/openshell/gateway:${{ inputs.source-sha }} + ghcr.io/nvidia/openshell/sandbox:${{ inputs.source-sha }} + ghcr.io/nvidia/openshell/supervisor:${{ inputs.source-sha }} + secrets: + CODEX_SECURITY_API_KEY: ${{ secrets.CODEX_SECURITY_API_KEY }} + CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} + + prepare-integration: + permissions: + actions: read + contents: read + packages: read + uses: ./.github/workflows/prepare-integration-inputs.yml + with: + source-sha: ${{ inputs.source-sha }} + deb-artifact-name: deb-linux-amd64 + rpm-artifact-name: rpm-linux-x86_64 + + conformance-integration: + needs: prepare-integration + permissions: + actions: read + contents: read + packages: read + uses: ./.github/workflows/integration-runner.yml + with: + category: conformance + source-sha: ${{ needs.prepare-integration.outputs.source_sha }} + integration-inputs-artifact-id: ${{ needs.prepare-integration.outputs.integration_inputs_artifact_id }} + test-matrix: >- + [ + {"environment":"ubuntu-docker-rootful","installer":"deb","testsuite":"conformance"}, + {"environment":"ubuntu-k3s","installer":"k3s","testsuite":"conformance"}, + {"environment":"fedora-podman-rootful","installer":"rpm","testsuite":"conformance"}, + {"environment":"fedora-podman-rootless","installer":"rpm","testsuite":"conformance"} + ] + + feature-specific-integration: + needs: prepare-integration + permissions: + actions: read + contents: read + packages: read + uses: ./.github/workflows/integration-runner.yml + with: + category: feature-specific + source-sha: ${{ needs.prepare-integration.outputs.source_sha }} + integration-inputs-artifact-id: ${{ needs.prepare-integration.outputs.integration_inputs_artifact_id }} + test-matrix: >- + [ + {"environment":"fedora-podman-rootful","installer":"rpm","testsuite":"provider-refresh"}, + {"environment":"fedora-podman-rootless","installer":"rpm","testsuite":"provider-refresh"} + ] + + docker-e2e: + permissions: + actions: read + contents: read + packages: read + uses: ./.github/workflows/e2e-docker-test.yml + with: + image-tag: ${{ inputs.source-sha }} + checkout-ref: ${{ inputs.source-sha }} + runner: linux-arm64-cpu8 + conformance-artifact-prefix: openshell-conformance + + vm-e2e: + permissions: + actions: read + contents: read + packages: read + uses: ./.github/workflows/e2e-vm-test.yml + with: + checkout-ref: ${{ inputs.source-sha }} + conformance-artifact-prefix: openshell-conformance + + protobuf-compatibility: + name: Protobuf Compatibility + runs-on: linux-amd64-cpu8 + timeout-minutes: 15 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + ref: ${{ inputs.source-sha }} + + - uses: ./.github/actions/check-protobuf-compatibility + with: + ref: refs/tags/${{ env.RELEASE_TAG }} + + compatibility-review: + name: Compatibility Review (advisory) + needs: security + if: ${{ !cancelled() }} + permissions: + contents: read + uses: ./.github/workflows/codex-compatibility.yml + with: + candidate_ref: ${{ inputs.release-tag }} + source_sha: ${{ inputs.source-sha }} + secrets: + CODEX_SECURITY_API_KEY: ${{ secrets.CODEX_SECURITY_API_KEY }} + + qualification-result: + name: Release Qualification + if: always() + needs: + - protobuf-compatibility + - security + - conformance-integration + - feature-specific-integration + - docker-e2e + - vm-e2e + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: read + outputs: + artifact-name: ${{ steps.summary.outputs.artifact-name }} + current-profile-passed: ${{ steps.summary.outputs.current-profile-passed }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + ref: ${{ inputs.source-sha }} + + - name: Record qualification result + id: summary + env: + CONFORMANCE_RESULT: ${{ needs.conformance-integration.result }} + DOCKER_E2E_RESULT: ${{ needs.docker-e2e.result }} + FEATURE_INTEGRATION_RESULT: ${{ needs.feature-specific-integration.result }} + IS_PRERELEASE: ${{ inputs.is-prerelease }} + PROTO_COMPATIBILITY_RESULT: ${{ needs.protobuf-compatibility.result }} + SECURITY_RESULT: ${{ needs.security.result }} + SOURCE_SHA: ${{ inputs.source-sha }} + VM_E2E_RESULT: ${{ needs.vm-e2e.result }} + run: | + set -euo pipefail + current_profile_passed=$(tasks/scripts/generate-qualification-summary.sh qualification-summary.json) + artifact_name="qualification-${RELEASE_TAG}-run-${GITHUB_RUN_ID}-attempt-${GITHUB_RUN_ATTEMPT}" + run_url=$(jq -r '.run.url' qualification-summary.json) + + { + echo "artifact-name=${artifact_name}" + echo "current-profile-passed=${current_profile_passed}" + } >> "${GITHUB_OUTPUT}" + + { + echo "## Release qualification" + echo + echo "- Candidate: \`${RELEASE_TAG}\` (\`${SOURCE_SHA}\`)" + echo "- Current qualification profile passed: **${current_profile_passed}**" + echo "- RFC-0014 qualification coverage complete: **false**" + echo "- Run: [${GITHUB_RUN_ID}, attempt ${GITHUB_RUN_ATTEMPT}](${run_url})" + echo + echo "| Suite | Result |" + echo "| --- | --- |" + echo "| Protobuf API compatibility | ${PROTO_COMPATIBILITY_RESULT} |" + echo "| Security | ${SECURITY_RESULT} |" + echo "| Conformance integration | ${CONFORMANCE_RESULT} |" + echo "| Feature integration | ${FEATURE_INTEGRATION_RESULT} |" + echo "| Docker E2E | ${DOCKER_E2E_RESULT} |" + echo "| VM E2E | ${VM_E2E_RESULT} |" + echo + echo "Advisory compatibility findings do not affect the qualification result." + echo "See the Compatibility Review job and compatibility-review-run-${GITHUB_RUN_ID}-attempt-${GITHUB_RUN_ATTEMPT} artifact in [this run](${run_url})." + } >> "${GITHUB_STEP_SUMMARY}" + + - name: Upload qualification result + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: ${{ steps.summary.outputs.artifact-name }} + path: qualification-summary.json + retention-days: 90 + if-no-files-found: error + + - name: Require current qualification profile before publication + if: steps.summary.outputs.current-profile-passed != 'true' + run: | + echo "Release ${RELEASE_TAG} did not pass the current release-tag-v1 qualification profile." >&2 + exit 1 diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 7a225270a6..bcb3eadeff 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -130,207 +130,22 @@ jobs: image-tag: ${{ needs.compute-versions.outputs.source_sha }} checkout-ref: ${{ needs.compute-versions.outputs.source_sha }} - security: - name: Security Scan - needs: [compute-versions, build-images] + qualification-result: + name: Release Qualification + needs: [compute-versions, build-binaries, build-vm-driver, build-images, build-deb, build-rpm] permissions: actions: read contents: read packages: read security-events: write - uses: ./.github/workflows/security-scan.yml - with: - candidate_ref: ${{ inputs.tag || github.ref_name }} - fail-on-codex-findings: true - fail-on-static-findings: false - images: | - ghcr.io/nvidia/openshell/gateway:${{ needs.compute-versions.outputs.source_sha }} - ghcr.io/nvidia/openshell/sandbox:${{ needs.compute-versions.outputs.source_sha }} - ghcr.io/nvidia/openshell/supervisor:${{ needs.compute-versions.outputs.source_sha }} - secrets: - CODEX_SECURITY_API_KEY: ${{ secrets.CODEX_SECURITY_API_KEY }} - CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} - - prepare-integration: - needs: [compute-versions, build-binaries, build-deb, build-images, build-rpm] - permissions: - actions: read - contents: read - packages: read - uses: ./.github/workflows/prepare-integration-inputs.yml + uses: ./.github/workflows/release-qualification.yml with: + release-tag: ${{ inputs.tag || github.ref_name }} source-sha: ${{ needs.compute-versions.outputs.source_sha }} - deb-artifact-name: deb-linux-amd64 - rpm-artifact-name: rpm-linux-x86_64 - - conformance-integration: - needs: prepare-integration - permissions: - actions: read - contents: read - packages: read - uses: ./.github/workflows/integration-runner.yml - with: - category: conformance - source-sha: ${{ needs.prepare-integration.outputs.source_sha }} - integration-inputs-artifact-id: ${{ needs.prepare-integration.outputs.integration_inputs_artifact_id }} - test-matrix: >- - [ - {"environment":"ubuntu-docker-rootful","installer":"deb","testsuite":"conformance"}, - {"environment":"ubuntu-k3s","installer":"k3s","testsuite":"conformance"}, - {"environment":"fedora-podman-rootful","installer":"rpm","testsuite":"conformance"}, - {"environment":"fedora-podman-rootless","installer":"rpm","testsuite":"conformance"} - ] - - feature-specific-integration: - needs: prepare-integration - permissions: - actions: read - contents: read - packages: read - uses: ./.github/workflows/integration-runner.yml - with: - category: feature-specific - source-sha: ${{ needs.prepare-integration.outputs.source_sha }} - integration-inputs-artifact-id: ${{ needs.prepare-integration.outputs.integration_inputs_artifact_id }} - test-matrix: >- - [ - {"environment":"fedora-podman-rootful","installer":"rpm","testsuite":"provider-refresh"}, - {"environment":"fedora-podman-rootless","installer":"rpm","testsuite":"provider-refresh"} - ] - - docker-e2e: - needs: [compute-versions, build-binaries, build-images] - permissions: - actions: read - contents: read - packages: read - uses: ./.github/workflows/e2e-docker-test.yml - with: - image-tag: ${{ needs.compute-versions.outputs.source_sha }} - checkout-ref: ${{ needs.compute-versions.outputs.source_sha }} - runner: linux-arm64-cpu8 - conformance-artifact-prefix: openshell-conformance - - vm-e2e: - needs: [compute-versions, build-binaries, build-vm-driver] - permissions: - actions: read - contents: read - packages: read - uses: ./.github/workflows/e2e-vm-test.yml - with: - checkout-ref: ${{ needs.compute-versions.outputs.source_sha }} - conformance-artifact-prefix: openshell-conformance - - protobuf-compatibility: - name: Protobuf Compatibility - needs: compute-versions - runs-on: linux-amd64-cpu8 - timeout-minutes: 15 - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - persist-credentials: false - ref: ${{ needs.compute-versions.outputs.source_sha }} - - - uses: ./.github/actions/check-protobuf-compatibility - with: - ref: refs/tags/${{ env.RELEASE_TAG }} - - compatibility-review: - name: Compatibility Review (advisory) - needs: compute-versions - permissions: - contents: read - uses: ./.github/workflows/codex-compatibility.yml - with: - candidate_ref: ${{ inputs.tag || github.ref_name }} - source_sha: ${{ needs.compute-versions.outputs.source_sha }} + is-prerelease: ${{ needs.compute-versions.outputs.is_prerelease == 'true' }} secrets: CODEX_SECURITY_API_KEY: ${{ secrets.CODEX_SECURITY_API_KEY }} - - qualification-result: - name: Release Qualification - if: always() - needs: - - compute-versions - - protobuf-compatibility - - security - - conformance-integration - - feature-specific-integration - - docker-e2e - - vm-e2e - runs-on: ubuntu-latest - timeout-minutes: 5 - permissions: - contents: read - outputs: - artifact-name: ${{ steps.summary.outputs.artifact-name }} - current-profile-passed: ${{ steps.summary.outputs.current-profile-passed }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - ref: ${{ needs.compute-versions.outputs.source_sha || github.sha }} - - - name: Record qualification result - id: summary - env: - CONFORMANCE_RESULT: ${{ needs.conformance-integration.result }} - DOCKER_E2E_RESULT: ${{ needs.docker-e2e.result }} - FEATURE_INTEGRATION_RESULT: ${{ needs.feature-specific-integration.result }} - IS_PRERELEASE: ${{ needs.compute-versions.outputs.is_prerelease }} - PROTO_COMPATIBILITY_RESULT: ${{ needs.protobuf-compatibility.result }} - SECURITY_RESULT: ${{ needs.security.result }} - SOURCE_SHA: ${{ needs.compute-versions.outputs.source_sha }} - VM_E2E_RESULT: ${{ needs.vm-e2e.result }} - run: | - set -euo pipefail - current_profile_passed=$(tasks/scripts/generate-qualification-summary.sh qualification-summary.json) - artifact_name="qualification-${RELEASE_TAG}-run-${GITHUB_RUN_ID}-attempt-${GITHUB_RUN_ATTEMPT}" - run_url=$(jq -r '.run.url' qualification-summary.json) - - { - echo "artifact-name=${artifact_name}" - echo "current-profile-passed=${current_profile_passed}" - } >> "${GITHUB_OUTPUT}" - - { - echo "## Release qualification" - echo - echo "- Candidate: \`${RELEASE_TAG}\` (\`${SOURCE_SHA}\`)" - echo "- Current qualification profile passed: **${current_profile_passed}**" - echo "- RFC-0014 qualification coverage complete: **false**" - echo "- Run: [${GITHUB_RUN_ID}, attempt ${GITHUB_RUN_ATTEMPT}](${run_url})" - echo - echo "| Suite | Result |" - echo "| --- | --- |" - echo "| Protobuf API compatibility | ${PROTO_COMPATIBILITY_RESULT} |" - echo "| Security | ${SECURITY_RESULT} |" - echo "| Conformance integration | ${CONFORMANCE_RESULT} |" - echo "| Feature integration | ${FEATURE_INTEGRATION_RESULT} |" - echo "| Docker E2E | ${DOCKER_E2E_RESULT} |" - echo "| VM E2E | ${VM_E2E_RESULT} |" - echo - echo "Advisory compatibility review runs independently and does not gate publication." - echo "See the Compatibility Review job and compatibility-review-run-${GITHUB_RUN_ID}-attempt-${GITHUB_RUN_ATTEMPT} artifact in [this run](${run_url})." - } >> "${GITHUB_STEP_SUMMARY}" - - - name: Upload qualification result - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 - with: - name: ${{ steps.summary.outputs.artifact-name }} - path: qualification-summary.json - retention-days: 90 - if-no-files-found: error - - - name: Require current qualification profile before publication - if: steps.summary.outputs.current-profile-passed != 'true' - run: | - echo "Release ${RELEASE_TAG} did not pass the current release-tag-v1 qualification profile." >&2 - exit 1 + CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} build-python-wheel: name: Build Python Wheel diff --git a/CI.md b/CI.md index de6c53511b..94f6d1ce88 100644 --- a/CI.md +++ b/CI.md @@ -74,8 +74,10 @@ so Windows failures do not fail the workflow. ### Advisory release compatibility review -`Codex Compatibility Review` runs alongside tagged release qualification. It -reviews the cumulative diff from the previous reachable stable release to the +`Codex Compatibility Review` runs after Security Scan in the reusable release +qualification workflow. Both Codex workflows share the `codex-release-review` +concurrency group, so separate release or manual runs cannot overlap their API +usage. The review covers the cumulative diff from the previous reachable stable release to the exact candidate commit, using the same tag-derived patch/minor policy as the protobuf check. It reviews public Rust, Python, Go, and TypeScript SDKs, API behavior, CLI contracts, configuration, policy, Helm, and persisted state. @@ -90,9 +92,9 @@ repository; candidate-side agent configuration and instructions are not loaded. It does not run candidate builds or tests. The review has a 30-minute execution limit inside a 40-minute job timeout. -This rollout is report-only: findings and review failures cannot block -publication. The job is independent of the required qualification dependency -chain. Its summary distinguishes complete, incomplete, and failed execution +This rollout is report-only: findings and review failures remain advisory. +The qualification caller waits for the review to finish, but its result does not +affect the required profile. Its summary distinguishes complete, incomplete, and failed execution from the agent's compatibility assessment. Missing credentials, invalid baselines, source mismatches, malformed reports, and timeouts are not clean reviews. A completed review still does not prove that no breaks exist. @@ -288,8 +290,9 @@ jobs: ``` Set `needs: security` on a downstream promotion job to require successful scans. -The tagged release workflow records protobuf, security, and integration outcomes in a -qualification job after publishing its commit-addressed OCI images. A failed +The tagged release workflow calls `release-qualification.yml` to run and record +protobuf, security, and integration checks after building its candidate artifacts +and publishing its commit-addressed OCI images. A failed check remains visible in the workflow, with build artifacts and evidence retained in Actions storage. Both pre-release and stable publication require the implemented `release-tag-v1` profile to pass; that profile is an incremental subset of RFC @@ -547,6 +550,7 @@ These workflows run after merge to publish dev/tagged artifacts and verify them. |---|---| | `.github/workflows/release-dev.yml` | Publishes the rolling `dev` build on every push to `main`. Builds gateway, sandbox, and supervisor images and binaries, packages, wheels, and pushes the Helm chart as `oci://ghcr.io/nvidia/openshell/helm-chart:0.0.0-dev` (plus an immutable `0.0.0-dev.` pin). Also dispatchable manually. | | `.github/workflows/release-tag.yml` | Publishes tagged stable releases and manually dispatched pre-releases. Its automatic tag trigger excludes `-pre.*`. Both require the currently implemented qualification profile to pass before publication; the summary identifies the remaining RFC 0014 coverage. Failed candidates retain build artifacts and evidence in Actions storage. Source-SHA OCI images remain available as qualification inputs. | +| `.github/workflows/release-qualification.yml` | Reusable qualification suites and result aggregation. Runs security scans, conformance and feature integration, Docker and VM E2E, protobuf compatibility, and advisory compatibility review. | | `.github/workflows/snap-package.yml` | Builds Snap and component artifacts for Release Dev and Release Tag without Store credentials or publication. | | `.github/workflows/snap-publish.yml` | Uploads existing Snap and component artifacts to the Store without rebuilding. Release Dev calls it directly for `latest/edge` after Snap builds and requires it to succeed before creating the dev release. Release Tag calls it for `latest/stable` only for stable releases, after qualification and release assembly succeed. | | `.github/workflows/release-canary.yml` | Smoke-tests published dev artifacts in the `macos`, `ubuntu-deb`, `ubuntu-snap-system-docker`, `fedora`, and `kubernetes` (kind + Helm) jobs. Each job reaches its gateway and creates, exercises, and deletes a sandbox. The `ubuntu-snap-system-docker` job verifies a compatible system Docker lifecycle, while `ubuntu-snap-docker-preflight` tests fail-fast behavior when Docker is absent or supplied by the Docker snap. The positive Snap lane also runs a local policy containment check with the packaged prover. It runs automatically after `Release Dev` succeeds and supports manual dispatch (`gh workflow run release-canary.yml --ref `). See the `test-release-canary` skill for the playbook and local kind reproduction. | From 7988c45ff0532d4f0760b091daf9b6f4bf683e5d Mon Sep 17 00:00:00 2001 From: Simon Scatton Date: Mon, 12 Oct 2026 15:59:33 +0200 Subject: [PATCH 2/3] fix(ci): queue Codex reviews without security ordering Signed-off-by: Simon Scatton --- .agents/skills/watch-github-actions/SKILL.md | 8 +++++--- .github/workflows/codex-compatibility.yml | 1 + .github/workflows/codex-security.yml | 1 + .github/workflows/release-qualification.yml | 2 -- CI.md | 10 ++++++---- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.agents/skills/watch-github-actions/SKILL.md b/.agents/skills/watch-github-actions/SKILL.md index 11482d62ad..ae212fd5dc 100644 --- a/.agents/skills/watch-github-actions/SKILL.md +++ b/.agents/skills/watch-github-actions/SKILL.md @@ -178,9 +178,11 @@ candidate and baseline SHAs before interpreting findings. `complete` describes execution and coverage, not compatibility: also read the assessment and findings. An `error`, incomplete coverage, or missing artifact means no clean review is available. Its findings are advisory and do not affect the qualification result. -The review starts after Security Scan finishes, and the two Codex workflows share -the `codex-release-review` concurrency group to prevent overlapping API usage -across runs. The qualification caller waits for both reviews to finish. Do not +The review is scheduled independently of Security Scan. The two Codex workflows +share the `codex-release-review` concurrency group with `queue: max`, retaining +up to 100 pending reviews while preventing overlapping API usage across runs. +Either review can run first; other security scanners run in parallel. +The qualification caller waits for both reviews to finish. Do not rerun Release Tag to debug this reviewer. Use its dedicated manual workflow with an existing candidate tag; that path does not publish release artifacts. diff --git a/.github/workflows/codex-compatibility.yml b/.github/workflows/codex-compatibility.yml index 8b2dfebb56..c26f4cddb6 100644 --- a/.github/workflows/codex-compatibility.yml +++ b/.github/workflows/codex-compatibility.yml @@ -30,6 +30,7 @@ permissions: concurrency: group: codex-release-review cancel-in-progress: false + queue: max jobs: review: diff --git a/.github/workflows/codex-security.yml b/.github/workflows/codex-security.yml index 4ffc350b8c..3fd305554b 100644 --- a/.github/workflows/codex-security.yml +++ b/.github/workflows/codex-security.yml @@ -73,6 +73,7 @@ permissions: concurrency: group: codex-release-review cancel-in-progress: false + queue: max env: CODEX_SECURITY_MAX_CONCURRENT_THREADS: "8" diff --git a/.github/workflows/release-qualification.yml b/.github/workflows/release-qualification.yml index 3406951eb3..e62e3f3971 100644 --- a/.github/workflows/release-qualification.yml +++ b/.github/workflows/release-qualification.yml @@ -149,8 +149,6 @@ jobs: compatibility-review: name: Compatibility Review (advisory) - needs: security - if: ${{ !cancelled() }} permissions: contents: read uses: ./.github/workflows/codex-compatibility.yml diff --git a/CI.md b/CI.md index 94f6d1ce88..707664c993 100644 --- a/CI.md +++ b/CI.md @@ -74,10 +74,12 @@ so Windows failures do not fail the workflow. ### Advisory release compatibility review -`Codex Compatibility Review` runs after Security Scan in the reusable release -qualification workflow. Both Codex workflows share the `codex-release-review` -concurrency group, so separate release or manual runs cannot overlap their API -usage. The review covers the cumulative diff from the previous reachable stable release to the +`Codex Compatibility Review` is scheduled independently of Security Scan in the +reusable release qualification workflow. Both Codex workflows share the +`codex-release-review` concurrency group with `queue: max`, so only one review +runs at a time and up to 100 pending reviews are retained across release and +manual runs. Either review can run first; other security scanners run in parallel. +The review covers the cumulative diff from the previous reachable stable release to the exact candidate commit, using the same tag-derived patch/minor policy as the protobuf check. It reviews public Rust, Python, Go, and TypeScript SDKs, API behavior, CLI contracts, configuration, policy, Helm, and persisted state. From f05c4ed7accc0d2dec68ced408bf61b877d62509 Mon Sep 17 00:00:00 2001 From: Simon Scatton Date: Mon, 12 Oct 2026 17:06:20 +0200 Subject: [PATCH 3/3] fix(ci): retain qualification evidence after build failures Signed-off-by: Simon Scatton --- .github/workflows/release-tag.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index bcb3eadeff..549618a358 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -132,6 +132,7 @@ jobs: qualification-result: name: Release Qualification + if: always() && needs.compute-versions.result == 'success' needs: [compute-versions, build-binaries, build-vm-driver, build-images, build-deb, build-rpm] permissions: actions: read