Skip to content

feat(plugin-npm): add npm provenance support #6750

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 7, 2025
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
363 changes: 260 additions & 103 deletions .pnp.cjs

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed .yarn/cache/ms-npm-2.1.2-ec0c1512ff-673cdb2c31.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed .yarn/cache/ssri-npm-6.0.1-a40d823fc9-aa85bffced.zip
Binary file not shown.
Binary file not shown.
34 changes: 34 additions & 0 deletions .yarn/versions/e30c5e10.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
releases:
"@yarnpkg/cli": minor
"@yarnpkg/core": minor
"@yarnpkg/plugin-npm": minor
"@yarnpkg/plugin-npm-cli": minor

declined:
- "@yarnpkg/plugin-compat"
- "@yarnpkg/plugin-constraints"
- "@yarnpkg/plugin-dlx"
- "@yarnpkg/plugin-essentials"
- "@yarnpkg/plugin-exec"
- "@yarnpkg/plugin-file"
- "@yarnpkg/plugin-git"
- "@yarnpkg/plugin-github"
- "@yarnpkg/plugin-http"
- "@yarnpkg/plugin-init"
- "@yarnpkg/plugin-interactive-tools"
- "@yarnpkg/plugin-link"
- "@yarnpkg/plugin-nm"
- "@yarnpkg/plugin-pack"
- "@yarnpkg/plugin-patch"
- "@yarnpkg/plugin-pnp"
- "@yarnpkg/plugin-pnpm"
- "@yarnpkg/plugin-stage"
- "@yarnpkg/plugin-typescript"
- "@yarnpkg/plugin-version"
- "@yarnpkg/plugin-workspace-tools"
- "@yarnpkg/builder"
- "@yarnpkg/doctor"
- "@yarnpkg/extensions"
- "@yarnpkg/nm"
- "@yarnpkg/pnpify"
- "@yarnpkg/sdks"
2 changes: 2 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ initScope: yarnpkg

npmPublishAccess: public

npmPublishProvenance: true

packageExtensions:
"@codemirror/lang-html@*":
dependencies:
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
},
"resolutions": {
"ink@^3.2.0": "patch:ink@npm%3A3.2.0#~/.yarn/patches/ink-npm-3.2.0-2f1df5b094.patch",
"yoga-layout-prebuilt": "patch:[email protected]#./.yarn/patches/yoga-layout-prebuilt.patch"
"yoga-layout-prebuilt": "patch:[email protected]#./.yarn/patches/yoga-layout-prebuilt.patch",
"make-fetch-happen@npm:^14.0.1": "portal:packages/make-fetch-smaller",
"make-fetch-happen@npm:^14.0.2": "portal:packages/make-fetch-smaller"
},
"dependenciesMeta": {
"core-js": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,3 +444,44 @@ Our research showed that even our power users aren't always aware of some of the
When enabled, the `enableOfflineMode` flag tells Yarn to ignore remote registries and only pull data from its internal caches. This is a handy mode when working from within network-constrained environments such as planes or trains.

To leave the offline work mode, check how it got enabled by running `yarn config --why`. If `<environment>`, run `unset YARN_ENABLE_OFFLINE_MODE` in your terminal. Otherwise, remove the `enableOfflineMode` flag from the relevant `.yarnrc.yml` files.

## YN0091 - `INVALID_PROVENANCE_ENVIRONMENT`

This error is triggered when the [provenance statement](https://docs.npmjs.com/generating-provenance-statements) cannot be generated in the current environment. GitHub Actions and GitLab CI are the only supported environments at the moment, and this error is triggered when either running in another environment or when credentials are missing.

On GitHub Actions, you need to grant the `write-id` permission to your workflow. Here is an example of how to do that:

```yaml
name: Publish Package to npmjs
on:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-latest # Must run on GitHub-hosted runners
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- run: npm install -g corepack && corepack enable
- run: yarn && yarn build
- run: yarn config set npmAuthToken '${{ secrets.NPM_TOKEN }}'
- run: yarn publish --provenance --tolerate-republish
Comment on lines +468 to +469
Copy link
Contributor

@aduh95 aduh95 Apr 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the actual recommendation? Shouldn't it be using an env variable instead?

Suggested change
- run: yarn config set npmAuthToken '${{ secrets.NPM_TOKEN }}'
- run: yarn publish --provenance --tolerate-republish
- run: yarn publish --provenance --tolerate-republish
env:
YARN_NPM_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it feels cleaner and more self-contained

```

On GitLab CI, you need to produce a `SIGSTORE_ID_TOKEN` for your workflow. Here is an example of how to do that:

```yaml
publish:
image: 'node:22'
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
script:
- npm install -g corepack && corepack enable
- yarn && yarn build
- yarn config set npmAuthToken $NPM_TOKEN
- yarn publish --provenance --tolerate-republish
```
5 changes: 5 additions & 0 deletions packages/docusaurus/static/configuration/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,11 @@
"format": "uri-reference",
"examples": ["./build/index.mjs"]
},
"provenance": {
"title": "Define whether to produce a provenance statement for the package when publishing. Overrides all other provenance settings.",
"type": "boolean",
"examples": [true]
},
"registry": {
"description": "If present, will replace whatever registry is defined in the configuration when the package is about to be pushed to a remote location.",
"type": "string",
Expand Down
9 changes: 8 additions & 1 deletion packages/docusaurus/static/configuration/yarnrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -529,9 +529,16 @@
"_package": "@yarnpkg/plugin-npm-cli",
"type": "string",
"title": "Define the default access to use when publishing packages to the npm registry.",
"description": "Valid values are `public` and `restricted`, but `restricted` usually requires to register for a paid plan (this is up to the registry you use). Can be overridden on a per-package basis using the `publishConfig.access` field.",
"description": "Valid values are `public` and `restricted`, but `restricted` usually requires to register for a paid plan (this is up to the registry you use). Can be overridden on a per-package basis using the [`publishConfig.access`](manifest#publishConfig.access) field.",
"enum": ["public", "restricted"]
},
"npmPublishProvenance": {
"_package": "@yarnpkg/plugin-npm-cli",
"title": "Define whether to attach a provenance statement when publishing packages to the npm registry.",
"description": "If true, Yarn will generate and publish the provenance information when publishing packages. Can be overridden on a per-package basis using the [`publishConfig.provenance`](manifest#publishConfig.provenance) field.",
"type": "boolean",
"default": false
},
"npmAuditExcludePackages": {
"_package": "@yarnpkg/plugin-npm-cli",
"title": "Array of package name glob patterns to exclude from `yarn npm audit`.",
Expand Down
5 changes: 5 additions & 0 deletions packages/make-fetch-smaller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# make-fetch-smaller

This package is a drop-in replacement for `make-fetch-happen`, but uses Node.js native `fetch` instead of pulling [79 dependencies.](https://node-modules.dev/graph#install=make-fetch-happen)

It is used by the [sigstore](https://www.npmjs.com/package/sigstore) package and its dependencies to produce the provenance statement for packages published to the npm registry with `yarn npm publish --provenance`.
2 changes: 2 additions & 0 deletions packages/make-fetch-smaller/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// eslint-disable-next-line
module.exports = fetch;
14 changes: 14 additions & 0 deletions packages/make-fetch-smaller/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "make-fetch-smaller",
"private": true,
"repository": {
"type": "git",
"url": "git+https://github.com/yarnpkg/berry.git",
"directory": "packages/make-fetch-smaller"
},
"license": "BSD-2-Clause",
"type": "commonjs",
"engines": {
"node": ">=18.12.0"
}
}
22 changes: 22 additions & 0 deletions packages/plugin-npm-cli/sources/commands/npm/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export default class NpmPublishCommand extends BaseCommand {
description: `The OTP token to use with the command`,
});

provenance = Option.Boolean(`--provenance`, false, {
description: `Generate provenance for the package. Only available in GitHub Actions and GitLab CI. Can be set globally through the \`npmPublishProvenance\` setting or the \`YARN_NPM_CONFIG_PROVENANCE\` environment variable, or per-package through the \`publishConfig.provenance\` field in package.json.`,
});

async execute() {
const configuration = await Configuration.find(this.context.cwd, this.context.plugins);
const {project, workspace} = await Project.find(configuration, this.context.cwd);
Expand Down Expand Up @@ -102,11 +106,29 @@ export default class NpmPublishCommand extends BaseCommand {
const buffer = await miscUtils.bufferStream(pack);

const gitHead = await npmPublishUtils.getGitHead(workspace.cwd);

let provenance = false;
if (workspace.manifest.publishConfig && `provenance` in workspace.manifest.publishConfig) {
provenance = Boolean(workspace.manifest.publishConfig.provenance);
if (provenance) {
report.reportInfo(null, `Generating provenance statement because \`publishConfig.provenance\` field is set.`);
} else {
report.reportInfo(null, `Skipping provenance statement because \`publishConfig.provenance\` field is set to false.`);
}
} else if (this.provenance) {
provenance = true;
report.reportInfo(null, `Generating provenance statement because \`--provenance\` flag is set.`);
} else if (configuration.get(`npmPublishProvenance`)) {
provenance = true;
report.reportInfo(null, `Generating provenance statement because \`npmPublishProvenance\` setting is set.`);
}

const body = await npmPublishUtils.makePublishBody(workspace, buffer, {
access: this.access,
tag: this.tag,
registry,
gitHead,
provenance,
});

await npmHttpUtils.put(npmHttpUtils.getIdentUrl(ident), body, {
Expand Down
6 changes: 6 additions & 0 deletions packages/plugin-npm-cli/sources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export {NpmWhoamiCommand};
declare module '@yarnpkg/core' {
interface ConfigurationValueMap {
npmPublishAccess: string | null;
npmPublishProvenance: boolean;
npmAuditExcludePackages: Array<string>;
npmAuditIgnoreAdvisories: Array<string>;
}
Expand All @@ -39,6 +40,11 @@ const plugin: Plugin = {
type: SettingsType.STRING,
default: null,
},
npmPublishProvenance: {
description: `Whether to generate provenance for the published packages`,
type: SettingsType.BOOLEAN,
default: false,
},
npmAuditExcludePackages: {
description: `Array of glob patterns of packages to exclude from npm audit`,
type: SettingsType.STRING,
Expand Down
4 changes: 4 additions & 0 deletions packages/plugin-npm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ This plugin adds support for downloading packages from the npm registry.
## Install

This plugin is included by default in Yarn.

## Attribution

Provenance code adapted from [npm/cli](https://github.com/npm/cli/blob/04f53ce13201b460123067d7153f1681342548e1/workspaces/libnpmpublish/lib/provenance.js), under [ISC license](https://github.com/npm/cli/blob/04f53ce13201b460123067d7153f1681342548e1/workspaces/libnpmpublish/LICENSE).
5 changes: 3 additions & 2 deletions packages/plugin-npm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"enquirer": "^2.3.6",
"lodash": "^4.17.15",
"semver": "^7.1.2",
"ssri": "^6.0.1",
"sigstore": "^3.1.0",
"ssri": "^12.0.0",
"tslib": "^2.4.0"
},
"peerDependencies": {
Expand All @@ -22,7 +23,7 @@
"devDependencies": {
"@types/lodash": "^4.14.136",
"@types/semver": "^7.1.0",
"@types/ssri": "^6.0.1",
"@types/ssri": "^7.1.5",
"@yarnpkg/core": "workspace:^",
"@yarnpkg/plugin-pack": "workspace:^"
},
Expand Down
Loading
Loading