Skip to content

Private npm Supply Chain

Wavemap separates package authorization, credential storage, delivery, and publication. A credential is scoped to one actor and operation class; it is never promoted from a developer workstation into CI or from dependency reads into package publication.

Developers should begin with Private npm Access. This page owns the automation and operator lifecycle.

ContextAuthorityCredential And Lifetime
Developer installDeveloper’s npm identity can read declared packages.Developer-owned granular token in the native OS store; normally 180 days.
Wavemap CI dependency installExact packages declared by Wavemap policy.Wavemap-only NPM_PRIVATE_READ_TOKEN Actions secret; normally 180 days.
Local Docker buildSame read authority as the invoking developer.Native token passed as BuildKit secret for one frontend build.
CI Docker buildSame read authority as Wavemap CI.CI token passed as BuildKit secret for one frontend build.
Codon UI publicationExact repository, workflow, branch, and environment.GitHub OIDC identity for one workflow job; no persistent npm write token.
i18n-foundation publicationExact repository, workflow, branch, and environment.GitHub OIDC identity for one workflow job; no persistent npm write token.
Deployed application runtimeNo npm registry authority.No npm token.

The public i18n package must resolve with empty authentication. A token is not added merely because that package shares the same consumer graph.

Wavemap owns one repository Actions secret named NPM_PRIVATE_READ_TOKEN. Its backing npm token is read-only, selects the exact private package set discovered by Wavemap policy, has no organization permissions, and cannot bypass 2FA. Waveguide uses the same external secret name with a different token value so either consumer can be rotated or revoked independently.

The repository’s composite pnpm setup action passes the secret to bin/npm-auth/preflight-ci.sh. Before installation, that preflight:

  1. Validates that the secret has one supported granular-token shape.
  2. Builds a temporary authenticated npm configuration with owner-only permissions.
  3. Resolves every exact private package from the versioned policy.
  4. Resolves every public assertion with credentials removed.
  5. Runs the requested frozen install only after the package proofs pass.

Workflow source references only secrets.NPM_PRIVATE_READ_TOKEN; there is no NPM_TOKEN fallback. Fork, Dependabot, and explicit cache-only lanes remain credential-free and cannot deploy.

Only Wavemap’s frontend graph consumes @codon-ui/cli. Frontend dependency installation receives one BuildKit secret named npm_private_read_token; backend development and deployment builds receive no npm credential. Dockerfiles consume the secret from a mount only for the install instruction, create a temporary owner-only npm configuration, and remove that file inside the same instruction.

Never carry the token through ARG, ENV, Compose environment, a copied npmrc, image metadata, an exported cache, or a runtime container. The public commands:

Terminal window
pnpm wavemap -- npm-auth docker-proof
pnpm wavemap -- npm-auth docker-proof --target frontend-deploy

force no-cache builds without exported image output and scan withheld build output for the exact credential before releasing logs. The named-target form recovers one failed target without rebuilding accepted targets. A Docker change is accepted only when image configuration, history, layers, logs, and exported cache remain credential-free.

Dependency-read credentials do not publish packages. The two source repositories own manual trusted-publication workflows:

PackageSource And WorkflowRequired npm Trusted-Publisher IdentityAccess
@codon-ui/cligabrielbourget/codon-ui / publish-cli.ymlRepository codon-ui, branch develop, environment npm-releaseRestricted
@gabrielbourget/i18n-foundationgabrielbourget/i18n-foundation / publish-package.ymlRepository i18n-foundation, branch main, environment npm-releasePublic

The npm Repository field takes the bare GitHub repository name, not an npm package name. Both workflows require an exact version and publish <version> confirmation, grant id-token: write only to the publication job, and use an npm-release environment with no npm secret or variable. Package publishing access requires 2FA and disallows bypass tokens; trusted publishers remain compatible with that stricter setting.

Do not add NPM_TOKEN, a write token, or an environment secret when OIDC fails. Diagnose package/repository identity, workflow filename, branch, environment, version, and package contents locally. A failed paid or registry-mutating run does not authorize a rerun.

Start ordinary rotation 30 days before expiry and escalate at 7 days:

  1. Create a new read-only token dedicated to Wavemap, selecting the current policy’s complete private package set.
  2. Keep the old token active and update only the Wavemap repository’s NPM_PRIVATE_READ_TOKEN secret.
  3. With explicit authorization for that paid action, run one bounded CI proof that performs an empty-cache install and the relevant clean frontend Docker builds.
  4. Confirm source has no fallback and the accepted run used the replacement secret path.
  5. Revoke the old npm token.
  6. Re-run the least expensive post-revocation package proof needed to show that a cache did not hide stale authority.

Secret mutation, workflow dispatch, rerun, publication, and revocation are separate human gates. Never revoke the only proved credential before its replacement passes the same operation class.

For a departing developer:

  1. Remove the npm identity from package-specific teams and the codon-ui organization.
  2. Have the developer revoke their personal token; do not rotate other developers’ native credentials.
  3. Confirm the removed identity can no longer resolve the private package when a safe non-owner proof is available.
  4. Leave Waveguide and Wavemap CI tokens unchanged unless exposure, not membership, is the reason for offboarding.

For a departing publisher, remove the identity from cli-maintainers or the relevant GitHub environment reviewers. OIDC publication remains bound to the exact repository workflow rather than a personal write token.

Suspected BoundaryContainmentRecovery Proof
Developer token exposedRevoke that token, create a replacement, and run bootstrap --rotate.Both consumer preflights and clean frozen installs pass; CI remains untouched.
Wavemap CI token exposedReplace the Wavemap token and repository secret; do not rotate Waveguide automatically.Exact-package CI preflight and required clean frontend Docker lane pass before old-token revocation.
Token appears in a Docker artifactStop distribution, revoke the responsible token, and inspect image config, history, layers, and caches.Rebuild without cache through the BuildKit-secret path and repeat exact-value scans.
Trusted publication identity failsPause publication; inspect the exact npm publisher tuple and workflow source without adding a write token.Local release checks pass, then one freshly authorized OIDC publication and registry readback pass.
npm membership is broader than policyRemove the unintended team or member grant and review organization-member residual authority.Intended identities retain reads; removed identities are denied; both CI readers remain healthy.

Do not place token values, raw workflow logs, or account inventories in public docs or issues. Record sanitized evidence: repository, workflow/run identifier, package and version, operation class, result, and whether cache-independent proof was used.

The enforcing sources are infra/operations/config/private-npm-access-policy.json, infra/operations/src/private-npm, bin/npm-auth, .github/actions/setup-pnpm, workflow contract tests, frontend Dockerfiles, and Bake definitions. Update this page when the secret name, BuildKit secret ID, package policy, publisher tuple, or rotation ownership changes.