fix: recognize owned Codex model catalog cache during host probes #47
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish to npm | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| mode: | |
| description: Recovery mode | |
| required: true | |
| default: finalize-only | |
| type: choice | |
| options: | |
| - publish-qualified | |
| - finalize-only | |
| release_tag: | |
| description: Existing published tag (for example v1.19.3) | |
| required: true | |
| type: string | |
| publish_run_id: | |
| description: Workflow run containing PublishedArtifactReceiptV1 | |
| required: false | |
| type: string | |
| publish_run_attempt: | |
| description: Attempt number that produced the receipt | |
| required: true | |
| default: "1" | |
| type: string | |
| qualification_run_id: | |
| description: Tag workflow run containing the qualified exact artifact | |
| required: false | |
| type: string | |
| qualification_run_attempt: | |
| description: Attempt number that produced the qualified exact artifact | |
| required: false | |
| default: "1" | |
| type: string | |
| concurrency: | |
| group: publish-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| qualify: | |
| if: github.event_name != 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24.17.0 | |
| package-manager-cache: false | |
| - name: Verify tag matches package.json version | |
| run: | | |
| TAG_VERSION="${GITHUB_REF#refs/tags/v}" | |
| PKG_VERSION=$(node -p "require('./package.json').version") | |
| if [ "${TAG_VERSION}" != "${PKG_VERSION}" ]; then | |
| echo "Tag v${TAG_VERSION} does not match package.json version ${PKG_VERSION}" | |
| exit 1 | |
| fi | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run package release checks | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| AUTHORITY_SOURCE="github-actions:${GITHUB_WORKFLOW}:${GITHUB_EVENT_NAME}:${GITHUB_REPOSITORY}:${GITHUB_REF}:${GITHUB_SHA}" | |
| POLICY_DIGEST="$(node -e 'const {sha256}=require("./hooks/_runtime/content-identity.cjs"); process.stdout.write(sha256(JSON.stringify({workflow:process.env.GITHUB_WORKFLOW,event:process.env.GITHUB_EVENT_NAME,repository:process.env.GITHUB_REPOSITORY,ref:process.env.GITHUB_REF,commit:process.env.GITHUB_SHA,purpose:"release"})))')" | |
| BUDGET_DIGEST="$( | |
| node scripts/run-validation.js --route package-release --purpose release --actor release-pipeline --authority-source "${AUTHORITY_SOURCE}" --policy-digest "${POLICY_DIGEST}" --plan --json | | |
| node -e 'const fs = require("fs"); const envelope = JSON.parse(fs.readFileSync(0, "utf8")); const plan = envelope?.data?.plan; const digest = plan?.budgetCard?.digest; if (envelope?.ok !== true || plan?.routeResolved !== "full" || plan?.verificationPurpose !== "release" || plan?.candidateStable !== true || !/^[a-f0-9]{64}$/.test(String(digest || ""))) process.exit(1); process.stdout.write(digest)' | |
| )" | |
| node scripts/run-validation.js --route package-release --purpose release --actor release-pipeline --authority-source "${AUTHORITY_SOURCE}" --policy-digest "${POLICY_DIGEST}" --approve-plan "${BUDGET_DIGEST}" | |
| - name: Create and verify the exact qualified artifact | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| RELEASE_DIR="${RUNNER_TEMP}/devcodex-release-artifact" | |
| mkdir -p "${RELEASE_DIR}" | |
| node scripts/exact-release-artifact.js create --output-dir "${RELEASE_DIR}" | |
| node scripts/exact-release-artifact.js verify --output-dir "${RELEASE_DIR}" | |
| - name: Install and exercise the exact qualified artifact in isolation | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| RELEASE_DIR="${RUNNER_TEMP}/devcodex-release-artifact" | |
| 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}`)')" | |
| node scripts/test-global-install-smoke.js --tarball "${RELEASE_ARTIFACT_PATH}" | |
| node scripts/exact-release-artifact.js verify --output-dir "${RELEASE_DIR}" | |
| env: | |
| RELEASE_DIR: ${{ runner.temp }}/devcodex-release-artifact | |
| - name: Preserve qualified artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: qualified-release-${{ github.ref_name }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: ${{ runner.temp }}/devcodex-release-artifact | |
| if-no-files-found: error | |
| retention-days: 30 | |
| publish: | |
| needs: qualify | |
| if: always() && github.event_name == 'workflow_dispatch' && inputs.mode == 'publish-qualified' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| contents: read | |
| id-token: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.release_tag }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24.17.0 | |
| registry-url: https://registry.npmjs.org | |
| package-manager-cache: false | |
| - name: Verify publish-qualified input binding | |
| shell: bash | |
| env: | |
| RELEASE_TAG: ${{ inputs.release_tag }} | |
| QUALIFICATION_RUN_ID: ${{ inputs.qualification_run_id }} | |
| QUALIFICATION_RUN_ATTEMPT: ${{ inputs.qualification_run_attempt }} | |
| run: | | |
| set -euo pipefail | |
| PKG_VERSION="$(node -p "require('./package.json').version")" | |
| if [ "${RELEASE_TAG}" != "v${PKG_VERSION}" ]; then | |
| echo "Release tag ${RELEASE_TAG} does not match package version ${PKG_VERSION}" | |
| exit 1 | |
| fi | |
| if ! [[ "${QUALIFICATION_RUN_ID}" =~ ^[0-9]+$ ]] || ! [[ "${QUALIFICATION_RUN_ATTEMPT}" =~ ^[0-9]+$ ]]; then | |
| echo "publish-qualified requires numeric qualification run identity" | |
| exit 1 | |
| fi | |
| - name: Download qualified artifact | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: qualified-release-${{ inputs.release_tag }}-${{ inputs.qualification_run_id }}-${{ inputs.qualification_run_attempt }} | |
| path: ${{ runner.temp }}/devcodex-release-artifact | |
| run-id: ${{ inputs.qualification_run_id }} | |
| github-token: ${{ github.token }} | |
| - name: Verify exact artifact and detect an existing version | |
| id: prepare | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| RELEASE_DIR="${RUNNER_TEMP}/devcodex-release-artifact" | |
| node scripts/exact-release-artifact.js verify --output-dir "${RELEASE_DIR}" --embedded-qualification | |
| node scripts/exact-release-artifact.js prepare-publish \ | |
| --output-dir "${RELEASE_DIR}" \ | |
| --embedded-qualification \ | |
| --run-id "${GITHUB_RUN_ID}" \ | |
| --run-attempt "${GITHUB_RUN_ATTEMPT}" \ | |
| > "${RUNNER_TEMP}/prepare-publish.json" | |
| ACTION="$(node -e 'const fs=require("fs"); const value=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); if(value.ok!==true||!value.action) process.exit(1); process.stdout.write(value.action)' "${RUNNER_TEMP}/prepare-publish.json")" | |
| echo "action=${ACTION}" >> "${GITHUB_OUTPUT}" | |
| - name: Publish the exact qualified tarball once | |
| if: steps.prepare.outputs.action == 'publish-required' | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| RELEASE_DIR="${RUNNER_TEMP}/devcodex-release-artifact" | |
| 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}`)')" | |
| npm publish "${RELEASE_ARTIFACT_PATH}" --ignore-scripts --provenance --access public | |
| node scripts/exact-release-artifact.js mark-published \ | |
| --output-dir "${RELEASE_DIR}" \ | |
| --embedded-qualification \ | |
| --status published \ | |
| --run-id "${GITHUB_RUN_ID}" \ | |
| --run-attempt "${GITHUB_RUN_ATTEMPT}" | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| RELEASE_DIR: ${{ runner.temp }}/devcodex-release-artifact | |
| - name: Verify and preserve PublishedArtifactReceiptV1 | |
| run: node scripts/exact-release-artifact.js verify-published --output-dir "${RUNNER_TEMP}/devcodex-release-artifact" --embedded-qualification | |
| - name: Upload irreversible publish receipt | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: published-release-${{ inputs.release_tag }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: ${{ runner.temp }}/devcodex-release-artifact | |
| if-no-files-found: error | |
| retention-days: 90 | |
| finalize: | |
| needs: [qualify, publish] | |
| if: always() && github.event_name == 'workflow_dispatch' && ((inputs.mode == 'publish-qualified' && needs.publish.result == 'success') || inputs.mode == 'finalize-only') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| actions: read | |
| contents: write | |
| steps: | |
| - name: Checkout release tag | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.release_tag || github.ref }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24.17.0 | |
| package-manager-cache: false | |
| - name: Verify finalize recovery input binding | |
| if: inputs.mode == 'finalize-only' | |
| shell: bash | |
| env: | |
| PUBLISH_RUN_ID: ${{ inputs.publish_run_id }} | |
| PUBLISH_RUN_ATTEMPT: ${{ inputs.publish_run_attempt }} | |
| run: | | |
| set -euo pipefail | |
| if ! [[ "${PUBLISH_RUN_ID}" =~ ^[0-9]+$ ]] || ! [[ "${PUBLISH_RUN_ATTEMPT}" =~ ^[0-9]+$ ]]; then | |
| echo "finalize-only requires numeric publish run identity" | |
| exit 1 | |
| fi | |
| - name: Download current publish receipt | |
| if: inputs.mode == 'publish-qualified' | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: published-release-${{ inputs.release_tag }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: ${{ runner.temp }}/devcodex-release-artifact | |
| - name: Download prior publish receipt for finalize-only recovery | |
| if: inputs.mode == 'finalize-only' | |
| uses: actions/download-artifact@v5 | |
| with: | |
| name: published-release-${{ inputs.release_tag }}-${{ inputs.publish_run_id }}-${{ inputs.publish_run_attempt }} | |
| path: ${{ runner.temp }}/devcodex-release-artifact | |
| run-id: ${{ inputs.publish_run_id }} | |
| github-token: ${{ github.token }} | |
| - name: Verify tag and published receipt binding | |
| shell: bash | |
| env: | |
| RELEASE_TAG: ${{ inputs.release_tag }} | |
| run: | | |
| set -euo pipefail | |
| TAG_VERSION="${RELEASE_TAG#v}" | |
| PKG_VERSION="$(node -p "require('./package.json').version")" | |
| if [ "${RELEASE_TAG}" != "v${PKG_VERSION}" ] || [ "${TAG_VERSION}" != "${PKG_VERSION}" ]; then | |
| echo "Release tag ${RELEASE_TAG} does not match package version ${PKG_VERSION}" | |
| exit 1 | |
| fi | |
| node scripts/exact-release-artifact.js verify-published --output-dir "${RUNNER_TEMP}/devcodex-release-artifact" --embedded-qualification | |
| - name: Reconcile registry identity with bounded exponential backoff | |
| shell: bash | |
| env: | |
| FINALIZE_MAX_ATTEMPTS: ${{ vars.DEVCODEX_FINALIZE_MAX_ATTEMPTS }} | |
| FINALIZE_INITIAL_DELAY_SECONDS: ${{ vars.DEVCODEX_FINALIZE_INITIAL_DELAY_SECONDS }} | |
| FINALIZE_MAX_DELAY_SECONDS: ${{ vars.DEVCODEX_FINALIZE_MAX_DELAY_SECONDS }} | |
| run: | | |
| set -euo pipefail | |
| MAX_ATTEMPTS="${FINALIZE_MAX_ATTEMPTS:-8}" | |
| DELAY="${FINALIZE_INITIAL_DELAY_SECONDS:-5}" | |
| MAX_DELAY="${FINALIZE_MAX_DELAY_SECONDS:-60}" | |
| for attempt in $(seq 1 "${MAX_ATTEMPTS}"); do | |
| set +e | |
| node scripts/exact-release-artifact.js finalize --output-dir "${RUNNER_TEMP}/devcodex-release-artifact" --embedded-qualification > "${RUNNER_TEMP}/finalize-result.json" | |
| STATUS=$? | |
| set -e | |
| if [ "${STATUS}" -eq 0 ]; then | |
| cat "${RUNNER_TEMP}/finalize-result.json" | |
| break | |
| fi | |
| if [ "${STATUS}" -ne 75 ]; then | |
| exit "${STATUS}" | |
| fi | |
| if [ "${attempt}" -eq "${MAX_ATTEMPTS}" ]; then | |
| echo "Registry did not converge within the finalize budget; rerun finalize-only with this publish receipt" | |
| exit 1 | |
| fi | |
| sleep "${DELAY}" | |
| DELAY=$((DELAY * 2)) | |
| if [ "${DELAY}" -gt "${MAX_DELAY}" ]; then DELAY="${MAX_DELAY}"; fi | |
| done | |
| - name: Create or verify the GitHub Release idempotently | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_TAG: ${{ inputs.release_tag }} | |
| RELEASE_DIR: ${{ runner.temp }}/devcodex-release-artifact | |
| run: | | |
| set -euo pipefail | |
| 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}`)')" | |
| ASSET_NAME="$(basename "${RELEASE_ARTIFACT_PATH}")" | |
| if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then | |
| EXISTING_DIR="${RUNNER_TEMP}/existing-release-asset" | |
| mkdir -p "${EXISTING_DIR}" | |
| if gh release download "${RELEASE_TAG}" --pattern "${ASSET_NAME}" --dir "${EXISTING_DIR}"; then | |
| cmp "${RELEASE_ARTIFACT_PATH}" "${EXISTING_DIR}/${ASSET_NAME}" | |
| else | |
| gh release upload "${RELEASE_TAG}" "${RELEASE_ARTIFACT_PATH}" | |
| fi | |
| else | |
| gh release create "${RELEASE_TAG}" "${RELEASE_ARTIFACT_PATH}" \ | |
| --verify-tag \ | |
| --title "DevCodex ${RELEASE_TAG}" \ | |
| --notes-file "changelogs/releases/${RELEASE_TAG}.md" | |
| fi |