From ddeea7d54df9ca8b653446597a9da43c689bceab Mon Sep 17 00:00:00 2001 From: Kai Koenig Date: Thu, 3 Sep 2026 15:01:27 +1200 Subject: [PATCH] ci: harden npm dependency checks --- .github/workflows/node.js.yml | 78 ++++++++++++++++++++++++++++++++++- package.json | 5 --- 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 4dd4f77..5b7c5a4 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -9,6 +9,9 @@ on: pull_request: branches: [ "main", "develop" ] +permissions: + contents: read + jobs: build: @@ -26,7 +29,8 @@ jobs: with: node-version: ${{ matrix.node-version }} cache: 'npm' - - run: npm ci + - run: npm ci --ignore-scripts + - run: npm run prepare - run: npm test - run: npm run eslint - run: npm run tseslint @@ -43,5 +47,75 @@ jobs: with: node-version: 24.x cache: 'npm' - - run: npm ci + - run: npm ci --ignore-scripts - run: npm run prettier:check + + 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', 'example/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 + + example: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v7 + with: + node-version: 24.x + cache: 'npm' + cache-dependency-path: | + package-lock.json + example/package-lock.json + - run: npm ci --ignore-scripts + - run: npm run prepare + - run: npm ci --ignore-scripts + working-directory: example + - run: npm audit --omit=dev + working-directory: example + - run: npm audit signatures + working-directory: example + - name: Smoke test example handler + working-directory: example + run: | + node <<'NODE' + const assert = require('node:assert/strict') + const { handler } = require('./index') + + handler({}, {}) + .then((result) => assert.equal(result, 'all good!')) + .catch((error) => { + console.error(error) + process.exitCode = 1 + }) + NODE diff --git a/package.json b/package.json index 2bf04cc..777af67 100644 --- a/package.json +++ b/package.json @@ -37,11 +37,6 @@ "@types/aws-lambda": "^8.10.160", "raygun": "^2.2.4" }, - "overrides": { - "keyv": "4.5.4", - "flat-cache": "4.0.1", - "file-entry-cache": "8.0.0" - }, "repository": { "type": "git", "url": "git+https://github.com/MindscapeHQ/raygun4node-aws-lambda.git"