From 28b98a4eab0f8f92bf35fc5f57018118a6c5fe02 Mon Sep 17 00:00:00 2001 From: Sina Meraji Date: Mon, 10 Aug 2026 11:33:49 +0900 Subject: [PATCH] ci: publish to npm via trusted publishing (OIDC), not a 2FA-bypass token MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The publish job authenticated with secrets.NPM_TOKEN. Automation tokens bypass 2FA by design — that's their whole purpose — so the strongest account protection did not cover the one operation that matters most: shipping code to everyone who runs `npm i -g gitflare`. A leaked token publishes a release on its own. Trusted publishing removes the standing credential entirely. GitHub mints a short-lived OIDC credential scoped to a single workflow run, and npm verifies it against a publisher registered for this repo + this exact workflow filename. Nothing to exfiltrate, nothing to rotate. - id-token: write on the publish job only (release-please doesn't need it) - Node 22 + npm@latest in the publish job: OIDC needs Node >= 22.14 and npm >= 11.5.1, and Node 22 still bundles npm 10.x. ci.yml stays on Node 20 so the engines >= 20 floor is still tested. - NODE_AUTH_TOKEN dropped; the npm CLI detects OIDC on its own. Side benefit: npm generates provenance attestations automatically for public packages published this way, so releases become verifiable back to this repo and commit. REQUIRES a one-time setup on npmjs.com before this merges — see the PR. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/release-please.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index bfbfab2..54fbbe4 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -23,30 +23,43 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} + # Publishes via npm trusted publishing (OIDC) — no long-lived npm token. + # GitHub mints a short-lived credential scoped to this one workflow run, so + # there is nothing standing to leak and nothing that bypasses 2FA. The + # trusted publisher registered on npmjs.com pins owner/repo AND this exact + # workflow filename, so renaming this file breaks publishing until the + # registration is updated to match. publish: needs: release-please if: ${{ needs.release-please.outputs.release_created == 'true' }} runs-on: ubuntu-latest permissions: contents: read + id-token: write # required for OIDC — without it npm falls back to a token steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 + # Trusted publishing needs Node >= 22.14 and npm >= 11.5.1. Node 22 still + # bundles npm 10.x, hence the explicit upgrade below. This is the publish + # job only — ci.yml keeps testing on Node 20 to hold the engines floor. - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: pnpm registry-url: https://registry.npmjs.org + - run: npm install -g npm@latest + - run: pnpm install --frozen-lockfile # Build the published artifact (tsc + bundles the Worker into dist/). - run: pnpm --filter gitflare build + # No NODE_AUTH_TOKEN: the npm CLI detects the OIDC environment and + # authenticates with it. Provenance attestations are generated + # automatically for public packages published this way. - name: Publish to npm working-directory: packages/cli run: npm publish --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}