fix: mitigate npm dependency advisories
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
||||
import { createRequire } from 'node:module';
|
||||
import { extname, join, resolve } from 'node:path';
|
||||
|
||||
const workspaceRoot = resolve(import.meta.dirname, '..', '..');
|
||||
const rootLock = JSON.parse(readFileSync(join(workspaceRoot, 'package-lock.json'), 'utf8'));
|
||||
const apiLock = JSON.parse(readFileSync(join(workspaceRoot, 'api', 'package-lock.json'), 'utf8'));
|
||||
|
||||
assertVersionAtLeast(rootLock.packages['node_modules/postcss']?.version, [8, 5, 18], 'postcss');
|
||||
assertEqual(rootLock.packages['node_modules/react-router']?.version, '7.18.1', 'react-router');
|
||||
assertEqual(apiLock.packages['node_modules/brace-expansion-safe']?.version, '5.0.8', 'brace-expansion-safe');
|
||||
assertEqual(
|
||||
apiLock.packages['node_modules/brace-expansion']?.resolved,
|
||||
'vendor/brace-expansion-compat',
|
||||
'brace-expansion compatibility adapter',
|
||||
);
|
||||
|
||||
const forbiddenRscPatterns = [
|
||||
/\bunstable_RSC\w*/u,
|
||||
/\bRSCRouterConfig\b/u,
|
||||
/\bRSCStaticRouter\b/u,
|
||||
/\bcreateCallServer\b/u,
|
||||
/react-router\/dom\/server/u,
|
||||
];
|
||||
for (const filePath of sourceFiles(join(workspaceRoot, 'src'))) {
|
||||
const source = readFileSync(filePath, 'utf8');
|
||||
for (const pattern of forbiddenRscPatterns) {
|
||||
if (pattern.test(source)) {
|
||||
throw new Error(`React Router RSC mitigation violated by ${filePath}: ${pattern}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const apiRequire = createRequire(join(workspaceRoot, 'api', 'package.json'));
|
||||
const expand = apiRequire('brace-expansion');
|
||||
if (typeof expand !== 'function' || expand.EXPANSION_MAX_LENGTH !== 4_000_000) {
|
||||
throw new Error('brace-expansion compatibility adapter is not using the bounded 5.0.8 implementation');
|
||||
}
|
||||
assertEqual(expand('{a,b}{1,2}').join(','), 'a1,a2,b1,b2', 'brace-expansion legacy API');
|
||||
|
||||
for (const relativePath of [
|
||||
'node_modules/archiver-utils/node_modules/minimatch',
|
||||
'node_modules/readdir-glob/node_modules/minimatch',
|
||||
'node_modules/rimraf/node_modules/minimatch',
|
||||
]) {
|
||||
const loaded = apiRequire(join(workspaceRoot, 'api', relativePath));
|
||||
const match = typeof loaded === 'function' ? loaded : loaded.minimatch;
|
||||
if (typeof match !== 'function' || !match('file-a.xlsx', 'file-{a,b}.xlsx')) {
|
||||
throw new Error(`Legacy minimatch compatibility failed for ${relativePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Dependency mitigations verified: PostCSS patched, React Router RSC unused, brace expansion bounded and compatible.');
|
||||
|
||||
function sourceFiles(directory) {
|
||||
return readdirSync(directory).flatMap((name) => {
|
||||
const path = join(directory, name);
|
||||
if (statSync(path).isDirectory()) return sourceFiles(path);
|
||||
return ['.js', '.jsx', '.ts', '.tsx'].includes(extname(path)) ? [path] : [];
|
||||
});
|
||||
}
|
||||
|
||||
function assertVersionAtLeast(actual, minimum, label) {
|
||||
if (!actual) throw new Error(`${label} is missing from package-lock.json`);
|
||||
const parts = actual.split('.').map((part) => Number(part.replace(/\D.*$/u, '')));
|
||||
if (minimum.some((value, index) => parts[index] < value && minimum.slice(0, index).every((item, i) => parts[i] === item))) {
|
||||
throw new Error(`${label} ${actual} is older than ${minimum.join('.')}`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertEqual(actual, expected, label) {
|
||||
if (actual !== expected) throw new Error(`${label}: expected ${expected}, received ${actual ?? 'missing'}`);
|
||||
}
|
||||
Reference in New Issue
Block a user