mirror of
https://github.com/tiennm99/ccs.git
synced 2026-08-24 10:26:29 +00:00
chore(hardening): add debt inventory and async io kickoff
This commit is contained in:
@@ -0,0 +1,285 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ROOT_DIR = path.resolve(__dirname, '..');
|
||||
const SRC_DIR = path.join(ROOT_DIR, 'src');
|
||||
const REPORT_DIR = path.join(ROOT_DIR, 'docs', 'reports');
|
||||
const JSON_REPORT_PATH = path.join(REPORT_DIR, 'hardening-inventory.json');
|
||||
const MD_REPORT_PATH = path.join(REPORT_DIR, 'hardening-inventory.md');
|
||||
|
||||
const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']);
|
||||
const HOTPATH_PATTERNS = [
|
||||
/^src\/web-server\//,
|
||||
/^src\/commands\//,
|
||||
/^src\/cliproxy\//,
|
||||
/^src\/management\//,
|
||||
/^src\/auth\//,
|
||||
/^src\/delegation\//,
|
||||
/^src\/utils\//,
|
||||
/^src\/ccs\.ts$/,
|
||||
];
|
||||
|
||||
const SYNC_CALL_NAMES = [
|
||||
'accessSync',
|
||||
'appendFileSync',
|
||||
'chmodSync',
|
||||
'chownSync',
|
||||
'closeSync',
|
||||
'copyFileSync',
|
||||
'cpSync',
|
||||
'existsSync',
|
||||
'fstatSync',
|
||||
'fsyncSync',
|
||||
'ftruncateSync',
|
||||
'futimesSync',
|
||||
'lchmodSync',
|
||||
'lchownSync',
|
||||
'linkSync',
|
||||
'lstatSync',
|
||||
'mkdirSync',
|
||||
'mkdtempSync',
|
||||
'openSync',
|
||||
'opendirSync',
|
||||
'readFileSync',
|
||||
'readdirSync',
|
||||
'readlinkSync',
|
||||
'readSync',
|
||||
'readvSync',
|
||||
'realpathSync',
|
||||
'renameSync',
|
||||
'rmSync',
|
||||
'rmdirSync',
|
||||
'statSync',
|
||||
'symlinkSync',
|
||||
'truncateSync',
|
||||
'unlinkSync',
|
||||
'utimesSync',
|
||||
'writeFileSync',
|
||||
'writeSync',
|
||||
'writevSync',
|
||||
];
|
||||
|
||||
const SYNC_CALL_LINE_REGEX = new RegExp(`\\b(?:fs\\.)?(?:${SYNC_CALL_NAMES.join('|')})\\b`);
|
||||
const SYNC_CALL_CAPTURE_REGEX = new RegExp(`\\b(?:fs\\.)?(${SYNC_CALL_NAMES.join('|')})\\b`, 'g');
|
||||
const LEGACY_MARKER_REGEX =
|
||||
/(?:\blegacy\b|\bshim\b|backward compatibility|backwards compatibility|compatibility layer|deprecated.*re-export|re-export.*compatibility)/i;
|
||||
|
||||
function toPosixPath(filePath) {
|
||||
return filePath.split(path.sep).join('/');
|
||||
}
|
||||
|
||||
function relativePath(filePath) {
|
||||
return toPosixPath(path.relative(ROOT_DIR, filePath));
|
||||
}
|
||||
|
||||
function isSourceFile(filePath) {
|
||||
return SOURCE_EXTENSIONS.has(path.extname(filePath));
|
||||
}
|
||||
|
||||
function isHotpath(filePath) {
|
||||
return HOTPATH_PATTERNS.some((pattern) => pattern.test(filePath));
|
||||
}
|
||||
|
||||
function walkFiles(dirPath) {
|
||||
const output = [];
|
||||
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dirPath, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
output.push(...walkFiles(fullPath));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.isFile() && isSourceFile(fullPath)) {
|
||||
output.push(fullPath);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function uniqueSorted(values) {
|
||||
return Array.from(new Set(values)).sort((a, b) => a.localeCompare(b));
|
||||
}
|
||||
|
||||
function sortByCountDesc(items) {
|
||||
return [...items].sort((a, b) => {
|
||||
if (b.count !== a.count) return b.count - a.count;
|
||||
return a.file.localeCompare(b.file);
|
||||
});
|
||||
}
|
||||
|
||||
function summarize(items, limit = 10) {
|
||||
return sortByCountDesc(items)
|
||||
.slice(0, limit)
|
||||
.map((item) => ({
|
||||
file: item.file,
|
||||
count: item.count,
|
||||
calls: uniqueSorted(item.calls || []),
|
||||
markers: uniqueSorted(item.markers || []),
|
||||
}));
|
||||
}
|
||||
|
||||
function buildReport() {
|
||||
const files = walkFiles(SRC_DIR);
|
||||
const syncEntries = [];
|
||||
const legacyEntries = [];
|
||||
|
||||
for (const fullPath of files) {
|
||||
const file = relativePath(fullPath);
|
||||
const lines = fs.readFileSync(fullPath, 'utf8').split(/\r?\n/);
|
||||
|
||||
let syncCount = 0;
|
||||
const syncCalls = [];
|
||||
let legacyCount = 0;
|
||||
const legacyMarkers = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (SYNC_CALL_LINE_REGEX.test(line)) {
|
||||
const matches = [...line.matchAll(SYNC_CALL_CAPTURE_REGEX)];
|
||||
syncCount += matches.length;
|
||||
for (const match of matches) {
|
||||
syncCalls.push(match[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (LEGACY_MARKER_REGEX.test(line)) {
|
||||
legacyCount += 1;
|
||||
const normalized = line.trim();
|
||||
if (normalized.length > 0) {
|
||||
legacyMarkers.push(normalized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (syncCount > 0) {
|
||||
syncEntries.push({
|
||||
file,
|
||||
count: syncCount,
|
||||
calls: syncCalls,
|
||||
hotpath: isHotpath(file),
|
||||
});
|
||||
}
|
||||
|
||||
if (legacyCount > 0) {
|
||||
legacyEntries.push({
|
||||
file,
|
||||
count: legacyCount,
|
||||
markers: legacyMarkers,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const syncHotpathEntries = syncEntries.filter((entry) => entry.hotpath);
|
||||
const totalSyncCount = syncEntries.reduce((acc, entry) => acc + entry.count, 0);
|
||||
const totalSyncHotpathCount = syncHotpathEntries.reduce((acc, entry) => acc + entry.count, 0);
|
||||
const totalLegacyMarkers = legacyEntries.reduce((acc, entry) => acc + entry.count, 0);
|
||||
|
||||
return {
|
||||
scope: 'src/**/*.{ts,tsx,js,jsx,mjs,cjs}',
|
||||
syncFs: {
|
||||
totalOccurrences: totalSyncCount,
|
||||
filesAffected: syncEntries.length,
|
||||
hotpathOccurrences: totalSyncHotpathCount,
|
||||
hotpathFilesAffected: syncHotpathEntries.length,
|
||||
topHotpathFiles: summarize(syncHotpathEntries),
|
||||
topFilesOverall: summarize(syncEntries),
|
||||
},
|
||||
legacyShim: {
|
||||
totalMarkers: totalLegacyMarkers,
|
||||
filesAffected: legacyEntries.length,
|
||||
topFiles: summarize(legacyEntries),
|
||||
explicitShimFiles: uniqueSorted(
|
||||
legacyEntries
|
||||
.map((entry) => entry.file)
|
||||
.filter((file) => /shim|re-export|compat/i.test(path.basename(file)))
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function renderMarkdown(report) {
|
||||
const lines = [];
|
||||
|
||||
lines.push('# Hardening Inventory Report');
|
||||
lines.push('');
|
||||
lines.push(`Scope: \`${report.scope}\``);
|
||||
lines.push('');
|
||||
lines.push('## Summary');
|
||||
lines.push('');
|
||||
lines.push('| Metric | Value |');
|
||||
lines.push('|---|---:|');
|
||||
lines.push(`| Sync fs occurrences (all) | ${report.syncFs.totalOccurrences} |`);
|
||||
lines.push(`| Sync fs files affected (all) | ${report.syncFs.filesAffected} |`);
|
||||
lines.push(`| Sync fs occurrences (runtime hotpaths) | ${report.syncFs.hotpathOccurrences} |`);
|
||||
lines.push(`| Sync fs files affected (runtime hotpaths) | ${report.syncFs.hotpathFilesAffected} |`);
|
||||
lines.push(`| Legacy shim markers | ${report.legacyShim.totalMarkers} |`);
|
||||
lines.push(`| Legacy shim files affected | ${report.legacyShim.filesAffected} |`);
|
||||
lines.push('');
|
||||
|
||||
lines.push('## Top Runtime Hotpath Sync fs Files');
|
||||
lines.push('');
|
||||
lines.push('| File | Sync Calls | API Names |');
|
||||
lines.push('|---|---:|---|');
|
||||
|
||||
for (const item of report.syncFs.topHotpathFiles) {
|
||||
lines.push(`| \`${item.file}\` | ${item.count} | ${item.calls.join(', ')} |`);
|
||||
}
|
||||
|
||||
if (report.syncFs.topHotpathFiles.length === 0) {
|
||||
lines.push('| _none_ | 0 | - |');
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
lines.push('## Top Legacy Shim Marker Files');
|
||||
lines.push('');
|
||||
lines.push('| File | Marker Count |');
|
||||
lines.push('|---|---:|');
|
||||
|
||||
for (const item of report.legacyShim.topFiles) {
|
||||
lines.push(`| \`${item.file}\` | ${item.count} |`);
|
||||
}
|
||||
|
||||
if (report.legacyShim.topFiles.length === 0) {
|
||||
lines.push('| _none_ | 0 |');
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
lines.push('## Explicit Shim/Re-export Files');
|
||||
lines.push('');
|
||||
for (const file of report.legacyShim.explicitShimFiles) {
|
||||
lines.push(`- \`${file}\``);
|
||||
}
|
||||
if (report.legacyShim.explicitShimFiles.length === 0) {
|
||||
lines.push('- _none_');
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function main() {
|
||||
const report = buildReport();
|
||||
|
||||
fs.mkdirSync(REPORT_DIR, { recursive: true });
|
||||
fs.writeFileSync(JSON_REPORT_PATH, JSON.stringify(report, null, 2) + '\n', 'utf8');
|
||||
fs.writeFileSync(MD_REPORT_PATH, renderMarkdown(report), 'utf8');
|
||||
|
||||
const relJson = relativePath(JSON_REPORT_PATH);
|
||||
const relMd = relativePath(MD_REPORT_PATH);
|
||||
|
||||
console.log(`[hardening-inventory] generatedAt=${new Date().toISOString()}`);
|
||||
console.log(
|
||||
`[hardening-inventory] sync-fs total=${report.syncFs.totalOccurrences}, hotpath=${report.syncFs.hotpathOccurrences}`
|
||||
);
|
||||
console.log(
|
||||
`[hardening-inventory] legacy markers total=${report.legacyShim.totalMarkers}, files=${report.legacyShim.filesAffected}`
|
||||
);
|
||||
console.log(`[hardening-inventory] wrote ${relJson}`);
|
||||
console.log(`[hardening-inventory] wrote ${relMd}`);
|
||||
}
|
||||
|
||||
main();
|
||||
Reference in New Issue
Block a user