Npm Audits and GitHub Actions
Packages get old, security bugs are founds, new versions are released. It’s a good practice to find out what packages in my project are outdated, so I can take actions and update them to newer versions if that’s desirable.
I’m sure there’re many different tools for that. One of them comes with npm package manager:
$ npm audit
It can also take some options, --audit-level
is one of them. For example if I want npm audit to return an error code only when moderate or higher vulnerabilities are found, I set --audit-level moderate
It will hopefully report:
found 0 vulnerabilities
A nice thing about npm audit
is it’s easy to run it in a pipeline, for example in GitHub Actions, a job with npm audit might look like this:
jobs:
audit:
name: Audit packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Audit packages
run: npm audit --audit-level moderate
env:
CI: true
With the CI
envrionment variable, it runs a bit more efficiently (I think it means it reports less because there’s no need for textual output in pipelines, the return code is what matters the most).
A more complete example could be to run such a check on PR:
name: PR buildon:
pull_request:
workflow_dispatch:jobs:
audit:
name: Audit packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Audit packages
run: npm audit --audit-level moderate
env:
CI: trueanalyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2build:
name: Build with Node ${{ matrix.node_version }}
runs-on: ubuntu-latest
strategy:
matrix:
node_version:
- 12
- 14
- 15
- 16
- 17
- 18
steps:
- uses: actions/checkout@v3
- id: build
uses: ./.github/actions/build
with:
node_version: ${{ matrix.node_version }}
When a PR is created, reopened, or synchronized, this workflow will kick off.
I can further specify in Settings => Branches what checks have to pass in order to be able to merge the PR into a protected branch:
This way, it doesn’t matter that I did not specify any needs
in the jobs, the jobs can run in parallel and I’ll still not be able to merge before they all pass:
Only when they all pass, I can merge to the protected branch:
Or I can set up a periodic check with cron:
name: Static analysison:
schedule:
- cron: '30 8 * * 6'jobs:
audit:
name: Audit packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Audit packages
run: npm audit --audit-level moderate
env:
CI: trueanalyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
Just two warnings regarding cron in GitHub Actions:
- they can be delayed, sometimes by a lot of minutes; e.g. this cron job ran about 15 minutes late; I assume and hope this might be an issue only in the free subscription
- the time is in UTC :) I mean you probably know, but sometimes it can catch me out :)
Or it can all run as a prerequisite for e.g. pushing to an NPM registry:
In Yaml, it can look like this:
name: Run tests and publishon:
push:
branches:
- master
paths-ignore:
- '.github/**'
- '**.md'
- 'tests/**'
workflow_dispatch:jobs:
audit:
name: Audit packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Audit packages
run: npm audit --audit-level moderate
env:
CI: trueanalyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2build:
name: Build with Node ${{ matrix.node_version }}
needs:
- audit
- analyze
runs-on: ubuntu-latest
strategy:
matrix:
node_version:
- 12
- 14
- 15
- 16
- 17
- 18
steps:
- uses: actions/checkout@v3
- id: build
uses: ./.github/actions/build
with:
node_version: ${{ matrix.node_version }}release:
name: Release to npm
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
registry-url: 'https://registry.npmjs.org'
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
This workflow lives in the repo in ./.github/workflows/cd-release.yaml
.
Static checks — linting, security checks, package dependencies checks, and more — can be really helpful when maintaining a project over a long period of time. GitHub Actions allow us to easily automate these checks.