fix(deploy): patch audited frontend dependencies
CI and Deploy / test (push) Failing after 25m4s
CI and Deploy / deploy (push) Has been skipped

This commit is contained in:
cesnimda
2026-10-17 21:02:45 +02:00
parent e7dba9a2f7
commit 2278473763
7 changed files with 329 additions and 184 deletions
@@ -0,0 +1,50 @@
import { spawnSync } from 'node:child_process';
import fs from 'node:fs';
import { pathToFileURL } from 'node:url';
export function evaluateAudit(report, lock, now = Date.now()) {
if (report?.error || !report?.metadata?.vulnerabilities || !report?.vulnerabilities || !lock?.packages) {
return { accepted: [], failures: ['Missing or invalid audit/lock data'] };
}
const accepted = [], failures = [];
const allowedChain = new Set(['braces', 'micromatch', 'fast-glob', '@next/eslint-plugin-next', 'eslint-config-next']);
const devOnlyApprovedOrigin = (name, visited = new Set()) => {
const finding = report.vulnerabilities[name];
if (!allowedChain.has(name) || visited.has(name) || finding?.severity !== 'high' ||
!Array.isArray(finding.nodes) || !finding.nodes.length ||
finding.nodes.some(node => lock.packages[node]?.dev !== true || name === 'braces' && lock.packages[node]?.version !== '3.0.3') ||
!Array.isArray(finding.via) || !finding.via.length) return false;
const path = new Set(visited).add(name);
return finding.via.every(origin => typeof origin === 'string' ? devOnlyApprovedOrigin(origin, path) :
origin?.name === 'braces' && origin.dependency === 'braces' && origin.severity === 'high' && origin.url === 'https://github.com/advisories/GHSA-vfj7-8cjw-p6xm');
};
for (const [name, finding] of Object.entries(report.vulnerabilities)) {
if (!['info', 'low', 'moderate', 'high', 'critical'].includes(finding.severity)) {
failures.push(`${name}: invalid severity`);
} else if (['high', 'critical'].includes(finding.severity)) {
// Owner-approved on 17 October: no upstream fix; trusted lint patterns only, never production dependencies.
if (Number.isFinite(now) && now < Date.parse('2026-11-01T00:00:00Z') && devOnlyApprovedOrigin(name)) accepted.push(name);
else failures.push(`${name}: ${finding.severity}`);
}
}
return { accepted, failures };
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
try {
const result = spawnSync(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['audit', '--json', '--audit-level=high'], {
encoding: 'utf8', maxBuffer: 8 * 1024 * 1024, shell: process.platform === 'win32',
});
fs.mkdirSync('.artifacts', { recursive: true });
fs.writeFileSync('.artifacts/frontend-audit.json', result.stdout || '');
if (result.error || result.signal || ![0, 1].includes(result.status)) throw new Error('npm audit did not complete');
const report = JSON.parse(result.stdout);
const decision = evaluateAudit(report, JSON.parse(fs.readFileSync('package-lock.json', 'utf8')));
console.log(JSON.stringify({ report, ...decision,
temporaryException: decision.accepted.length ? 'GHSA-vfj7-8cjw-p6xm: dev-only; expires after 2026-10-31 UTC' : null }, null, 2));
process.exitCode = decision.failures.length ? 1 : 0;
} catch (error) {
console.error(error.message);
process.exitCode = 1;
}
}
@@ -0,0 +1,55 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { evaluateAudit } from './audit-dependencies.mjs';
const now = Date.parse('2026-10-17T18:00:00Z');
function fixture() {
return {
report: {
metadata: { vulnerabilities: { high: 2, critical: 0 } },
vulnerabilities: {
braces: { severity: 'high', nodes: ['node_modules/braces'], via: [{ name: 'braces', dependency: 'braces', severity: 'high', url: 'https://github.com/advisories/GHSA-vfj7-8cjw-p6xm' }] },
micromatch: { severity: 'high', nodes: ['node_modules/micromatch'], via: ['braces'] },
},
},
lock: { packages: { 'node_modules/braces': { dev: true, version: '3.0.3' }, 'node_modules/micromatch': { dev: true, version: '4.0.8' } } },
};
}
test('allows only the approved dev-only advisory and its linked findings before expiry', () => {
const { report, lock } = fixture();
assert.deepEqual(evaluateAudit(report, lock, now), { accepted: ['braces', 'micromatch'], failures: [] });
});
test('blocks the same advisory if any affected copy is a production dependency', () => {
const { report, lock } = fixture(); delete lock.packages['node_modules/braces'].dev;
assert.ok(evaluateAudit(report, lock, now).failures.length);
});
test('blocks any new advisory even inside the otherwise approved chain', () => {
const { report, lock } = fixture(); report.vulnerabilities.braces.via.push({ name: 'braces', url: 'https://github.com/advisories/UNKNOWN' });
assert.ok(evaluateAudit(report, lock, now).failures.length);
});
test('critical findings cannot use the high-only exception', () => {
const { report, lock } = fixture(); report.vulnerabilities.braces.severity = 'critical';
assert.ok(evaluateAudit(report, lock, now).failures.length);
});
test('a critical underlying advisory is rejected even if its aggregate severity is inconsistent', () => {
const { report, lock } = fixture(); report.vulnerabilities.braces.via[0].severity = 'critical';
assert.ok(evaluateAudit(report, lock, now).failures.length);
});
test('expires after 31 October UTC without an environment-variable bypass', () => {
const { report, lock } = fixture();
assert.ok(evaluateAudit(report, lock, Date.parse('2026-11-01T00:00:00Z')).failures.length);
});
test('missing nodes, missing lock entries and cyclic origins fail closed', () => {
for (const change of [x => x.report.vulnerabilities.braces.nodes = [], x => delete x.lock.packages['node_modules/braces'], x => x.report.vulnerabilities.braces.via = ['micromatch']]) {
const input = fixture(); change(input); assert.ok(evaluateAudit(input.report, input.lock, now).failures.length);
}
});
test('invalid reports and unknown severities fail closed', () => {
assert.ok(evaluateAudit({ error: { message: 'Registry unavailable' } }, {}, now).failures.length);
const { report, lock } = fixture(); report.vulnerabilities.braces.severity = 'unknown';
assert.ok(evaluateAudit(report, lock, now).failures.length);
});
test('non-blocking moderate findings retain the existing audit threshold', () => {
const report = { metadata: { vulnerabilities: { moderate: 1 } }, vulnerabilities: { tool: { severity: 'moderate', via: [] } } };
assert.deepEqual(evaluateAudit(report, { packages: {} }, now), { accepted: [], failures: [] });
});