1212 default : finalize-only
1313 type : choice
1414 options :
15+ - publish-qualified
1516 - finalize-only
1617 release_tag :
1718 description : Existing published tag (for example v1.19.3)
1819 required : true
1920 type : string
2021 publish_run_id :
2122 description : Workflow run containing PublishedArtifactReceiptV1
22- required : true
23+ required : false
2324 type : string
2425 publish_run_attempt :
2526 description : Attempt number that produced the receipt
2627 required : true
2728 default : " 1"
2829 type : string
30+ qualification_run_id :
31+ description : Tag workflow run containing the qualified exact artifact
32+ required : false
33+ type : string
34+ qualification_run_attempt :
35+ description : Attempt number that produced the qualified exact artifact
36+ required : false
37+ default : " 1"
38+ type : string
2939
3040concurrency :
3141 group : publish-${{ github.ref }}
8191 node scripts/exact-release-artifact.js create --output-dir "${RELEASE_DIR}"
8292 node scripts/exact-release-artifact.js verify --output-dir "${RELEASE_DIR}"
8393
94+ - name : Install and exercise the exact qualified artifact in isolation
95+ shell : bash
96+ run : |
97+ set -euo pipefail
98+ RELEASE_DIR="${RUNNER_TEMP}/devcodex-release-artifact"
99+ RELEASE_ARTIFACT_PATH="$(node -e 'const fs=require("fs"); const value=JSON.parse(fs.readFileSync(`${process.env.RELEASE_DIR}/exact-release-artifact.receipt.json`,"utf8")); process.stdout.write(`${process.env.RELEASE_DIR}/${value.artifactFile}`)')"
100+ node scripts/test-global-install-smoke.js --tarball "${RELEASE_ARTIFACT_PATH}"
101+ node scripts/exact-release-artifact.js verify --output-dir "${RELEASE_DIR}"
102+ env :
103+ RELEASE_DIR : ${{ runner.temp }}/devcodex-release-artifact
104+
84105 - name : Preserve qualified artifact
85106 uses : actions/upload-artifact@v4
86107 with :
@@ -91,15 +112,18 @@ jobs:
91112
92113 publish :
93114 needs : qualify
94- if : github.event_name != 'workflow_dispatch'
115+ if : always() && github.event_name == 'workflow_dispatch' && inputs.mode == 'publish-qualified '
95116 runs-on : ubuntu-latest
96117 permissions :
118+ actions : read
97119 contents : read
98120 id-token : write
99121
100122 steps :
101123 - name : Checkout
102124 uses : actions/checkout@v6
125+ with :
126+ ref : ${{ inputs.release_tag }}
103127
104128 - name : Setup Node.js
105129 uses : actions/setup-node@v6
@@ -108,11 +132,31 @@ jobs:
108132 registry-url : https://registry.npmjs.org
109133 package-manager-cache : false
110134
135+ - name : Verify publish-qualified input binding
136+ shell : bash
137+ env :
138+ RELEASE_TAG : ${{ inputs.release_tag }}
139+ QUALIFICATION_RUN_ID : ${{ inputs.qualification_run_id }}
140+ QUALIFICATION_RUN_ATTEMPT : ${{ inputs.qualification_run_attempt }}
141+ run : |
142+ set -euo pipefail
143+ PKG_VERSION="$(node -p "require('./package.json').version")"
144+ if [ "${RELEASE_TAG}" != "v${PKG_VERSION}" ]; then
145+ echo "Release tag ${RELEASE_TAG} does not match package version ${PKG_VERSION}"
146+ exit 1
147+ fi
148+ if ! [[ "${QUALIFICATION_RUN_ID}" =~ ^[0-9]+$ ]] || ! [[ "${QUALIFICATION_RUN_ATTEMPT}" =~ ^[0-9]+$ ]]; then
149+ echo "publish-qualified requires numeric qualification run identity"
150+ exit 1
151+ fi
152+
111153 - name : Download qualified artifact
112154 uses : actions/download-artifact@v5
113155 with :
114- name : qualified-release-${{ github.ref_name }}-${{ github.run_id }}-${{ github.run_attempt }}
156+ name : qualified-release-${{ inputs.release_tag }}-${{ inputs.qualification_run_id }}-${{ inputs.qualification_run_attempt }}
115157 path : ${{ runner.temp }}/devcodex-release-artifact
158+ run-id : ${{ inputs.qualification_run_id }}
159+ github-token : ${{ github.token }}
116160
117161 - name : Verify exact artifact and detect an existing version
118162 id : prepare
@@ -154,14 +198,14 @@ jobs:
154198 - name : Upload irreversible publish receipt
155199 uses : actions/upload-artifact@v4
156200 with :
157- name : published-release-${{ github.ref_name }}-${{ github.run_id }}-${{ github.run_attempt }}
201+ name : published-release-${{ inputs.release_tag }}-${{ github.run_id }}-${{ github.run_attempt }}
158202 path : ${{ runner.temp }}/devcodex-release-artifact
159203 if-no-files-found : error
160204 retention-days : 90
161205
162206 finalize :
163207 needs : [qualify, publish]
164- if : always() && (( github.event_name != 'workflow_dispatch' && needs.publish.result == 'success') || github.event_name == 'workflow_dispatch ')
208+ if : always() && github.event_name == 'workflow_dispatch' && ((inputs.mode == 'publish-qualified' && needs.publish.result == 'success') || inputs.mode == 'finalize-only ')
165209 runs-on : ubuntu-latest
166210 permissions :
167211 actions : read
@@ -179,15 +223,28 @@ jobs:
179223 node-version : 24.17.0
180224 package-manager-cache : false
181225
226+ - name : Verify finalize recovery input binding
227+ if : inputs.mode == 'finalize-only'
228+ shell : bash
229+ env :
230+ PUBLISH_RUN_ID : ${{ inputs.publish_run_id }}
231+ PUBLISH_RUN_ATTEMPT : ${{ inputs.publish_run_attempt }}
232+ run : |
233+ set -euo pipefail
234+ if ! [[ "${PUBLISH_RUN_ID}" =~ ^[0-9]+$ ]] || ! [[ "${PUBLISH_RUN_ATTEMPT}" =~ ^[0-9]+$ ]]; then
235+ echo "finalize-only requires numeric publish run identity"
236+ exit 1
237+ fi
238+
182239 - name : Download current publish receipt
183- if : github.event_name != 'workflow_dispatch '
240+ if : inputs.mode == 'publish-qualified '
184241 uses : actions/download-artifact@v5
185242 with :
186- name : published-release-${{ github.ref_name }}-${{ github.run_id }}-${{ github.run_attempt }}
243+ name : published-release-${{ inputs.release_tag }}-${{ github.run_id }}-${{ github.run_attempt }}
187244 path : ${{ runner.temp }}/devcodex-release-artifact
188245
189246 - name : Download prior publish receipt for finalize-only recovery
190- if : github.event_name == 'workflow_dispatch '
247+ if : inputs.mode == 'finalize-only '
191248 uses : actions/download-artifact@v5
192249 with :
193250 name : published-release-${{ inputs.release_tag }}-${{ inputs.publish_run_id }}-${{ inputs.publish_run_attempt }}
@@ -198,7 +255,7 @@ jobs:
198255 - name : Verify tag and published receipt binding
199256 shell : bash
200257 env :
201- RELEASE_TAG : ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }}
258+ RELEASE_TAG : ${{ inputs.release_tag }}
202259 run : |
203260 set -euo pipefail
204261 TAG_VERSION="${RELEASE_TAG#v}"
@@ -245,7 +302,7 @@ jobs:
245302 shell : bash
246303 env :
247304 GH_TOKEN : ${{ github.token }}
248- RELEASE_TAG : ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref_name }}
305+ RELEASE_TAG : ${{ inputs.release_tag }}
249306 RELEASE_DIR : ${{ runner.temp }}/devcodex-release-artifact
250307 run : |
251308 set -euo pipefail
0 commit comments