Skip to content

Commit

Permalink
feat: support npm cli provenance v1 attestations (#776)
Browse files Browse the repository at this point in the history
Fixes #614, #450, #449, #515

Adds support for NPM CLIs build provenances, generated when running `npm
publish --provenance --access public` from a [GitHub Actions
workflow](https://github.com/ramonpetgrave64/gundam-visor/blob/599500821344b070902a7a5666064bfdaba715df/.github/workflows/npm-publish.yml#L21).

## Testing

- added unit tests for some new helper functions
- added regression test cases

## Future work

- #493, so we can
do `--print-provenance`
- implemented in
#768 (comment)

---------

Signed-off-by: Ramon Petgrave <ramon.petgrave64@gmail.com>
  • Loading branch information
ramonpetgrave64 committed Jul 30, 2024
1 parent 0b14659 commit 7f3db92
Show file tree
Hide file tree
Showing 24 changed files with 852 additions and 65 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ PASSED: Verified SLSA provenance

Verification of npm packages is currently an experimental feature.

More details about npm attestations are in [docs/npm.md](./docs/npm.md)

#### The verify-npm-package command

```bash
Expand Down
187 changes: 186 additions & 1 deletion cli/slsa-verifier/main_regression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1519,6 +1519,14 @@ func Test_runVerifyNpmPackage(t *testing.T) {
pkgName: pointerTo("@trishankatdatadog/supreme-goggles"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder v1",
artifact: "gundam-visor-cli-v1-tag.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgVersion: pointerTo("1.0.1"),
pkgName: pointerTo("gundam-visor"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder short runner name",
artifact: "supreme-googles-cli-v02-tag.tgz",
Expand All @@ -1527,6 +1535,17 @@ func Test_runVerifyNpmPackage(t *testing.T) {
pkgName: pointerTo("@trishankatdatadog/supreme-goggles"),
builderID: pointerTo("https://github.com/actions/runner"),
},
{
// The builderID for v1 should never be the "shortname".
// https://github.com/npm/cli/blob/93883bb6459208a916584cad8c6c72a315cf32af/workspaces/libnpmpublish/lib/provenance.js#L58.
name: "valid npm CLI builder v1 short runner name",
artifact: "gundam-visor-cli-v1-tag.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgVersion: pointerTo("1.0.1"),
pkgName: pointerTo("gundam-visor"),
builderID: pointerTo("https://github.com/actions/runner"),
err: serrors.ErrorInvalidBuilderID,
},
{
name: "valid npm CLI builder no builder",
artifact: "supreme-googles-cli-v02-tag.tgz",
Expand All @@ -1535,6 +1554,14 @@ func Test_runVerifyNpmPackage(t *testing.T) {
pkgName: pointerTo("@trishankatdatadog/supreme-goggles"),
err: serrors.ErrorInvalidBuilderID,
},
{
name: "valid npm CLI builder v1 no builder",
artifact: "gundam-visor-cli-v1-tag.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgVersion: pointerTo("1.0.5"),
pkgName: pointerTo("gundam-visor"),
err: serrors.ErrorInvalidBuilderID,
},
{
name: "valid npm CLI builder mismatch builder",
artifact: "supreme-googles-cli-v02-tag.tgz",
Expand All @@ -1544,20 +1571,43 @@ func Test_runVerifyNpmPackage(t *testing.T) {
builderID: pointerTo("https://github.com/actions/runner2"),
err: serrors.ErrorNotSupported,
},
{
name: "valid npm CLI builder v1 mismatch builder",
artifact: "gundam-visor-cli-v1-tag.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgVersion: pointerTo("1.0.1"),
pkgName: pointerTo("gundam-visor"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted2"),
err: serrors.ErrorNotSupported,
},
{
name: "valid npm CLI builder no package name",
artifact: "supreme-googles-cli-v02-tag.tgz",
source: "github.com/trishankatdatadog/supreme-goggles",
pkgVersion: pointerTo("1.0.5"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder v1 no package name",
artifact: "gundam-visor-cli-v1-tag.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgVersion: pointerTo("1.0.1"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder no package version",
artifact: "supreme-googles-cli-v02-tag.tgz",
source: "github.com/trishankatdatadog/supreme-goggles",
pkgName: pointerTo("@trishankatdatadog/supreme-goggles"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder v1 no package version",
artifact: "gundam-visor-cli-v1-tag.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgName: pointerTo("gundam-visor"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder mismatch source",
artifact: "supreme-googles-cli-v02-tag.tgz",
Expand All @@ -1567,6 +1617,15 @@ func Test_runVerifyNpmPackage(t *testing.T) {
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchSource,
},
{
name: "valid npm CLI builder v1 mismatch source",
artifact: "gundam-visor-cli-v1-tag.tgz",
source: "github.com/ramonpetgrave64/gundam-visorS",
pkgVersion: pointerTo("1.0.1"),
pkgName: pointerTo("gundam-visor"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchSource,
},
{
name: "valid npm CLI builder mismatch package version",
artifact: "supreme-googles-cli-v02-tag.tgz",
Expand All @@ -1575,6 +1634,15 @@ func Test_runVerifyNpmPackage(t *testing.T) {
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchPackageVersion,
},
{
name: "valid npm CLI builder v1 mismatch package version",
artifact: "gundam-visor-cli-v1-tag.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgVersion: pointerTo("1.0.2"),
pkgName: pointerTo("gundam-visor"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchPackageVersion,
},
{
name: "valid npm CLI builder mismatch package name",
artifact: "supreme-googles-cli-v02-tag.tgz",
Expand All @@ -1583,6 +1651,15 @@ func Test_runVerifyNpmPackage(t *testing.T) {
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchPackageName,
},
{
name: "valid npm CLI builder v1 mismatch package name",
artifact: "gundam-visor-cli-v1-tag.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgVersion: pointerTo("1.0.1"),
pkgName: pointerTo("gundam-visorS"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchPackageName,
},
{
name: "invalid signature provenance npm CLI",
artifact: "supreme-googles-cli-v02-tag-invalidsigprov.tgz",
Expand All @@ -1592,13 +1669,31 @@ func Test_runVerifyNpmPackage(t *testing.T) {
err: serrors.ErrorInvalidSignature,
},
{
name: "invalid signature provenance npm CLI",
name: "invalid signature provenance npm CLI v1",
artifact: "gundam-visor-cli-v1-tag-invalidsigprov.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgVersion: pointerTo("1.0.1"),
pkgName: pointerTo("gundam-visor"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorInvalidSignature,
},
{
name: "invalid signature publish npm CLI",
artifact: "supreme-googles-cli-v02-tag-invalidsigpub.tgz",
source: "github.com/trishankatdatadog/supreme-goggles",
pkgName: pointerTo("@trishankatdatadog/supreme-goggles"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorInvalidSignature,
},
{
name: "invalid signature publish npm CLI v1",
artifact: "gundam-visor-cli-v1-tag-invalidsigpub.tgz",
source: "github.com/ramonpetgrave64/gundam-visor",
pkgVersion: pointerTo("1.0.1"),
pkgName: pointerTo("gundam-visor"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorInvalidSignature,
},
// npm CLI with main branch.
{
name: "valid npm CLI builder",
Expand All @@ -1608,6 +1703,14 @@ func Test_runVerifyNpmPackage(t *testing.T) {
pkgName: pointerTo("@laurentsimon/provenance-npm-test"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder v1",
artifact: "provenance-npm-test-cli-v1-prega.tgz",
source: "github.com/sigstore/sigstore-js",
pkgVersion: pointerTo("2.3.1"),
pkgName: pointerTo("sigstore"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder short runner name",
artifact: "provenance-npm-test-cli-v02-prega.tgz",
Expand All @@ -1616,6 +1719,17 @@ func Test_runVerifyNpmPackage(t *testing.T) {
pkgName: pointerTo("@laurentsimon/provenance-npm-test"),
builderID: pointerTo("https://github.com/actions/runner"),
},
{
// The builderID for v1 should never be the "shortname".
// https://github.com/npm/cli/blob/93883bb6459208a916584cad8c6c72a315cf32af/workspaces/libnpmpublish/lib/provenance.js#L58.
name: "valid npm CLI builder v1 short runner name",
artifact: "provenance-npm-test-cli-v1-prega.tgz",
source: "github.com/sigstore/sigstore-js",
pkgVersion: pointerTo("2.3.1"),
pkgName: pointerTo("sigstore"),
builderID: pointerTo("https://github.com/actions/runner"),
err: serrors.ErrorInvalidBuilderID,
},
{
name: "valid npm CLI builder no builder",
artifact: "provenance-npm-test-cli-v02-prega.tgz",
Expand All @@ -1624,6 +1738,14 @@ func Test_runVerifyNpmPackage(t *testing.T) {
pkgName: pointerTo("@laurentsimon/provenance-npm-test"),
err: serrors.ErrorInvalidBuilderID,
},
{
name: "valid npm CLI builder v1 no builder",
artifact: "provenance-npm-test-cli-v1-prega.tgz",
source: "github.com/sigstore/sigstore-js",
pkgVersion: pointerTo("2.3.1"),
pkgName: pointerTo("sigstore"),
err: serrors.ErrorInvalidBuilderID,
},
{
name: "valid npm CLI builder mismatch builder",
artifact: "provenance-npm-test-cli-v02-prega.tgz",
Expand All @@ -1633,27 +1755,58 @@ func Test_runVerifyNpmPackage(t *testing.T) {
builderID: pointerTo("https://github.com/actions/runner2"),
err: serrors.ErrorNotSupported,
},
{
name: "valid npm CLI builder v1 mismatch builder",
artifact: "provenance-npm-test-cli-v1-prega.tgz",
source: "github.com/sigstore/sigstore-js",
pkgVersion: pointerTo("2.3.1"),
pkgName: pointerTo("sigstore"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted2"),
err: serrors.ErrorNotSupported,
},
{
name: "valid npm CLI builder no package name",
artifact: "provenance-npm-test-cli-v02-prega.tgz",
pkgVersion: pointerTo("1.0.3"),
source: "github.com/laurentsimon/provenance-npm-test",
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder v1 no package name",
artifact: "provenance-npm-test-cli-v1-prega.tgz",
pkgVersion: pointerTo("2.3.1"),
source: "github.com/sigstore/sigstore-js",
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder no package version",
artifact: "provenance-npm-test-cli-v02-prega.tgz",
source: "github.com/laurentsimon/provenance-npm-test",
pkgName: pointerTo("@laurentsimon/provenance-npm-test"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder v1 no package version",
artifact: "provenance-npm-test-cli-v1-prega.tgz",
source: "github.com/sigstore/sigstore-js",
pkgName: pointerTo("sigstore"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
},
{
name: "valid npm CLI builder mismatch source",
artifact: "provenance-npm-test-cli-v02-prega.tgz",
source: "github.com/laurentsimon/provenance-npm-test2",
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchSource,
},
{
name: "valid npm CLI builder v1 mismatch source",
artifact: "provenance-npm-test-cli-v1-prega.tgz",
source: "github.com/sigstore/sigstore-js2",
pkgName: pointerTo("sigstore"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchSource,
},
{
name: "valid npm CLI builder mismatch package version",
artifact: "provenance-npm-test-cli-v02-prega.tgz",
Expand All @@ -1662,6 +1815,14 @@ func Test_runVerifyNpmPackage(t *testing.T) {
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchPackageVersion,
},
{
name: "valid npm CLI builder v1 mismatch package version",
artifact: "provenance-npm-test-cli-v1-prega.tgz",
source: "github.com/sigstore/sigstore-js",
pkgVersion: pointerTo("2.3.2"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchPackageVersion,
},
{
name: "valid npm CLI builder mismatch package name",
artifact: "provenance-npm-test-cli-v02-prega.tgz",
Expand All @@ -1670,6 +1831,14 @@ func Test_runVerifyNpmPackage(t *testing.T) {
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchPackageName,
},
{
name: "valid npm CLI builder v1 mismatch package name",
artifact: "provenance-npm-test-cli-v1-prega.tgz",
source: "github.com/sigstore/sigstore-js",
pkgName: pointerTo("sigstore2"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorMismatchPackageName,
},
{
name: "invalid signature provenance npm CLI",
artifact: "provenance-npm-test-cli-v02-prega-invalidsigprov.tgz",
Expand All @@ -1678,6 +1847,14 @@ func Test_runVerifyNpmPackage(t *testing.T) {
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorInvalidSignature,
},
{
name: "invalid signature provenance npm CLI v1",
artifact: "provenance-npm-test-cli-v1-prega-invalidsigprov.tgz",
source: "github.com/sigstore/sigstore-js",
pkgName: pointerTo("sigstore"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorInvalidSignature,
},
{
name: "invalid signature publish npm CLI",
artifact: "provenance-npm-test-cli-v02-prega-invalidsigpub.tgz",
Expand All @@ -1686,6 +1863,14 @@ func Test_runVerifyNpmPackage(t *testing.T) {
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorInvalidSignature,
},
{
name: "invalid signature publish npm CLI v1",
artifact: "provenance-npm-test-cli-v1-prega-invalidsigpub.tgz",
source: "github.com/sigstore/sigstore-js",
pkgName: pointerTo("sigstore"),
builderID: pointerTo("https://github.com/actions/runner/github-hosted"),
err: serrors.ErrorInvalidSignature,
},
// OSSF builder.
{
name: "valid npm OSSF builder",
Expand Down
Binary file not shown.
Loading

0 comments on commit 7f3db92

Please sign in to comment.