diff --git a/api/base.yaml b/api/base.yaml index 74192fe..ee8e362 100644 --- a/api/base.yaml +++ b/api/base.yaml @@ -67,7 +67,7 @@ tags: **Granular Access Tokens with `bypass_2fa`:** Granular Access Tokens (GATs) created with `bypass_2fa: true` are - allowed to perform automation flows such as direct publish, but they + allowed to perform automation flows within their scopes and publish policy, but they are **not** permitted to perform account-identity or governance write operations. Requests to those endpoints authenticated with a bypass-2FA GAT are rejected with `403 Forbidden` and must instead be @@ -91,7 +91,7 @@ tags: `PUT`/`DELETE /-/team/{orgName}/{teamName}/package` Direct publish (`PUT /{escapedPackageName}`) remains functional for - bypass-2FA GATs. + direct-capable bypass-2FA GATs. It is not permitted for stage-only GATs. - name: Tokens x-displayName: Tokens diff --git a/api/registry.npmjs.com/publish.yaml b/api/registry.npmjs.com/publish.yaml index 73b0a52..6d2d9c2 100644 --- a/api/registry.npmjs.com/publish.yaml +++ b/api/registry.npmjs.com/publish.yaml @@ -20,6 +20,19 @@ paths: tags: - Publish summary: Publish a new version of a package + description: | + Publish a new package version directly to the registry. + + Stage-only Granular Access Tokens cannot publish new versions through this + endpoint, even with `bypass_2fa: true`. Requests rejected by the publish-policy + check return `403 Forbidden` with `E_STAGE_REQUIRED` in the error message. + Earlier authentication or package authorization checks can return other errors, + including `404 Not Found`. Rejected requests are not automatically redirected + to staging. Use `POST /-/stage/package/{package-name}` + (`npm stage publish`), followed by maintainer approval with 2FA. + + The stage-only policy restricts new-version publication. Existing authorization + and 2FA requirements still apply. operationId: publish requestBody: required: true diff --git a/api/registry.npmjs.com/token.yaml b/api/registry.npmjs.com/token.yaml index fef455f..3e442f4 100644 --- a/api/registry.npmjs.com/token.yaml +++ b/api/registry.npmjs.com/token.yaml @@ -8,6 +8,23 @@ paths: Create a new npm access token with customizable permissions, scope restrictions, expiration, and CIDR IP range limitations. + To create a stage-only Granular Access Token (GAT), set + `packages_and_scopes_permission` to `read-write-stage-only` and select + at least one package or scope. This grants package write access but + restricts publishing new versions to `POST /-/stage/package/{package-name}` + (`npm stage publish`). Direct publication is not allowed or automatically staged. + Requests rejected by the publish-policy check return `403 Forbidden` with + `E_STAGE_REQUIRED` in the error message. Earlier authentication or package + authorization checks can return other errors, including `404 Not Found`. + A maintainer must approve the staged version with 2FA before publication. + Stage-only is not a valid value for `orgs_permission`. + + The publish restriction is separate from `bypass_2fa`. Stage-only tokens + can be created with either setting, and existing scope, permission, and + 2FA checks still apply to all operations. The restriction does not itself + remove other package write capabilities, such as changing dist-tags or + deprecating versions. + **Requirements:** - Must be authenticated - **Two-factor authentication is required for this endpoint** @@ -86,12 +103,14 @@ paths: oneOf: - type: number - type: string - description: 'Expiration in days (number) or ISO date string. Read-write tokens: maximum 90 days, defaults to 7 days. Read-only tokens: unlimited maximum, defaults to 30 days' + description: 'Expiration in days (number) or ISO date string. Read-write tokens, including read-write-stage-only: maximum 90 days, defaults to 7 days. Read-only tokens: unlimited maximum, defaults to 30 days' bypass_2fa: type: boolean description: | Allow token to bypass 2FA requirements for automation - flows such as direct publish. + flows permitted by its package permissions and publish policy. + This does not allow a stage-only token to publish directly or + bypass the 2FA challenge when approving a staged version. Tokens created with `bypass_2fa: true` **cannot** perform account, token, or org/team/package governance write @@ -125,8 +144,17 @@ paths: description: Organizations this token can access. Empty arrays are treated as not provided packages_and_scopes_permission: type: string - enum: ["read-only", "read-write", "no-access"] - description: Permission for packages and scopes. Defaults to "read-only" if packages/scopes arrays have length > 0, otherwise "no-access" + enum: ["read-only", "read-write", "read-write-stage-only", "no-access"] + description: | + Permission for packages and scopes. Defaults to "read-only" if + packages/scopes arrays have length > 0, otherwise "no-access". + + - `read-only`: read package data. + - `read-write`: package write access, including direct and staged publishing. + - `read-write-stage-only`: package write access with new versions restricted + to staged publishing and subsequent maintainer approval with 2FA. + - `no-access`: no package or scope permissions. + orgs_permission: type: string enum: ["read-only", "read-write", "no-access"] @@ -134,6 +162,17 @@ paths: required: - password - name + examples: + stageOnly: + summary: Stage-only GAT for an existing package + value: + password: '' + name: 'staged-release-ci' + packages: ['@myorg/release-tools'] + packages_and_scopes_permission: 'read-write-stage-only' + orgs_permission: 'no-access' + expires: 7 + bypass_2fa: true security: - npmSessionToken: [] - npmAccessToken: [] @@ -216,7 +255,8 @@ paths: action: type: string description: Permission action ("read" or "write"). - description: List of permissions granted to this token. + description: | + List of permissions granted to this token. scopes: type: array items: @@ -258,7 +298,7 @@ paths: invalidPackagesPermission: summary: Invalid packages_and_scopes_permission value value: - error: 'Invalid packages_and_scopes_permission. Must be one of: no-access, read-only, read-write' + error: 'Invalid packages_and_scopes_permission. Must be one of: no-access, read-only, read-write, read-write-stage-only' invalidOrgsPermission: summary: Invalid orgs_permission value value: