diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 89f61f6..71d981f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -45,15 +45,6 @@ jobs: exit 1 fi - - name: Check npm token - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - if [ -z "$NODE_AUTH_TOKEN" ]; then - echo "NPM_TOKEN secret is required to publish the npm package." - exit 1 - fi - - name: Run GoReleaser uses: goreleaser/goreleaser-action@v7 with: @@ -69,11 +60,10 @@ jobs: with: node-version: '24' registry-url: https://registry.npmjs.org + package-manager-cache: false - name: Publish npm package working-directory: npm - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | node scripts/set-version.js "$GITHUB_REF_NAME" - npm publish --access public --provenance + npm publish --access public diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0cd35d..106e3e7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,23 +9,24 @@ make lint make test ``` -## Release Secrets +## Release Credentials The release workflow publishes three outputs when a `v*` tag is pushed: - GitHub Release assets, using the repository `GITHUB_TOKEN` - Homebrew formula updates, using `TAP_GITHUB_TOKEN` -- npm package updates, using `NPM_TOKEN` +- npm package updates, using npm Trusted Publishing with GitHub Actions OIDC -`GITHUB_TOKEN` is created automatically by GitHub Actions. The other two tokens -must be created manually and saved as repository secrets in `go-tapd/cli`. +`GITHUB_TOKEN` is created automatically by GitHub Actions. `TAP_GITHUB_TOKEN` +must be created manually and saved as a repository secret in `go-tapd/cli`. +npm publishing does not use a long-lived repository secret; it depends on a +trusted publisher configuration on npmjs.com. -### Required Secrets +### Required Repository Secrets | Secret | Used for | Minimum access | | --- | --- | --- | | `TAP_GITHUB_TOKEN` | Commit the generated Homebrew formula to `go-tapd/homebrew-tap` | GitHub fine-grained personal access token with `Contents: Read and write` on `go-tapd/homebrew-tap` | -| `NPM_TOKEN` | Publish `@go-tapd/tapd` to npm | npm granular access token with `Read and write` access to the `@go-tapd` package scope | ### Configure `TAP_GITHUB_TOKEN` @@ -58,52 +59,40 @@ write to the tap repository. The token does not need access to issues, pull requests, actions, administration, or any repository other than `go-tapd/homebrew-tap`. -### Configure `NPM_TOKEN` - -Create this token from npm: - -1. Open `https://www.npmjs.com/settings/flc1125/tokens`. -2. Click `Generate New Token`. -3. Use a descriptive name, such as `go-tapd-cli-release`. -4. Add a description, such as `Publish @go-tapd/tapd from GitHub Actions`. -5. If npm asks for token type, choose a granular access token. -6. In `Packages and scopes`, set permission to `Read and write`. -7. Select the `@go-tapd` scope. If the scope cannot be selected before the - first package exists, temporarily select all packages, publish once, then - replace the token with a narrower `@go-tapd` token. -8. Do not rely on organization permissions alone. Organization access controls - teams and settings, but package publishing requires package or scope access. -9. Set an expiration date and note it somewhere you will check before the next - release. -10. If the account or package requires two-factor authentication for publish - actions, enable `Bypass two-factor authentication` for this CI token. -11. Generate the token and copy it immediately. +### Configure npm Trusted Publishing -Save it in the CLI repository: +Configure trusted publishing from npm: -1. Open `https://github.com/go-tapd/cli/settings/secrets/actions`. -2. Click `New repository secret`. -3. Set `Name` to `NPM_TOKEN`. -4. Paste the token into `Secret`. -5. Save the secret. +1. Open `https://www.npmjs.com/package/@go-tapd/tapd`. +2. Open the package settings. +3. Find the Trusted Publishing or Trusted Publisher section. +4. Choose GitHub Actions as the publisher. +5. Set organization or user to `go-tapd`. +6. Set repository to `cli`. +7. Set workflow filename to `release.yml`. +8. Leave environment empty unless the release workflow starts using a GitHub + environment. +9. Under Allowed actions, select `npm publish`. +10. Click Add publisher to save the trusted publisher configuration. -Why this permission is needed: the release workflow runs -`npm publish --access public --provenance` from the `npm/` package directory. -The token must be able to publish `@go-tapd/tapd`. It does not need access to -private packages or unrelated npm scopes. +Why this permission is needed: the release workflow runs `npm publish --access +public` from the `npm/` package directory. npm exchanges the GitHub Actions OIDC +identity for a short-lived publish token, so no long-lived npm repository secret +is required. Trusted publishing automatically generates npm provenance +attestations from GitHub Actions, so the workflow does not need to pass +`--provenance`. -### Verify Secret Configuration +### Verify Release Configuration -Check that both GitHub repository secrets exist: +Check that the required GitHub repository secret exists: ```bash gh secret list ``` -Expected names: +Expected name: ```text -NPM_TOKEN TAP_GITHUB_TOKEN ``` @@ -124,19 +113,23 @@ Expected results: - `npm publish --access public --dry-run` prints the package contents and ends with `+ @go-tapd/tapd@...`. -The dry-run does not prove that `NPM_TOKEN` itself has the correct access. It -only proves the local npm account and package metadata are valid. The token is -exercised by the GitHub Actions release workflow. +Manually re-open the npm package settings and confirm the trusted publisher +entry still targets `go-tapd/cli`, workflow `release.yml`, and the `npm publish` +allowed action. + +The dry-run does not prove that the trusted publisher is configured correctly. +It only proves the local npm account and package metadata are valid. The trusted +publisher is exercised by the GitHub Actions release workflow. -### Rotate Expired Tokens +### Rotate TAP_GITHUB_TOKEN -When a token is close to expiration: +When `TAP_GITHUB_TOKEN` is close to expiration: 1. Create a replacement token using the same permissions listed above. -2. Update the matching repository secret in +2. Update the repository secret in `https://github.com/go-tapd/cli/settings/secrets/actions`. 3. Re-run the verification commands. -4. Revoke the old token from GitHub or npm after the new secret is saved. +4. Revoke the old token from GitHub after the new secret is saved. Do not commit tokens, `.npmrc` files containing tokens, or screenshots that show token values. @@ -147,3 +140,4 @@ show token values. - npm Docs: [Creating and viewing access tokens](https://docs.npmjs.com/creating-and-viewing-access-tokens/) - npm Docs: [Requiring 2FA for package publishing and settings modification](https://docs.npmjs.com/requiring-2fa-for-package-publishing-and-settings-modification/) - npm Docs: [Generating provenance statements](https://docs.npmjs.com/generating-provenance-statements/) +- npm Docs: [Trusted publishing for npm packages](https://docs.npmjs.com/trusted-publishers/)