88 required : true
99 type : string
1010 release_ref :
11- description : Optional public OpenClaw release ref, tag, branch, or SHA
12- required : false
13- default : " "
11+ description : Exact public OpenClaw release ref, tag, or SHA
12+ required : true
1413 type : string
1514 package_spec :
16- description : Optional package spec covered by this evidence, for example openclaw@2026.4.27-beta.1
17- required : false
18- default : " "
15+ description : Exact package spec covered by this evidence, for example openclaw@2026.4.27-beta.1
16+ required : true
1917 type : string
2018 runs :
2119 description : " One per line: <label> <owner/repo> <run-id> <blocking|advisory>"
@@ -34,22 +32,27 @@ concurrency:
3432env :
3533 FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 : " true"
3634 NODE_VERSION : " 24.x"
35+ PACKAGE_SPEC : ${{ inputs.package_spec }}
36+ RELEASE_ID : ${{ inputs.release_id }}
37+ RELEASE_REF : ${{ inputs.release_ref }}
3738
3839jobs :
3940 write_evidence :
41+ if : github.ref == 'refs/heads/main'
4042 runs-on : ubuntu-latest
4143 permissions :
4244 actions : read
4345 contents : write
4446 steps :
4547 - name : Checkout release repo
46- uses : actions/checkout@v6
48+ uses : actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
4749 with :
4850 fetch-depth : 0
49- persist-credentials : false
51+ ref : main
52+ token : ${{ github.token }}
5053
5154 - name : Setup Node.js
52- uses : actions/setup-node@v6
55+ uses : actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
5356 with :
5457 node-version : ${{ env.NODE_VERSION }}
5558
@@ -69,48 +72,79 @@ jobs:
6972 run : |
7073 set -euo pipefail
7174 node scripts/openclaw-release-evidence.mjs \
72- --release-id "${{ inputs.release_id }} " \
73- --release-ref "${{ inputs.release_ref }} " \
74- --package-spec "${{ inputs.package_spec }} " \
75+ --release-id "$RELEASE_ID " \
76+ --release-ref "$RELEASE_REF " \
77+ --package-spec "$PACKAGE_SPEC " \
7578 --runs-file "$RUNNER_TEMP/openclaw-release-evidence/runs.txt" \
7679 --notes-file "$RUNNER_TEMP/openclaw-release-evidence/notes.md"
7780
7881 - name : Append run summary
7982 run : |
8083 set -euo pipefail
81- evidence_md="evidence/${{ inputs.release_id } }/release-evidence.md"
84+ evidence_md="evidence/${RELEASE_ID }/release-evidence.md"
8285 {
8386 cat "$evidence_md"
8487 echo
8588 echo "Evidence path: \`$evidence_md\`"
8689 } >> "$GITHUB_STEP_SUMMARY"
8790
8891 - name : Commit evidence to main
89- env :
90- PUSH_TOKEN : ${{ secrets.OPENCLAW_RELEASES_PRIVATE_PUSH_TOKEN }}
9192 run : |
9293 set -euo pipefail
93- evidence_path="evidence/${{ inputs.release_id }}"
94- if [[ -z "${PUSH_TOKEN// }" ]]; then
95- echo "::error::OPENCLAW_RELEASES_PRIVATE_PUSH_TOKEN is required to push release evidence directly to main."
96- exit 1
97- fi
94+ evidence_path="evidence/${RELEASE_ID}"
95+ node scripts/openclaw-release-evidence-contract.mjs verify-evidence \
96+ "${evidence_path}/release-evidence.json" "$RELEASE_ID" "$RELEASE_REF" "$PACKAGE_SPEC"
9897 git config user.name "openclaw-release-bot"
9998 git config user.email "release-bot@openclaw.ai"
10099 git add "${evidence_path}"
100+ generated_tree="$(git write-tree)"
101+ expected_tree="$(git rev-parse "${generated_tree}:${evidence_path}")"
102+ changed=0
101103 if git diff --cached --quiet; then
102104 echo "No evidence changes to commit."
103- exit 0
105+ else
106+ git commit -m "Evidence: record ${RELEASE_ID}"
107+ changed=1
104108 fi
105- git commit -m "Evidence: record ${{ inputs.release_id }}"
106- git remote set-url origin "https://x-access-token:${PUSH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
107- for attempt in 1 2 3 4 5; do
108- git fetch origin main
109- if git rebase origin/main && git push origin HEAD:main; then
110- exit 0
109+
110+ if [[ "$changed" == "1" ]]; then
111+ pushed=0
112+ for attempt in 1 2 3 4 5; do
113+ git fetch origin main
114+ if git rebase origin/main; then
115+ if [[ "$(git rev-parse "HEAD:${evidence_path}")" != "$expected_tree" ]]; then
116+ echo "::error::Rebase changed the generated evidence directory."
117+ exit 1
118+ fi
119+ if git push origin HEAD:main; then
120+ pushed=1
121+ break
122+ fi
123+ fi
124+ git rebase --abort || true
125+ sleep $((attempt * 5))
126+ done
127+ if [[ "$pushed" != "1" ]]; then
128+ echo "::error::Could not push evidence to main after retries."
129+ exit 1
111130 fi
112- git rebase --abort || true
113- sleep $((attempt * 5))
114- done
115- echo "::error::Could not push evidence to main after retries."
116- exit 1
131+ fi
132+
133+ git fetch origin main
134+ git merge-base --is-ancestor HEAD origin/main || {
135+ echo "::error::Published evidence commit is not reachable from origin/main."
136+ exit 1
137+ }
138+ remote_tree="$(git rev-parse "origin/main:${evidence_path}")"
139+ if [[ "$expected_tree" != "$remote_tree" ]]; then
140+ echo "::error::Remote evidence directory differs from the generated files."
141+ exit 1
142+ fi
143+ remote_json="$RUNNER_TEMP/openclaw-release-evidence/remote-release-evidence.json"
144+ git show "origin/main:${evidence_path}/release-evidence.json" > "$remote_json"
145+ cmp "${evidence_path}/release-evidence.json" "$remote_json" || {
146+ echo "::error::Remote evidence bytes differ from the generated JSON."
147+ exit 1
148+ }
149+ node scripts/openclaw-release-evidence-contract.mjs verify-evidence \
150+ "$remote_json" "$RELEASE_ID" "$RELEASE_REF" "$PACKAGE_SPEC"
0 commit comments