Npm package provenance with Github Actions

taylor-vick-M5tzZtFCOfs-unsplash

Introduction

Npm has added a really nice signing feature to the registry for the first time! Package authors can sign package builds for free and clients can verify the how a particular package version was built.

Why use it?

Npm and Github have an issue where if your npm credentials leak, dodgy people can publish packages to npm that look legit. This introduces malicious code into the ecosystem and it's difficult to detect.

If a package creator signs their builds at the CI/CD source then you can verify that the package was built by the package author and not a malicious actor.

npm signed package ui

This solution mostly applies to packages that are included in other packages but tool is a start at improving the supply chain in the javascript ecosystem so I was keen to check it out!

How to configure signing

The Github and npm docs on adding provenance to your package are pretty good so I won't repeat them here.

There were some issues I came across that I'll document here.

  1. You have to update your deployment libraries to the latest version(s). E.g. I had to upgrade semantic-release to the latest version.

  2. In your github action you have to set permissions to allow signing. The issue is that if you add one permission to a workflow you have to add all permissions required by the workflow.

    If you're using semantic release and are tagging your repo or changing any code in your repo as part of the deploy then you'll need to add the content:write permission to your workflow.

# your workflow
publish:
  permissions:
    id-token: write
    content: write
  1. Add provenance=true to your .npmrc file to enable signing. Make sure the file is not ignored by git. If you keep credentials in your .npmrc file then you should consider using package.json instead.
# package.json
{
  "publishConfig": {
    "provenance": true
  }
}

Wait for npm to process your package. This is much slower with signing than before. It took 10-15 minutes to process my package release on npm.

How to verify a package

You can use the npm UI. There is a prominent badge on the package page that shows if the package is signed or not.

You can see the badge by the version or at the bottom of the package page here on my NestJS ESLint plugin: https://www.npmjs.com/package/@darraghor/eslint-plugin-nestjs-typed

npm signed package ui

You can use npm audit signatures to verify any packages that are published with signatures.

Conclusion

It's pretty easy to setup signing if you use Github Actions and it's free!

Software supply chain is a huge area of concern for anyone building software so it's great to see npm and Github working together to improve the situation.

Package provenance is in beta right now but I'd recommend adding signing to any public packages you publish to npm.