* Handles OpenID Connect (OIDC) token retrieval and exchange for CI environments. * * This function is designed to work in Continuous Integration (CI) environments such as GitHub Actions, GitLab, and CircleCI. * It retrieves an OIDC token from the CI environment, exchanges it for an npm token, an
({ packageName, registry, opts, config })
| 19 | * @see https://circleci.com/docs/openid-connect-tokens/ for CircleCI OIDC. |
| 20 | */ |
| 21 | async function oidc ({ packageName, registry, opts, config }) { |
| 22 | /* |
| 23 | * This code should never run when people try to publish locally on their machines. |
| 24 | * It is designed to execute only in Continuous Integration (CI) environments. |
| 25 | */ |
| 26 | |
| 27 | try { |
| 28 | if (!( |
| 29 | /** @see https://github.com/watson/ci-info/blob/v4.2.0/vendors.json#L152 */ |
| 30 | ciInfo.GITHUB_ACTIONS || |
| 31 | /** @see https://github.com/watson/ci-info/blob/v4.2.0/vendors.json#L161C13-L161C22 */ |
| 32 | ciInfo.GITLAB || |
| 33 | /** @see https://github.com/watson/ci-info/blob/v4.2.0/vendors.json#L78 */ |
| 34 | ciInfo.CIRCLE |
| 35 | )) { |
| 36 | return undefined |
| 37 | } |
| 38 | |
| 39 | /** |
| 40 | * Check if the environment variable `NPM_ID_TOKEN` is set. |
| 41 | * In GitLab CI, the ID token is provided via an environment variable, |
| 42 | * with `NPM_ID_TOKEN` serving as a predefined default. For consistency, |
| 43 | * all supported CI environments are expected to support this variable. |
| 44 | * In contrast, GitHub Actions uses a request-based approach to retrieve the ID token. |
| 45 | * The presence of this token within GitHub Actions will override the request-based approach. |
| 46 | * This variable follows the prefix/suffix convention from sigstore (e.g., `SIGSTORE_ID_TOKEN`). |
| 47 | * @see https://docs.sigstore.dev/cosign/signing/overview/ |
| 48 | */ |
| 49 | let idToken = process.env.NPM_ID_TOKEN |
| 50 | |
| 51 | if (!idToken && ciInfo.GITHUB_ACTIONS) { |
| 52 | /** |
| 53 | * GitHub Actions provides these environment variables: |
| 54 | * - `ACTIONS_ID_TOKEN_REQUEST_URL`: The URL to request the ID token. |
| 55 | * - `ACTIONS_ID_TOKEN_REQUEST_TOKEN`: The token to authenticate the request. |
| 56 | * Only when a workflow has the following permissions: |
| 57 | * ``` |
| 58 | * permissions: |
| 59 | * id-token: write |
| 60 | * ``` |
| 61 | * @see https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-cloud-providers#adding-permissions-settings |
| 62 | */ |
| 63 | if (!( |
| 64 | process.env.ACTIONS_ID_TOKEN_REQUEST_URL && |
| 65 | process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN |
| 66 | )) { |
| 67 | log.silly('oidc', 'Skipped because incorrect permissions for id-token within GitHub workflow') |
| 68 | return undefined |
| 69 | } |
| 70 | |
| 71 | /** |
| 72 | * The specification for an audience is `npm:registry.npmjs.org`, where "registry.npmjs.org" can be any supported registry. |
| 73 | */ |
| 74 | const audience = `npm:${new URL(registry).hostname}` |
| 75 | const url = new URL(process.env.ACTIONS_ID_TOKEN_REQUEST_URL) |
| 76 | url.searchParams.append('audience', audience) |
| 77 | const startTime = Date.now() |
| 78 | const response = await fetch(url.href, { |
no test coverage detected
searching dependent graphs…