ethereumjs / ethereumjs-monorepo

Monorepo for the Ethereum VM TypeScript Implementation
2.58k stars 750 forks source link

Use NPM provenance to improve supply chain security #2676

Open paulmillr opened 1 year ago

paulmillr commented 1 year ago

Most package pages on the npm registry have a link to a source repository, but this information isn’t verified and doesn’t point at any specific commit. With the code explorer you can view the contents of a package before you install it, but this doesn’t help you determine where it came from. What we need is a way to draw a direct line from the npm package back to the exact source code commit from which it was derived. Much like an art historian tracking the chronology of ownership for a painting, we need a statement of provenance for a package which provides a verifiable record of the originating source and the build steps which were used to assemble the final artifact.

How do we ensure the compiled code published to NPM is the same that has been generated from building it by hand? There are two ways:

  1. Store compiled JS code in the repository. Cons: Messes-up diffs, git logs. A huge pain.
  2. Use publicly verifiable transparency logs and CI. NPM started providing it in Apr 2023! The blog post.

Check out bottom of README of https://www.npmjs.com/package/micro-eth-signer, there's new section:

shot

Steps I took:

  1. Create granular NPM access token. It's granular, meaning, it's limited to specific packages and can't touch anything else.
  2. Add this NPM_PUBLISH_TOKEN to GitHub repository secrets.
  3. Add publish-npm.yml to .github/workflows for GitHub Actions CI.
  4. Create new GitHub Release, by hand.

What happened immediately after step 4:

  1. GH CI ran an action that followed steps specified in publish-npm.yml.
  2. It set up a VM, installed node.js of specific version, executed npm install, execute npm run build
  3. It published the output to NPM
  4. It added signed logs to append-only ledger, which allows to verify the build was done properly

This was done manually - but I see our monorepo uses some automated way to generate github releases. It can be combined with software like changesets, which will automatically generate pull requests. Take a look at how sigstore-js did it.

paulmillr commented 1 year ago

Another thing is that you can (and should) always compare the checksum locally. The publish step itself is done in a logged and auditable way via pure-Microsoft infra (gh, npm).