Skip to content

ci: harden npm dependency checks #926

ci: harden npm dependency checks

ci: harden npm dependency checks #926

Workflow file for this run

# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
name: Node.js CI
on:
push:
branches: [ "master", "develop" ]
pull_request:
branches: [ "master", "develop" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x, 22.x, 24.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v7
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci --ignore-scripts
- run: npm run prepare
- run: npm test
# Run CommonJS compatibility test
- run: npm run test:cjs
# Run static analysis on JS files
- run: npm run eslint
# Run static analysis on TS files
- run: npm run tseslint
# Checks code formatting using the version pinned in package-lock.json.
prettier:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Use Node.js 24.x
uses: actions/setup-node@v7
with:
node-version: 24.x
cache: 'npm'
- run: npm ci --ignore-scripts
- run: npm exec -- prettier --check "lib/*.ts" "test/*.js" "examples/**/*.js"
supply-chain:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24.x
cache: 'npm'
- name: Reject known malicious package versions
run: |
node <<'NODE'
const fs = require('node:fs')
const blocked = new Map([
['keyv', '6.0.0'],
['flat-cache', '6.1.24'],
['file-entry-cache', '11.1.6']
])
const lockfiles = [
'package-lock.json',
'examples/express-sample/package-lock.json',
'examples/using-domains/package-lock.json'
]
for (const lockfile of lockfiles) {
const lock = JSON.parse(fs.readFileSync(lockfile, 'utf8'))
for (const [path, metadata] of Object.entries(lock.packages)) {
for (const [name, version] of blocked) {
if ((path === `node_modules/${name}` || path.endsWith(`/node_modules/${name}`)) && metadata.version === version) {
throw new Error(`${lockfile} contains known malicious package ${name}@${version}`)
}
}
}
}
NODE
- run: npm ci --ignore-scripts
- run: npm audit --omit=dev
- run: npm audit signatures
examples:
runs-on: ubuntu-latest
strategy:
matrix:
example: [express-sample, using-domains]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: 24.x
cache: 'npm'
cache-dependency-path: |
package-lock.json
examples/${{ matrix.example }}/package-lock.json
- run: npm ci --ignore-scripts
- run: npm run prepare
- run: npm ci --ignore-scripts
working-directory: examples/${{ matrix.example }}
- run: npm audit --omit=dev
working-directory: examples/${{ matrix.example }}
- run: npm audit signatures
working-directory: examples/${{ matrix.example }}
- name: Smoke test Express example
if: matrix.example == 'express-sample'
working-directory: examples/express-sample
env:
NODE_ENV: production
run: node -e "require('./app')"
- name: Smoke test domains example
if: matrix.example == 'using-domains'
working-directory: examples/using-domains
run: |
node --check app.js
node -e "require('config'); require('raygun')"