返回 DeepSeek-Reasonix
release-candidate-verify.yml
根目录 / .github / workflows / release-candidate-verify.yml
1 name: Verify release candidate rehearsal
2 run-name: Verify rehearsal ${{ inputs.candidate_id }}
3
4 on:
5 workflow_dispatch:
6 inputs:
7 candidate_id:
8 description: "Sealed non-publishing rehearsal candidate ID"
9 required: true
10 type: string
11
12 permissions:
13 actions: read
14 attestations: read
15 contents: read
16
17 jobs:
18 verify:
19 name: verify signed files across runs without rebuilding
20 runs-on: ubuntu-latest
21 steps:
22 - uses: actions/checkout@v7
23 with:
24 fetch-depth: 0
25 ref: ${{ github.sha }}
26 - uses: actions/setup-node@v7
27 with:
28 node-version: "22"
29 - name: Require protected control and resolve exact record
30 id: record
31 env:
32 GH_TOKEN: ${{ github.token }}
33 RELEASE_REVOKED_CANDIDATES: ${{ vars.RELEASE_REVOKED_CANDIDATES }}
34 run: |
35 set -euo pipefail
36 test "$GITHUB_REPOSITORY" = esengine/DeepSeek-Reasonix
37 test "$GITHUB_REF" = refs/heads/main-v2
38 test "$GITHUB_REF_PROTECTED" = true
39 node scripts/resolve-release-candidate.mjs resolve-rehearsal "${{ inputs.candidate_id }}"
40 - name: Download and verify producer record
41 id: inspected
42 env:
43 GH_TOKEN: ${{ github.token }}
44 RECORD_ID: ${{ steps.record.outputs.record_artifact_id }}
45 PRODUCER_RUN: ${{ steps.record.outputs.producer_run_id }}
46 run: |
47 set -euo pipefail
48 gh api "repos/$GITHUB_REPOSITORY/actions/artifacts/$RECORD_ID" > "$RUNNER_TEMP/record-artifact.json"
49 gh api "repos/$GITHUB_REPOSITORY/actions/runs/$PRODUCER_RUN" > "$RUNNER_TEMP/producer-run.json"
50 gh api "repos/$GITHUB_REPOSITORY/actions/artifacts/$RECORD_ID/zip" > "$RUNNER_TEMP/record.zip"
51 node scripts/verify-release-artifact-archive.mjs "$RUNNER_TEMP/record-artifact.json" "$RUNNER_TEMP/record.zip"
52 mkdir record
53 unzip -q "$RUNNER_TEMP/record.zip" -d record
54 test -s record/record.json
55 signer_sha="$(jq -r .head_sha "$RUNNER_TEMP/producer-run.json")"
56 gh attestation verify record/record.json --repo "$GITHUB_REPOSITORY" \
57 --signer-workflow "$GITHUB_REPOSITORY/.github/workflows/release-candidate.yml" \
58 --signer-digest "$signer_sha" --source-ref refs/heads/main-v2 --deny-self-hosted-runners
59 node scripts/resolve-release-candidate.mjs inspect-rehearsal "${{ inputs.candidate_id }}" \
60 record/record.json "$RUNNER_TEMP/record-artifact.json" "$RUNNER_TEMP/producer-run.json"
61 - name: Verify exact signed payload and native acceptance evidence
62 env:
63 GH_TOKEN: ${{ github.token }}
64 PAYLOAD_ID: ${{ steps.inspected.outputs.payload_artifact_id }}
65 PAYLOAD_NAME: ${{ steps.inspected.outputs.payload_artifact_name }}
66 PRODUCER_RUN: ${{ steps.inspected.outputs.producer_run_id }}
67 CONTROL_SHA: ${{ steps.inspected.outputs.candidate_control_sha }}
68 run: |
69 set -euo pipefail
70 gh api "repos/$GITHUB_REPOSITORY/actions/artifacts/$PAYLOAD_ID" > "$RUNNER_TEMP/payload-artifact.json"
71 test "$(jq -r .name "$RUNNER_TEMP/payload-artifact.json")" = "$PAYLOAD_NAME"
72 test "$(jq -r .workflow_run.id "$RUNNER_TEMP/payload-artifact.json")" = "$PRODUCER_RUN"
73 gh api "repos/$GITHUB_REPOSITORY/actions/artifacts/$PAYLOAD_ID/zip" > "$RUNNER_TEMP/payload.zip"
74 node scripts/verify-release-artifact-archive.mjs "$RUNNER_TEMP/payload-artifact.json" "$RUNNER_TEMP/payload.zip"
75 mkdir payload
76 unzip -q "$RUNNER_TEMP/payload.zip" -d payload
77 while IFS= read -r -d '' file; do
78 gh attestation verify "$file" --repo "$GITHUB_REPOSITORY" \
79 --signer-workflow "$GITHUB_REPOSITORY/.github/workflows/release-candidate.yml" \
80 --signer-digest "$CONTROL_SHA" --source-ref refs/heads/main-v2 \
81 --deny-self-hosted-runners >/dev/null
82 done < <(find payload -type f -print0)
83 node scripts/release-candidate.mjs verify-rehearsal payload record/record.json >/dev/null
84 git fetch origin main-v2
85 git merge-base --is-ancestor "${{ steps.inspected.outputs.source_sha }}" origin/main-v2
86 jq -n \
87 --arg candidate "${{ inputs.candidate_id }}" \
88 --arg source "${{ steps.inspected.outputs.source_sha }}" \
89 --arg producer "$PRODUCER_RUN" \
90 --arg verifier "$GITHUB_RUN_ID" \
91 --arg record "$(sha256sum record/record.json | awk '{print $1}')" \
92 --arg payload "$(sha256sum "$RUNNER_TEMP/payload.zip" | awk '{print $1}')" \
93 '{candidateId:$candidate,sourceSHA:$source,producerRunId:$producer,verifierRunId:$verifier,recordSha256:$record,payloadArchiveSha256:$payload,publication:false,result:"verified"}' \
94 > rehearsal-verification.json
95 {
96 echo "### Independent rehearsal verification"
97 echo
98 echo "- Candidate: \`${{ inputs.candidate_id }}\`"
99 echo "- Producer run: \`$PRODUCER_RUN\`"
100 echo "- Record SHA-256: \`$(jq -r .recordSha256 rehearsal-verification.json)\`"
101 echo "- Payload archive SHA-256: \`$(jq -r .payloadArchiveSha256 rehearsal-verification.json)\`"
102 echo "- No tag, release channel, or update pointer was changed."
103 } >> "$GITHUB_STEP_SUMMARY"
104 - uses: actions/upload-artifact@v7
105 with:
106 name: release-rehearsal-verification-${{ github.run_id }}-${{ github.run_attempt }}
107 path: rehearsal-verification.json
108 if-no-files-found: error
109 retention-days: 90
110
110 lines YAML