From 306822255da6feee498383d59bf49ca9bca423e8 Mon Sep 17 00:00:00 2001 From: Mao Nakamoto <41178744+maonakamoto@users.noreply.github.com> Date: Sun, 16 Aug 2026 14:58:09 +0200 Subject: [PATCH] ci: publish on a version tag, with provenance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit threadkit has a CI workflow but no way to ship. The package is publish-ready — name unclaimed on npm, `files: ["dist"]`, README and LICENSE both in the tarball, 27 files, builds clean — so the only thing standing between it and a release was a manual `npm publish` from someone's laptop. This is the same workflow ai-forms already carries, so the two libraries release identically rather than each growing its own procedure: - triggered by a `v*` tag, so every published artifact traces to a commit - `id-token: write` for npm provenance — the registry can prove the tarball was built by this workflow from this commit, not uploaded from a laptop - runs `npm run verify` first: never publish something that would not pass CI - refuses to publish when the tag and package.json version disagree, instead of silently shipping the wrong number Verified locally with the workflow's exact steps: `npm ci --ignore-scripts` then `npm run verify` — 31 tests pass. Needs the NPM_TOKEN repo secret once; after that a release is `npm version` plus a tag push. Co-Authored-By: Claude Opus 5 --- .github/workflows/publish.yml | 42 +++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/publish.yml diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..f78236a --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,42 @@ +name: Publish + +# Publishing is driven by a version tag, so the released artifact is always +# traceable to a commit. `npm version` creates the tag; pushing it ships. +on: + push: + tags: ['v*'] + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: read + # Required for npm provenance — proves on the registry that this tarball + # was built by this workflow from this commit. + id-token: write + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + + - run: npm ci --ignore-scripts + + # Never publish something that would not have passed CI. + - run: npm run verify + + # Refuse to publish a tag whose version does not match package.json, + # rather than silently shipping the wrong number. + - name: Check tag matches package version + run: | + tag="${GITHUB_REF_NAME#v}" + pkg=$(node -p "require('./package.json').version") + if [ "$tag" != "$pkg" ]; then + echo "Tag v$tag does not match package.json version $pkg" >&2 + exit 1 + fi + + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}