From 49079e7c2ceacd198e94f5e225a56043bad3807f Mon Sep 17 00:00:00 2001 From: Drew Botwinick Date: Sat, 25 Jul 2026 18:42:07 -0500 Subject: [PATCH] ci: enable npm provenance so the publish job keeps its OIDC permission MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The v0.2.2 npm publish failed with a 404 on PUT for a package that plainly exists — npm's way of reporting an authorization failure for a scoped package. The generated workflow declared `id-token: write` at workflow level but the publish job re-declared `permissions: contents: read`, and a job-level block replaces the workflow one rather than merging. The job therefore had no OIDC token, npm could not sign provenance, and the publish fell back to plain token auth, which this package rejects. repo-tools 0.1.19 derives both permission blocks from the same predicate so the file can no longer claim a permission its jobs do not get. `use_provenance: true` is what turns that predicate on here, restoring the configuration the hand-written workflow had: id-token at both levels, `--provenance` on the publish, and NODE_AUTH_TOKEN still supplied — the token and OIDC are used together. Worth recording that this is not a regression introduced by the migration. The v0.2.1 and v0.1.60 tag runs failed identically and those releases reached npm by dispatching the workflow manually from main, so the token-only path has never worked for this package; the hand-written workflow simply happened to keep the permission that made the OIDC path available. The rest of the v0.2.2 release came out green on the generated workflows: Publish (Go) verified all four module tags on its first live run, Publish (Python) shipped both projects, and Build & push Docker images completed with the aetherlite-dev -> aetherlite image_name override. --- .github/workflows/build-docker.yml | 6 +++--- .github/workflows/proto-check.yml | 6 +++--- .github/workflows/publish-npm.yml | 5 +++-- .github/workflows/publish-python.yml | 8 ++++---- .github/workflows/version-check.yml | 2 +- versions.yaml | 10 +++++++++- 6 files changed, 23 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index bca3967..ca7c016 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -56,7 +56,7 @@ jobs: - name: Read image version from versions.yaml id: imgver run: | - VER=$(uvx --from 'scitrera-repo-tools==0.1.18' sync-versions --print-version aether-gateway) + VER=$(uvx --from 'scitrera-repo-tools==0.1.19' sync-versions --print-version aether-gateway) echo "version=$VER" >> "$GITHUB_OUTPUT" echo "major_minor=$(echo $VER | cut -d. -f1-2)" >> "$GITHUB_OUTPUT" @@ -132,7 +132,7 @@ jobs: - name: Read image version from versions.yaml id: imgver run: | - VER=$(uvx --from 'scitrera-repo-tools==0.1.18' sync-versions --print-version aether-gateway) + VER=$(uvx --from 'scitrera-repo-tools==0.1.19' sync-versions --print-version aether-gateway) echo "version=$VER" >> "$GITHUB_OUTPUT" echo "major_minor=$(echo $VER | cut -d. -f1-2)" >> "$GITHUB_OUTPUT" @@ -210,7 +210,7 @@ jobs: - name: Read image version from versions.yaml id: imgver run: | - VER=$(uvx --from 'scitrera-repo-tools==0.1.18' sync-versions --print-version aether-gateway) + VER=$(uvx --from 'scitrera-repo-tools==0.1.19' sync-versions --print-version aether-gateway) echo "version=$VER" >> "$GITHUB_OUTPUT" echo "major_minor=$(echo $VER | cut -d. -f1-2)" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/proto-check.yml b/.github/workflows/proto-check.yml index 43322f6..7408e52 100644 --- a/.github/workflows/proto-check.yml +++ b/.github/workflows/proto-check.yml @@ -46,7 +46,7 @@ jobs: uses: astral-sh/setup-uv@v9.0.0 - name: Verify generated Go code is up to date - run: uvx --from 'scitrera-repo-tools==0.1.18' compile-protos --check --lang go + run: uvx --from 'scitrera-repo-tools==0.1.19' compile-protos --check --lang go proto-check-python: name: compile-protos --check (python) @@ -65,7 +65,7 @@ jobs: run: pip install grpcio-tools==1.81.1 - name: Verify generated Python code is up to date - run: uvx --from 'scitrera-repo-tools==0.1.18' compile-protos --check --lang python --python "$(which python)" + run: uvx --from 'scitrera-repo-tools==0.1.19' compile-protos --check --lang python --python "$(which python)" proto-check-typescript: name: compile-protos --check (typescript) @@ -85,4 +85,4 @@ jobs: uses: astral-sh/setup-uv@v9.0.0 - name: Verify generated TypeScript code is up to date - run: uvx --from 'scitrera-repo-tools==0.1.18' compile-protos --check --lang typescript + run: uvx --from 'scitrera-repo-tools==0.1.19' compile-protos --check --lang typescript diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 0741ecb..ea68ee6 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -30,6 +30,7 @@ jobs: name: npm permissions: contents: read + id-token: write steps: - uses: actions/checkout@v6 @@ -42,7 +43,7 @@ jobs: registry-url: 'https://registry.npmjs.org' - name: Rewrite local refs to version pins - run: uvx --from 'scitrera-repo-tools==0.1.18' sync-versions --release + run: uvx --from 'scitrera-repo-tools==0.1.19' sync-versions --release - name: Install dependencies run: npm ci @@ -53,7 +54,7 @@ jobs: working-directory: sdk/typescript - name: Publish to npm - run: npm publish --access public + run: npm publish --access public --provenance working-directory: sdk/typescript env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish-python.yml b/.github/workflows/publish-python.yml index 4266187..e471371 100644 --- a/.github/workflows/publish-python.yml +++ b/.github/workflows/publish-python.yml @@ -32,14 +32,14 @@ jobs: uses: astral-sh/setup-uv@v9.0.0 - name: Verify versions are in sync - run: uvx --from 'scitrera-repo-tools==0.1.18' sync-versions --check --verbose + run: uvx --from 'scitrera-repo-tools==0.1.19' sync-versions --check --verbose - name: Compare tag against versions.yaml if: github.ref_type == 'tag' run: | set -euo pipefail tag="${GITHUB_REF_NAME#v}" - declared="$(uvx --from 'scitrera-repo-tools==0.1.18' sync-versions --print-version aether-sdk-python)" + declared="$(uvx --from 'scitrera-repo-tools==0.1.19' sync-versions --print-version aether-sdk-python)" if [ "$tag" != "$declared" ]; then echo "::error::Tag ${GITHUB_REF_NAME} does not match the aether-sdk-python version declared in versions.yaml ($declared)" exit 1 @@ -66,7 +66,7 @@ jobs: python-version: '3.12' - name: Rewrite local refs to version pins - run: uvx --from 'scitrera-repo-tools==0.1.18' sync-versions --release + run: uvx --from 'scitrera-repo-tools==0.1.19' sync-versions --release - name: Build sdist + wheel run: | @@ -106,7 +106,7 @@ jobs: python-version: '3.12' - name: Rewrite local refs to version pins - run: uvx --from 'scitrera-repo-tools==0.1.18' sync-versions --release + run: uvx --from 'scitrera-repo-tools==0.1.19' sync-versions --release - name: Build sdist + wheel run: | diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index ade96af..7c62817 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -33,4 +33,4 @@ jobs: uses: astral-sh/setup-uv@v9.0.0 - name: Verify versions are in sync - run: uvx --from 'scitrera-repo-tools==0.1.18' sync-versions --check --verbose + run: uvx --from 'scitrera-repo-tools==0.1.19' sync-versions --check --verbose diff --git a/versions.yaml b/versions.yaml index 3a930c7..2d14de8 100644 --- a/versions.yaml +++ b/versions.yaml @@ -63,7 +63,7 @@ ci: # release, which is the same unpinned-tooling drift proto-check exists to # catch. Bump in lockstep with the proto toolchain when repo-tools changes # generated output. - repo_tools_source: "scitrera-repo-tools==0.1.18" + repo_tools_source: "scitrera-repo-tools==0.1.19" # `push_branches` is deliberately unset, so develop stays in both the push and # pull_request trigger lists and every check runs twice for a commit pushed to # an open PR's branch. That is the intended trade: both runs complete and both @@ -97,6 +97,14 @@ ci: # the one Python project whose version tracks the tag; ag2 is versioned # independently (0.0.2), so a single tag cannot verify both. verify_tag_version: aether-sdk-python + npm: + # Load-bearing, not cosmetic. It grants id-token: write to the publish job, + # which is what lets npm mint an OIDC token and sign a provenance statement. + # Without it the publish falls back to plain token auth and this package + # rejects it with a misleading 404 — the mode every tag-triggered npm publish + # has failed in, including v0.1.60 and v0.2.1. NODE_AUTH_TOKEN is still sent; + # the token and OIDC are used together. + use_provenance: true go: # -short matches what test.yml runs for unit CI: without it the suite tries # to reach RabbitMQ/Valkey/Postgres, which only the integration job provides.