|
|
@@ -230,7 +230,35 @@ jobs:
|
|
|
id: npm-audit
|
|
|
working-directory: frontend
|
|
|
run: |
|
|
|
- npm audit --omit=dev --json > npm-audit-results.json || echo "vulnerabilities_found=true" >> $GITHUB_OUTPUT
|
|
|
+ npm audit --omit=dev --json > npm-audit-raw.json 2>&1 || true
|
|
|
+ # Filter audit results to only include actual project dependencies
|
|
|
+ # (npm audit sometimes reports vulnerabilities in the npm CLI itself)
|
|
|
+ node -e "
|
|
|
+ const fs = require('fs');
|
|
|
+ const results = JSON.parse(fs.readFileSync('npm-audit-raw.json', 'utf8'));
|
|
|
+ const depTree = JSON.parse(require('child_process').execSync(
|
|
|
+ 'npm ls --omit=dev --all --json 2>/dev/null', { encoding: 'utf8' }
|
|
|
+ ));
|
|
|
+ const prodDeps = new Set();
|
|
|
+ (function walk(obj) {
|
|
|
+ for (const [name, info] of Object.entries(obj.dependencies || {})) {
|
|
|
+ prodDeps.add(name);
|
|
|
+ walk(info);
|
|
|
+ }
|
|
|
+ })(depTree);
|
|
|
+ const vulns = results.vulnerabilities || {};
|
|
|
+ const filtered = {};
|
|
|
+ for (const [name, info] of Object.entries(vulns)) {
|
|
|
+ if (prodDeps.has(name)) filtered[name] = info;
|
|
|
+ }
|
|
|
+ results.vulnerabilities = filtered;
|
|
|
+ fs.writeFileSync('npm-audit-results.json', JSON.stringify(results, null, 2));
|
|
|
+ const count = Object.keys(filtered).length;
|
|
|
+ console.log(count > 0
|
|
|
+ ? count + ' production vulnerabilities found'
|
|
|
+ : 'No production vulnerabilities (filtered ' + Object.keys(vulns).length + ' npm-internal entries)');
|
|
|
+ if (count > 0) process.exit(1);
|
|
|
+ " || echo "vulnerabilities_found=true" >> $GITHUB_OUTPUT
|
|
|
npm audit --omit=dev --audit-level=high || true
|
|
|
|
|
|
- name: Upload audit results
|