diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08d257f..0521c3d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,7 @@ jobs: - run: pnpm run lint - run: pnpm run test - run: pnpm run typecheck + - run: pnpm run test:ci-workflow - name: OpenAPI document is up to date with the committed JSON Schemas run: pnpm --filter @ddn/api run openapi:check - name: Merkle V1 golden vectors are up to date with the committed implementation @@ -151,7 +152,12 @@ jobs: # cross-architecture validation and does not overwrite policy.wasm, # manifest.json, or the profile either way. # - # Explicitly experimental and non-blocking (continue-on-error: true): + # Explicitly experimental and non-blocking: the validation step records + # its result, emits a visible Actions warning and uploads diagnostics, but + # exits successfully so a known experimental crash does not mark an + # otherwise green commit with a misleading red check. A success here is + # therefore NOT evidence that amd64 reproducibility passed; the step + # summary and diagnostics artifact remain the source of that result. # native amd64 currently fails nondeterministically with SIGSEGV in # host build-script binaries (proc-macro2, serde_json, ...) -- real, # reproduced on this native GitHub-hosted amd64 runner AND under QEMU, @@ -163,7 +169,6 @@ jobs: # (not full rebuild loops or core dumps) for that investigation. name: Experimental cross-architecture validation (linux/amd64, non-blocking) runs-on: ubuntu-latest - continue-on-error: true steps: - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4 @@ -174,12 +179,36 @@ jobs: - run: pnpm install --frozen-lockfile - run: pnpm --filter @ddn/schemas run build - run: node scripts/gen-reason-codes.mjs - - run: ./scripts/policy-reproducibility.sh - - name: Collect diagnostics (failure only) - if: failure() + - name: Run experimental amd64 validation without gating the commit + id: amd64-validation + shell: bash + run: | + set +e + ./scripts/policy-reproducibility.sh + status=$? + set -e + + if [ "$status" -eq 0 ]; then + echo "failed=false" >> "$GITHUB_OUTPUT" + echo "### Experimental linux/amd64 validation: PASS" >> "$GITHUB_STEP_SUMMARY" + else + echo "failed=true" >> "$GITHUB_OUTPUT" + echo "::warning title=Experimental linux/amd64 validation failed::Known non-blocking amd64 toolchain investigation failed with exit code $status; diagnostics will be uploaded. The linux/arm64 release gate is unaffected." + { + echo "### Experimental linux/amd64 validation: DID NOT PASS" + echo + echo "Exit code: $status. This check is diagnostic and does not gate the linux/arm64 release." + } >> "$GITHUB_STEP_SUMMARY" + fi + + exit 0 + - name: Collect diagnostics (experimental failure only) + if: steps.amd64-validation.outputs.failed == 'true' + continue-on-error: true run: ./scripts/diagnose-amd64-crash.sh - - name: Upload diagnostics (failure only) - if: failure() + - name: Upload diagnostics (experimental failure only) + if: steps.amd64-validation.outputs.failed == 'true' + continue-on-error: true uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: amd64-crash-diagnostics diff --git a/package.json b/package.json index 73513a4..ab25837 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "verify:milestone-2": "./scripts/verify-milestone-2.sh", "public-release-check": "node scripts/public-release-check.mjs --mode git-worktree", "test:public-release": "node --test scripts/public-snapshot-files.test.mjs && node scripts/public-release-check.mjs --self-test", + "test:ci-workflow": "node --test scripts/ci-workflow.test.mjs", "secrets:gitleaks": "node scripts/gitleaks-gate.mjs", "secrets:trufflehog": "node scripts/trufflehog-gate.mjs", "sbom": "node scripts/generate-sbom.mjs", diff --git a/scripts/ci-workflow.test.mjs b/scripts/ci-workflow.test.mjs new file mode 100644 index 0000000..495196a --- /dev/null +++ b/scripts/ci-workflow.test.mjs @@ -0,0 +1,29 @@ +#!/usr/bin/env node +// SPDX-License-Identifier: Apache-2.0 +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; + +const workflow = readFileSync(new URL('../.github/workflows/ci.yml', import.meta.url), 'utf8'); +const amd64Job = workflow.match( + / cross-architecture-amd64:\n([\s\S]*?)(?=\n [a-z][a-z0-9-]*:\n)/, +)?.[1]; + +test('experimental amd64 validation reports failure without producing a red commit check', () => { + assert.ok(amd64Job, 'cross-architecture-amd64 job must exist'); + assert.doesNotMatch( + amd64Job, + /^ continue-on-error: true$/m, + 'job-level continue-on-error leaves a red check-run even when the workflow succeeds', + ); + assert.match(amd64Job, /id: amd64-validation/); + assert.match(amd64Job, /echo "failed=true" >> "\$GITHUB_OUTPUT"/); + assert.match(amd64Job, /::warning title=Experimental linux\/amd64 validation failed/); + assert.match(amd64Job, /^ exit 0$/m); + assert.match( + amd64Job, + /if: steps\.amd64-validation\.outputs\.failed == 'true'/, + 'diagnostics must still run when the experimental validation fails', + ); +}); +