diff --git a/.github/npm-trusted-publishing.md b/.github/npm-trusted-publishing.md new file mode 100644 index 00000000..a4338acf --- /dev/null +++ b/.github/npm-trusted-publishing.md @@ -0,0 +1,30 @@ +# npm Trusted Publishing + +The npm publish workflows use GitHub Actions OIDC instead of a long-lived +`NPM_TOKEN`. Each package must have a matching Trusted Publisher entry on npm +before its first publish after this migration. + +For each package (`@snowluma/sdk`, `@snowluma/ui`, and `@snowluma/mcp`), open +the package's npm settings and add a **GitHub Actions** trusted publisher with: + +| Field | Value | +| --- | --- | +| Organization or user | `SnowLuma` | +| Repository | `SnowLuma` | +| Workflow filename | The exact filename below | +| Environment | `SnowLuma` | + +| Package | Workflow filename | +| --- | --- | +| `@snowluma/sdk` | `sdk-npm-publish.yml` | +| `@snowluma/ui` | `ui-npm-publish.yml` | +| `@snowluma/mcp` | `mcp-npm-publish.yml` | + +The workflow job keeps the `SnowLuma` GitHub Environment, so the environment +field must match exactly. The workflows grant `id-token: write`, use Node 24 +(which provides a recent enough npm CLI), and publish with provenance. They do +not read `NPM_TOKEN`. + +After all three entries are saved, rerun the failed workflow runs. Once a +successful publish is confirmed for every package, the obsolete `NPM_TOKEN` +environment secret can be removed from GitHub Actions settings. diff --git a/.github/workflows/mcp-npm-publish.yml b/.github/workflows/mcp-npm-publish.yml index 9b616f17..f782a2c0 100644 --- a/.github/workflows/mcp-npm-publish.yml +++ b/.github/workflows/mcp-npm-publish.yml @@ -40,7 +40,10 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version-file: '.node-version' + # Trusted Publishing requires Node >=22.14 and npm >=11.5.1. + # Node 24 ships a supported npm CLI; the application runtime stays + # pinned separately by .node-version. + node-version: '24' cache: 'pnpm' registry-url: 'https://registry.npmjs.org' @@ -77,21 +80,17 @@ jobs: echo "already_published=false" >> "${GITHUB_OUTPUT}" fi - - name: Validate npm token + - name: Show Trusted Publishing toolchain if: steps.npm.outputs.already_published != 'true' - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - if [ -z "${NODE_AUTH_TOKEN}" ]; then - echo 'Missing NPM_TOKEN in the SnowLuma environment secrets.' >&2 - exit 1 - fi + node --version + npm --version - name: Publish MCP to npm if: steps.npm.outputs.already_published != 'true' working-directory: packages/mcp - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + # Authentication is supplied by npm Trusted Publishing through the + # GitHub OIDC token (permissions.id-token: write above). run: npm publish --access public --provenance - name: Summary @@ -106,4 +105,5 @@ jobs: echo "| Version | \`${{ steps.npm.outputs.package_version }}\` |" echo "| Already published | \`${{ steps.npm.outputs.already_published }}\` |" echo "| Environment | \`SnowLuma\` |" + echo "| Authentication | npm Trusted Publishing (GitHub OIDC) |" } >> "${GITHUB_STEP_SUMMARY}" diff --git a/.github/workflows/sdk-npm-publish.yml b/.github/workflows/sdk-npm-publish.yml index eeba8429..8acee525 100644 --- a/.github/workflows/sdk-npm-publish.yml +++ b/.github/workflows/sdk-npm-publish.yml @@ -37,7 +37,10 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version-file: '.node-version' + # Trusted Publishing requires Node >=22.14 and npm >=11.5.1. + # Node 24 ships a supported npm CLI; the application runtime stays + # pinned separately by .node-version. + node-version: '24' cache: 'pnpm' registry-url: 'https://registry.npmjs.org' @@ -74,21 +77,17 @@ jobs: echo "already_published=false" >> "${GITHUB_OUTPUT}" fi - - name: Validate npm token + - name: Show Trusted Publishing toolchain if: steps.npm.outputs.already_published != 'true' - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - if [ -z "${NODE_AUTH_TOKEN}" ]; then - echo 'Missing NPM_TOKEN in the SnowLuma environment secrets.' >&2 - exit 1 - fi + node --version + npm --version - name: Publish SDK to npm if: steps.npm.outputs.already_published != 'true' working-directory: packages/sdk - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + # Authentication is supplied by npm Trusted Publishing through the + # GitHub OIDC token (permissions.id-token: write above). run: npm publish --access public --provenance - name: Summary @@ -103,4 +102,5 @@ jobs: echo "| Version | \`${{ steps.npm.outputs.package_version }}\` |" echo "| Already published | \`${{ steps.npm.outputs.already_published }}\` |" echo "| Environment | \`SnowLuma\` |" + echo "| Authentication | npm Trusted Publishing (GitHub OIDC) |" } >> "${GITHUB_STEP_SUMMARY}" diff --git a/.github/workflows/ui-npm-publish.yml b/.github/workflows/ui-npm-publish.yml index 782bd14b..2f33f5a4 100644 --- a/.github/workflows/ui-npm-publish.yml +++ b/.github/workflows/ui-npm-publish.yml @@ -37,7 +37,10 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version-file: '.node-version' + # Trusted Publishing requires Node >=22.14 and npm >=11.5.1. + # Node 24 ships a supported npm CLI; the application runtime stays + # pinned separately by .node-version. + node-version: '24' cache: 'pnpm' registry-url: 'https://registry.npmjs.org' @@ -71,21 +74,17 @@ jobs: echo "already_published=false" >> "${GITHUB_OUTPUT}" fi - - name: Validate npm token + - name: Show Trusted Publishing toolchain if: steps.npm.outputs.already_published != 'true' - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | - if [ -z "${NODE_AUTH_TOKEN}" ]; then - echo 'Missing NPM_TOKEN in the SnowLuma environment secrets.' >&2 - exit 1 - fi + node --version + npm --version - name: Publish UI to npm if: steps.npm.outputs.already_published != 'true' working-directory: packages/ui - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + # Authentication is supplied by npm Trusted Publishing through the + # GitHub OIDC token (permissions.id-token: write above). run: npm publish --access public --provenance - name: Summary @@ -100,4 +99,5 @@ jobs: echo "| Version | \`${{ steps.npm.outputs.package_version }}\` |" echo "| Already published | \`${{ steps.npm.outputs.already_published }}\` |" echo "| Environment | \`SnowLuma\` |" + echo "| Authentication | npm Trusted Publishing (GitHub OIDC) |" } >> "${GITHUB_STEP_SUMMARY}" diff --git a/packages/sdk/VERSIONING.md b/packages/sdk/VERSIONING.md index 1465a227..b4a7920e 100644 --- a/packages/sdk/VERSIONING.md +++ b/packages/sdk/VERSIONING.md @@ -34,7 +34,10 @@ Examples: ## Automated npm Publish -`.github/workflows/sdk-npm-publish.yml` publishes `@snowluma/sdk` when SDK-related files reach `main`, including the automated `dev` to `main` promotion flow. The publish job uses the GitHub Environment named `SnowLuma` and expects an environment secret named `NPM_TOKEN`. +`.github/workflows/sdk-npm-publish.yml` publishes `@snowluma/sdk` when SDK-related files reach `main`, including the automated `dev` to `main` promotion flow. The publish job uses npm Trusted Publishing with the GitHub Environment named `SnowLuma`; it authenticates through GitHub Actions OIDC and does not require an `NPM_TOKEN` secret. + +The one-time npm settings for SDK, UI, and MCP are documented in +[`.github/npm-trusted-publishing.md`](../../.github/npm-trusted-publishing.md). If the package version already exists on npm, the workflow skips publishing that run. Bump `packages/sdk/package.json` before merging SDK changes that should create a new npm release.