From eb09415e9e6feeab52bd34281d05acfec114005e Mon Sep 17 00:00:00 2001 From: ring-wdr Date: Wed, 25 Mar 2026 23:53:06 +0900 Subject: [PATCH] Validate npm OIDC publishing with a prerelease lane Add a release-driven publish workflow that uses GitHub OIDC, verifies the release tag against package.json, and routes prerelease versions to the npm next dist-tag. Bump the package version to 0.1.35-rc.0 so the pipeline can be exercised without moving latest. Constraint: Branch protection requires release validation to flow through the normal PR and main branch path Rejected: Publish 0.1.35 directly to latest | no consumer-facing package change yet Rejected: Skip real publish and rely on dry-run only | does not validate trusted publisher OIDC Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep prerelease versions on the next dist-tag until a consumer-visible package change is ready for latest Tested: npm run build; npm test; npm pack --dry-run Not-tested: End-to-end GitHub Release triggered npm publish via OIDC until merged and released from main --- .github/workflows/publish.yml | 64 +++++++++++++++++++++++++++++++++++ package-lock.json | 4 +-- package.json | 2 +- 3 files changed, 67 insertions(+), 3 deletions(-) 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..ea5615a --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,64 @@ +name: Publish + +on: + release: + types: + - published + +permissions: + contents: read + id-token: write + +jobs: + publish: + name: Publish package to npm + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Verify release tag matches package version + run: | + node --input-type=module -e " + import { readFileSync } from 'node:fs'; + const pkg = JSON.parse(readFileSync('package.json', 'utf8')); + const expected = 'v' + pkg.version; + const actual = process.env.RELEASE_TAG; + if (actual !== expected) { + console.error('Release tag mismatch:', { actual, expected }); + process.exit(1); + } + " + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} + + - name: Build + run: npm run build + + - name: Test + run: npm test + + - name: Select npm dist-tag + id: publish_meta + run: | + VERSION=$(node -p "JSON.parse(require('node:fs').readFileSync('package.json', 'utf8')).version") + if [[ "$VERSION" == *-* ]]; then + echo "dist_tag=next" >> "$GITHUB_OUTPUT" + echo "publish_args=--provenance --tag next" >> "$GITHUB_OUTPUT" + else + echo "dist_tag=latest" >> "$GITHUB_OUTPUT" + echo "publish_args=--provenance" >> "$GITHUB_OUTPUT" + fi + + - name: Publish to npm + run: npm publish ${{ steps.publish_meta.outputs.publish_args }} diff --git a/package-lock.json b/package-lock.json index 963067c..ca86f86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-devtool-cli", - "version": "0.1.34", + "version": "0.1.35-rc.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "react-devtool-cli", - "version": "0.1.34", + "version": "0.1.35-rc.0", "license": "MIT", "dependencies": { "playwright": "1.58.2" diff --git a/package.json b/package.json index 9238465..5f1d228 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-devtool-cli", - "version": "0.1.34", + "version": "0.1.35-rc.0", "description": "Agent-first CLI for React component tree inspection, snapshot-aware node debugging, and profiler analysis through a Playwright-managed browser session.", "license": "MIT", "type": "module",