From c691f5b71944b0cc7b2e9dcda62572158f945871 Mon Sep 17 00:00:00 2001 From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com> Date: Mon, 8 Jun 2026 09:11:01 +1000 Subject: [PATCH] SWR-SEC-OIDC-PUBLISH: name OIDC registries + the environment-claim rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep the existing (correct) stance — OIDC for registries that support it, scoped PAT in a protected environment for the IDE marketplaces / brew / scoop — and add two clarifications learned shipping a product release: - Name the OIDC-capable registries explicitly (crates.io, npm w/ provenance, NuGet via NuGet/login@v1 short-lived key, pub.dev) and the id-token/contents permission shape; note the Marketplace token is an org secret + repo allowlist. - Document the environment-claim binding: a trusted-publishing policy scoped to a named GitHub Environment only matches a token from a job that declares that exact `environment:`. Mismatch = silent publish failure. (This is the bug that broke a NuGet OIDC publish: policy Environment=release, job had none.) --- docs/specs/supply-chain-security.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/specs/supply-chain-security.md b/docs/specs/supply-chain-security.md index 5e044a5..abbedb1 100644 --- a/docs/specs/supply-chain-security.md +++ b/docs/specs/supply-chain-security.md @@ -141,9 +141,19 @@ every ecosystem; `dtolnay/rust-toolchain@stable` (a moving branch) is forbidden Where scripts are not needed, prefer `npm ci --ignore-scripts`. **[SWR-SEC-OIDC-PUBLISH] OIDC trusted publishing.** Registry publishing uses short-lived OIDC tokens -with no stored secret wherever the registry supports it; the per-channel plan lists each. Channels -that still require a Personal Access Token (the IDE marketplaces) run that PAT inside a protected -GitHub Environment with required reviewers and a `v*.*.*` tag restriction. +with no stored secret wherever the registry supports it — crates.io, npm (also `--provenance`), NuGet +(`NuGet/login@v1` exchanges the OIDC token for a ~1h, single-use API key), pub.dev. Each such job +declares `permissions: id-token: write` + `contents: read`. The per-channel plan lists each. Channels +with no first-class OIDC path — the IDE marketplaces (VS Code Marketplace, Open VSX) and the cross-repo +git pushes (Homebrew tap, Scoop bucket) — run a scoped, least-privilege token inside a protected GitHub +Environment with required reviewers and a `v*.*.*` tag restriction; the Marketplace token is typically +an org-level secret with a per-repo allowlist. + +**Environment-claim binding (load-bearing).** When a registry's trusted-publishing policy is scoped to +a named GitHub Environment, the publish job MUST declare that exact `environment:` — GitHub only injects +the `environment` claim into the OIDC token for a job bound to an environment, so a policy that names an +environment will reject a token from a job that declares none. Either bind the job to the environment +the policy names, or leave the policy's environment field empty; a mismatch is a silent publish failure. **[SWR-SEC-VULN-GATE] Vulnerability gates.** Product CI runs `osv-scanner` (Rust + Node, PR-diff plus a release full scan), `cargo-deny` (advisories/bans/licenses/sources from a committed `deny.toml`),