From 7c0eeed8d5b3898f1501d1e3ea36758d82a4c1fe Mon Sep 17 00:00:00 2001 From: maziggy Date: Fri, 20 Feb 2026 19:31:41 +0100 Subject: [PATCH] =?UTF-8?q?Both=20workflows=20now=20parse=20package-lock.j?= =?UTF-8?q?son=20directly=20instead=20of=20trusting=20npm=20ls.=20The=20lo?= =?UTF-8?q?ckfile=20correctly=20marks=20minimatch=20as=20dev:=20true=20and?= =?UTF-8?q?=20doesn't=20contain=20npm/tar=20at=20all=20=E2=80=94=20so=20al?= =?UTF-8?q?l=20three=20npm-internal=20packages=20will=20be=20filtered=20ou?= =?UTF-8?q?t=20regardless=20of=20which=20npm=20version=20CI=20uses.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 18 ++++++++---------- .github/workflows/security.yml | 18 ++++++++---------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8c9e60a9..56df79dd5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -152,20 +152,18 @@ jobs: - name: Run npm audit working-directory: frontend run: | - # Only audit production dependencies and filter out npm-internal packages - # (npm audit reports vulnerabilities in its own bundled deps like tar/minimatch). + # Only audit production dependencies and filter out npm-internal packages. + # npm 10.x audit/ls reports vulns in its own bundled deps (npm, tar, minimatch) + # so we parse package-lock.json directly to get the real prod dep list. npm audit --omit=dev --json > /tmp/audit.json 2>/dev/null || true - npm ls --omit=dev --all --json 2>/dev/null > /tmp/deps.json || true python3 -c " - import json, sys, subprocess + import json, sys data = json.load(open('/tmp/audit.json')) - deps = json.load(open('/tmp/deps.json')) + lock = json.load(open('package-lock.json')) prod = set() - def walk(obj): - for name, info in (obj.get('dependencies') or {}).items(): - prod.add(name) - walk(info) - walk(deps) + for path, info in lock.get('packages', {}).items(): + if path and not info.get('dev') and not info.get('devOptional'): + prod.add(path.split('node_modules/')[-1]) vulns = data.get('vulnerabilities', {}) fixable = {n: v for n, v in vulns.items() if n in prod and v.get('severity') in ('high', 'critical') and v.get('fixAvailable')} diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 9e0e8cb5c..0c2f859fd 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -278,23 +278,21 @@ jobs: working-directory: frontend run: | npm audit --omit=dev --json > npm-audit-raw.json 2>/dev/null || true - # Filter audit results to only include actual project dependencies - # (npm audit sometimes reports vulnerabilities in the npm CLI itself) + # Filter audit results to only include actual project dependencies. + # npm 10.x audit/ls reports vulns in its own bundled deps (npm, tar, minimatch) + # so we parse package-lock.json directly to get the real prod dep list. node -e " const fs = require('fs'); const raw = fs.readFileSync('npm-audit-raw.json', 'utf8'); let results; try { results = JSON.parse(raw); } catch { results = { vulnerabilities: {} }; } - const depTree = JSON.parse(require('child_process').execSync( - 'npm ls --omit=dev --all --json 2>/dev/null', { encoding: 'utf8' } - )); + const lock = JSON.parse(fs.readFileSync('package-lock.json', 'utf8')); const prodDeps = new Set(); - (function walk(obj) { - for (const [name, info] of Object.entries(obj.dependencies || {})) { - prodDeps.add(name); - walk(info); + for (const [path, info] of Object.entries(lock.packages || {})) { + if (path && !info.dev && !info.devOptional) { + prodDeps.add(path.split('node_modules/').pop()); } - })(depTree); + } const vulns = results.vulnerabilities || {}; const filtered = {}; for (const [name, info] of Object.entries(vulns)) {