|
1 | | -# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created |
2 | | -# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages |
3 | | - |
4 | 1 | name: Publish to NPM |
5 | 2 |
|
6 | 3 | on: |
7 | 4 | push: |
8 | | - branches: |
9 | | - - master |
| 5 | + tags: |
| 6 | + - 'v*.*.*' |
10 | 7 |
|
11 | 8 | permissions: |
12 | | - id-token: 'write' |
13 | | - contents: 'read' |
| 9 | + contents: read |
| 10 | + id-token: write |
14 | 11 |
|
15 | 12 | jobs: |
16 | 13 | publish-npm: |
| 14 | + environment: production |
17 | 15 | runs-on: ubuntu-latest |
18 | 16 | steps: |
19 | | - - name: Package Version Updated |
20 | | - |
21 | | - id: version-updated |
22 | | - with: |
23 | | - path: package.json |
24 | | - env: |
25 | | - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
26 | | - |
27 | | - - name: 'Checkout source code' |
28 | | - if: steps.version-updated.outputs.has-updated |
| 17 | + - name: Checkout (no repo token persisted) |
29 | 18 | uses: actions/checkout@v4 |
| 19 | + with: |
| 20 | + fetch-depth: 0 |
| 21 | + persist-credentials: false |
30 | 22 |
|
31 | | - - uses: actions/setup-node@v4 |
32 | | - if: steps.version-updated.outputs.has-updated |
| 23 | + - name: Setup Node |
| 24 | + uses: actions/setup-node@v4 |
33 | 25 | with: |
34 | 26 | node-version-file: '.nvmrc' |
35 | 27 | registry-url: https://registry.npmjs.org/ |
36 | 28 | cache: 'npm' |
37 | 29 |
|
38 | | - - name: Install |
| 30 | + - name: Assert latest npm |
| 31 | + run: npm i -g npm@latest |
| 32 | + |
| 33 | + - name: Guard - block registry overrides and shady files |
| 34 | + run: | |
| 35 | + # fail if any .npmrc exists in repo |
| 36 | + if git ls-files -z | xargs -0 -I{} bash -lc '[[ "{}" == *.npmrc ]]' | grep -q .; then |
| 37 | + echo "Repo contains an .npmrc. Refusing to publish."; exit 1; |
| 38 | + fi |
| 39 | + # fail if publishConfig.registry set |
| 40 | + node -e "const p=require('./package.json'); if(p.publishConfig?.registry){console.error('publishConfig.registry present — refuse to publish'); process.exit(1)}" |
| 41 | + # optional: block workflow/script changes in the release commit |
| 42 | + # git diff --name-only HEAD~1..HEAD | grep -E '^\.github/(workflows|scripts)/' && { echo 'Workflow/scripts changed in release commit — refuse.'; exit 1; } || true |
| 43 | + SHA=$(git rev-list -n 1 "$GITHUB_REF_NAME") |
| 44 | + PARENT=$(git rev-list -n 1 "$SHA^") |
| 45 | + git diff --name-only "$PARENT" "$SHA" | grep -E '^\.github/(workflows|scripts)/' \ |
| 46 | + && { echo 'Workflow/scripts changed in release commit — refuse.'; exit 1; } || true |
| 47 | +
|
| 48 | + - name: Verify tag matches package version |
| 49 | + run: | |
| 50 | + PKG_VERSION=$(node -p "require('./package.json').version") |
| 51 | + TAG="${GITHUB_REF_NAME#v}" |
| 52 | + [[ "$PKG_VERSION" == "$TAG" ]] || { echo "Tag v$TAG != package.json $PKG_VERSION"; exit 1; } |
| 53 | +
|
| 54 | + - name: Install deps (no lifecycle scripts) |
39 | 55 | run: npm ci --ignore-scripts |
40 | | - if: steps.version-updated.outputs.has-updated |
41 | 56 |
|
42 | 57 | - run: npm run clean |
43 | | - if: steps.version-updated.outputs.has-updated |
44 | | - |
45 | 58 | - run: npm run build |
46 | | - if: steps.version-updated.outputs.has-updated |
47 | 59 |
|
48 | | - - run: npm publish --ignore-scripts --provenance |
49 | | - if: steps.version-updated.outputs.has-updated |
| 60 | + - name: Publish |
50 | 61 | env: |
51 | | - NODE_AUTH_TOKEN: ${{secrets.npm_token}} |
| 62 | + NPM_CONFIG_PROVENANCE: true |
| 63 | + run: npm publish --access public --ignore-scripts --registry=https://registry.npmjs.org/ --provenance |
0 commit comments