Skip to content

Commit 3300b4a

Browse files
committed
Add signed public replay verification
1 parent b01f630 commit 3300b4a

1 file changed

Lines changed: 101 additions & 0 deletions

File tree

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
name: Public replay verification
2+
3+
on:
4+
workflow_dispatch:
5+
release:
6+
types: [published]
7+
8+
permissions:
9+
contents: read
10+
id-token: write
11+
attestations: write
12+
13+
jobs:
14+
verify-public-packages:
15+
runs-on: ubuntu-latest
16+
timeout-minutes: 15
17+
env:
18+
RELEASE_TAG: research-forge-v1-capability-acceptance-2026-08-01
19+
SUCCESS_PACKAGE: research-forge-openml-39-hidden-target-v1.zip
20+
SUCCESS_SHA256: 8c788149ac3a892e8e83d6f3d217d7671d50d507094611317ca273d7943a0eab
21+
BLOCKED_PACKAGE: research-forge-correctly-blocked-contract-v1.zip
22+
BLOCKED_SHA256: 7bb31c15bf45e6b832cbdc299315b4922b40d8524d75bf715677a88d4a78d227
23+
steps:
24+
- name: Download public release assets
25+
shell: bash
26+
run: |
27+
set -euo pipefail
28+
base="https://github.com/${GITHUB_REPOSITORY}/releases/download/${RELEASE_TAG}"
29+
curl --fail --location --retry 3 --output "${SUCCESS_PACKAGE}" "${base}/${SUCCESS_PACKAGE}"
30+
curl --fail --location --retry 3 --output "${BLOCKED_PACKAGE}" "${base}/${BLOCKED_PACKAGE}"
31+
32+
- name: Verify frozen archive digests
33+
shell: bash
34+
run: |
35+
set -euo pipefail
36+
printf '%s %s\n' "${SUCCESS_SHA256}" "${SUCCESS_PACKAGE}" | sha256sum --check --strict
37+
printf '%s %s\n' "${BLOCKED_SHA256}" "${BLOCKED_PACKAGE}" | sha256sum --check --strict
38+
39+
- name: Replay both standalone verifiers
40+
shell: bash
41+
run: |
42+
set -euo pipefail
43+
mkdir -p replay/success replay/blocked receipt
44+
unzip -q "${SUCCESS_PACKAGE}" -d replay/success
45+
unzip -q "${BLOCKED_PACKAGE}" -d replay/blocked
46+
(cd replay/success && python verify.py) | tee receipt/success-verification.json
47+
(cd replay/blocked && python verify.py) | tee receipt/blocked-verification.json
48+
49+
- name: Build external-host receipt
50+
shell: python
51+
run: |
52+
import hashlib
53+
import json
54+
import os
55+
from pathlib import Path
56+
57+
root = Path("receipt")
58+
payload = {
59+
"schema_version": 1,
60+
"receipt_kind": "github_hosted_public_replay",
61+
"repository": os.environ["GITHUB_REPOSITORY"],
62+
"workflow": os.environ["GITHUB_WORKFLOW"],
63+
"run_id": os.environ["GITHUB_RUN_ID"],
64+
"run_attempt": os.environ["GITHUB_RUN_ATTEMPT"],
65+
"runner_environment": "github-hosted ubuntu-latest",
66+
"release_tag": os.environ["RELEASE_TAG"],
67+
"packages": {
68+
"successful_case": {
69+
"name": os.environ["SUCCESS_PACKAGE"],
70+
"sha256": os.environ["SUCCESS_SHA256"],
71+
"verification": json.loads((root / "success-verification.json").read_text("utf-8")),
72+
},
73+
"blocked_case": {
74+
"name": os.environ["BLOCKED_PACKAGE"],
75+
"sha256": os.environ["BLOCKED_SHA256"],
76+
"verification": json.loads((root / "blocked-verification.json").read_text("utf-8")),
77+
},
78+
},
79+
"independent_scientific_operator": False,
80+
"c5_awarded": False,
81+
"claim_boundary": "GitHub-hosted replay proves external infrastructure execution and signed artifact provenance; it is not an independent scientific-operator review.",
82+
}
83+
encoded = json.dumps(payload, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")
84+
payload["receipt_subject_sha256"] = hashlib.sha256(encoded).hexdigest()
85+
(root / "external-host-replay-receipt.json").write_text(
86+
json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n",
87+
encoding="utf-8",
88+
)
89+
90+
- name: Upload replay receipt
91+
uses: actions/upload-artifact@v7
92+
with:
93+
name: public-replay-receipt
94+
path: receipt/
95+
if-no-files-found: error
96+
retention-days: 90
97+
98+
- name: Attest replay receipt provenance
99+
uses: actions/attest-build-provenance@v4
100+
with:
101+
subject-path: receipt/external-host-replay-receipt.json

0 commit comments

Comments
 (0)