Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ jobs:
if: startsWith(github.ref, 'refs/tags/') && vars.PUBLISH_MCP_REGISTRY == 'true'
runs-on: ubuntu-latest
timeout-minutes: 15
# Named in npm's trusted-publisher config, which checks it as an OIDC
# claim: publishing fails unless the two match. Restrict this environment
# to the tag pattern `v*` so a push to any branch cannot reach npm.
#
# Deliberately NOT the existing `release` environment — that one is scoped
# to the `main` branch, and this job runs on a tag ref, so it would be
# rejected outright.
environment: npm-publish
permissions:
contents: read
id-token: write # mints the OIDC token npm exchanges for publish rights
Expand Down
16 changes: 15 additions & 1 deletion dev-docs/CI.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,21 @@ Two jobs at the end of `release.yml` publish the `bomly-mcp` npm wrapper and the

The version must match a GitHub release that is already published: the package's postinstall step downloads that release's archive, so publishing ahead of it ships a package that cannot install.

2. **Set the trusted publisher** at `https://www.npmjs.com/package/bomly-mcp/access` → repository `bomly-dev/bomly-cli`, workflow `release.yml`. Configure it on the *package* access page; the account-level packages page does not have this setting.
2. **Set the trusted publisher** at `https://www.npmjs.com/package/bomly-mcp/access`. Configure it on the *package* access page; the account-level packages page does not have this setting.

| Field | Value |
| --- | --- |
| Publisher | GitHub Actions |
| Organization / Repository | `bomly-dev` / `bomly-cli` |
| Workflow filename | `release.yml` |
| Environment name | `npm-publish` |
| Allowed actions | `npm publish` only |

The environment name is checked as an OIDC claim, so it must match the `environment:` on the `publish-npm` job exactly. The `npm-publish` environment is restricted to the `v*` **tag** pattern, so a push to any branch cannot reach npm.

Do **not** use the existing `release` environment here: it is scoped to the `main` branch, and this job runs on a tag ref, so the deployment would be rejected.

Under **Publishing access**, choose *Require two-factor authentication and disallow bypass 2fa tokens*. Trusted publishers keep working under it, and it blocks token-based publishing entirely — which is the point, since there is no token.

3. **Turn the jobs on:**

Expand Down
15 changes: 14 additions & 1 deletion dev-docs/SECURITY_ASSURANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,26 @@ only their required permissions.
| `scorecard.yml` | `read-all` | Scorecard adds `security-events: write` and `id-token: write` to publish signed results |
| `bomly-guard.yml` | `contents: read` | Guard adds pull-request, issue, and security-event writes for comments and SARIF |
| `update-smoke-goldens.yml` | `contents: read` | The final job adds `contents: write` and `pull-requests: write` to publish reviewed goldens |
| `release.yml` | `contents: read` | Release jobs add only the contents, packages, actions, and OIDC permissions needed to publish artifacts and provenance |
| `release.yml` | `contents: read` | Release jobs add only the contents, packages, actions, and OIDC permissions needed to publish artifacts and provenance. `publish-npm` and `publish-mcp-registry` add `id-token: write` and use **no secret at all** — npm and the MCP Registry both authenticate by exchanging the workflow's OIDC identity (see [MCP Registry Publishing](CI.md#mcp-registry-publishing)) |

Third-party actions are pinned. Long-lived secrets are passed only to the step
that needs them. Release automation prefers short-lived, repository-scoped
GitHub App tokens; the Windows package publication token is validated before
release work starts and remains the documented exception.

npm publication holds no credential of any kind. It uses npm Trusted
Publishing, so npm exchanges the workflow's OIDC identity for publish rights.
The `publish-npm` job is bound to the `npm-publish` environment, which npm
verifies as an OIDC claim and which is restricted to the `v*` tag pattern, so
publishing cannot be reached from a branch push. The package additionally
requires two-factor authentication and disallows bypass-2FA tokens, so the
trusted publisher is the only automated path to the registry.

`mcp-publisher` is downloaded into that same privileged job, so it is pinned by
version and verified twice before execution: against a pinned SHA-256, and with
`cosign verify-blob` against the upstream Sigstore bundle, asserting the
artifact was built by the MCP Registry's own tagged release workflow.

## Evidence Changes

The assurance work is split so each control can be reviewed independently:
Expand Down
Loading