mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 12:15:57 +00:00
fix(hardening): count executable sync fs call sites
This commit is contained in:
@@ -31,9 +31,9 @@ Baseline captured: `2026-02-12`.
|
||||
|
||||
| Metric | Baseline |
|
||||
|---|---:|
|
||||
| Sync fs occurrences (all) | 841 |
|
||||
| Sync fs occurrences (all) | 835 |
|
||||
| Sync fs files affected (all) | 100 |
|
||||
| Sync fs occurrences (runtime hotpaths) | 730 |
|
||||
| Sync fs occurrences (runtime hotpaths) | 724 |
|
||||
| Sync fs files affected (runtime hotpaths) | 89 |
|
||||
| Legacy shim markers | 131 |
|
||||
| Legacy shim files affected | 56 |
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"scope": "src/**/*.{ts,tsx,js,jsx,mjs,cjs}",
|
||||
"syncFs": {
|
||||
"totalOccurrences": 841,
|
||||
"totalOccurrences": 835,
|
||||
"filesAffected": 100,
|
||||
"hotpathOccurrences": 730,
|
||||
"hotpathOccurrences": 724,
|
||||
"hotpathFilesAffected": 89,
|
||||
"topHotpathFiles": [
|
||||
{
|
||||
@@ -44,24 +44,6 @@
|
||||
],
|
||||
"markers": []
|
||||
},
|
||||
{
|
||||
"file": "src/utils/claude-dir-installer.ts",
|
||||
"count": 23,
|
||||
"calls": [
|
||||
"copyFileSync",
|
||||
"cpSync",
|
||||
"existsSync",
|
||||
"lstatSync",
|
||||
"mkdirSync",
|
||||
"readdirSync",
|
||||
"renameSync",
|
||||
"rmSync",
|
||||
"statSync",
|
||||
"unlinkSync",
|
||||
"writeFileSync"
|
||||
],
|
||||
"markers": []
|
||||
},
|
||||
{
|
||||
"file": "src/utils/shell-completion.ts",
|
||||
"count": 23,
|
||||
@@ -89,6 +71,24 @@
|
||||
],
|
||||
"markers": []
|
||||
},
|
||||
{
|
||||
"file": "src/utils/claude-dir-installer.ts",
|
||||
"count": 21,
|
||||
"calls": [
|
||||
"copyFileSync",
|
||||
"cpSync",
|
||||
"existsSync",
|
||||
"lstatSync",
|
||||
"mkdirSync",
|
||||
"readdirSync",
|
||||
"renameSync",
|
||||
"rmSync",
|
||||
"statSync",
|
||||
"unlinkSync",
|
||||
"writeFileSync"
|
||||
],
|
||||
"markers": []
|
||||
},
|
||||
{
|
||||
"file": "src/cliproxy/binary/version-cache.ts",
|
||||
"count": 20,
|
||||
@@ -218,24 +218,6 @@
|
||||
],
|
||||
"markers": []
|
||||
},
|
||||
{
|
||||
"file": "src/utils/claude-dir-installer.ts",
|
||||
"count": 23,
|
||||
"calls": [
|
||||
"copyFileSync",
|
||||
"cpSync",
|
||||
"existsSync",
|
||||
"lstatSync",
|
||||
"mkdirSync",
|
||||
"readdirSync",
|
||||
"renameSync",
|
||||
"rmSync",
|
||||
"statSync",
|
||||
"unlinkSync",
|
||||
"writeFileSync"
|
||||
],
|
||||
"markers": []
|
||||
},
|
||||
{
|
||||
"file": "src/utils/shell-completion.ts",
|
||||
"count": 23,
|
||||
@@ -263,6 +245,24 @@
|
||||
],
|
||||
"markers": []
|
||||
},
|
||||
{
|
||||
"file": "src/utils/claude-dir-installer.ts",
|
||||
"count": 21,
|
||||
"calls": [
|
||||
"copyFileSync",
|
||||
"cpSync",
|
||||
"existsSync",
|
||||
"lstatSync",
|
||||
"mkdirSync",
|
||||
"readdirSync",
|
||||
"renameSync",
|
||||
"rmSync",
|
||||
"statSync",
|
||||
"unlinkSync",
|
||||
"writeFileSync"
|
||||
],
|
||||
"markers": []
|
||||
},
|
||||
{
|
||||
"file": "src/cliproxy/binary/version-cache.ts",
|
||||
"count": 20,
|
||||
|
||||
@@ -6,9 +6,9 @@ Scope: `src/**/*.{ts,tsx,js,jsx,mjs,cjs}`
|
||||
|
||||
| Metric | Value |
|
||||
|---|---:|
|
||||
| Sync fs occurrences (all) | 841 |
|
||||
| Sync fs occurrences (all) | 835 |
|
||||
| Sync fs files affected (all) | 100 |
|
||||
| Sync fs occurrences (runtime hotpaths) | 730 |
|
||||
| Sync fs occurrences (runtime hotpaths) | 724 |
|
||||
| Sync fs files affected (runtime hotpaths) | 89 |
|
||||
| Legacy shim markers | 131 |
|
||||
| Legacy shim files affected | 56 |
|
||||
@@ -19,9 +19,9 @@ Scope: `src/**/*.{ts,tsx,js,jsx,mjs,cjs}`
|
||||
|---|---:|---|
|
||||
| `src/management/shared-manager.ts` | 60 | copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, readlinkSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync |
|
||||
| `src/utils/claude-symlink-manager.ts` | 27 | copyFileSync, existsSync, lstatSync, mkdirSync, readdirSync, readlinkSync, renameSync, rmSync, statSync, symlinkSync, unlinkSync |
|
||||
| `src/utils/claude-dir-installer.ts` | 23 | copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync |
|
||||
| `src/utils/shell-completion.ts` | 23 | appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync, statSync |
|
||||
| `src/web-server/routes/settings-routes.ts` | 23 | copyFileSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync |
|
||||
| `src/utils/claude-dir-installer.ts` | 21 | copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync |
|
||||
| `src/cliproxy/binary/version-cache.ts` | 20 | existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync |
|
||||
| `src/management/recovery-manager.ts` | 20 | copyFileSync, existsSync, mkdirSync, renameSync, writeFileSync |
|
||||
| `src/web-server/routes/cliproxy-stats-routes.ts` | 20 | closeSync, existsSync, fstatSync, mkdirSync, openSync, readdirSync, readFileSync, readSync, renameSync, statSync, writeFileSync |
|
||||
|
||||
+143
-15
@@ -60,9 +60,10 @@ const SYNC_CALL_NAMES = [
|
||||
'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 SYNC_CALL_CAPTURE_REGEX = new RegExp(
|
||||
`(?:\\bfs(?:\\s*\\?\\.)?\\s*\\.\\s*|(?<![\\w$.]))(${SYNC_CALL_NAMES.join('|')})\\s*\\(`,
|
||||
'g'
|
||||
);
|
||||
const LEGACY_MARKER_REGEX =
|
||||
/(?:\blegacy\b|\bshim\b|backward compatibility|backwards compatibility|compatibility layer|deprecated.*re-export|re-export.*compatibility)/i;
|
||||
|
||||
@@ -123,6 +124,142 @@ function summarize(items, limit = 10) {
|
||||
}));
|
||||
}
|
||||
|
||||
function stripComments(sourceText) {
|
||||
let output = '';
|
||||
let index = 0;
|
||||
let inLineComment = false;
|
||||
let inBlockComment = false;
|
||||
let inSingleQuote = false;
|
||||
let inDoubleQuote = false;
|
||||
let inTemplateLiteral = false;
|
||||
|
||||
while (index < sourceText.length) {
|
||||
const current = sourceText[index];
|
||||
const next = sourceText[index + 1];
|
||||
|
||||
if (inLineComment) {
|
||||
if (current === '\n' || current === '\r') {
|
||||
inLineComment = false;
|
||||
output += current;
|
||||
} else {
|
||||
output += ' ';
|
||||
}
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inBlockComment) {
|
||||
if (current === '*' && next === '/') {
|
||||
output += ' ';
|
||||
index += 2;
|
||||
inBlockComment = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
output += current === '\n' || current === '\r' ? current : ' ';
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inSingleQuote) {
|
||||
output += current;
|
||||
if (current === '\\') {
|
||||
output += next ?? '';
|
||||
index += 2;
|
||||
continue;
|
||||
}
|
||||
if (current === "'") {
|
||||
inSingleQuote = false;
|
||||
}
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inDoubleQuote) {
|
||||
output += current;
|
||||
if (current === '\\') {
|
||||
output += next ?? '';
|
||||
index += 2;
|
||||
continue;
|
||||
}
|
||||
if (current === '"') {
|
||||
inDoubleQuote = false;
|
||||
}
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inTemplateLiteral) {
|
||||
output += current;
|
||||
if (current === '\\') {
|
||||
output += next ?? '';
|
||||
index += 2;
|
||||
continue;
|
||||
}
|
||||
if (current === '`') {
|
||||
inTemplateLiteral = false;
|
||||
}
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current === '/' && next === '/') {
|
||||
output += ' ';
|
||||
index += 2;
|
||||
inLineComment = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current === '/' && next === '*') {
|
||||
output += ' ';
|
||||
index += 2;
|
||||
inBlockComment = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current === "'") {
|
||||
inSingleQuote = true;
|
||||
output += current;
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current === '"') {
|
||||
inDoubleQuote = true;
|
||||
output += current;
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current === '`') {
|
||||
inTemplateLiteral = true;
|
||||
output += current;
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
output += current;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function collectSyncCallSites(sourceText) {
|
||||
const sanitizedSource = stripComments(sourceText);
|
||||
const captureRegex = new RegExp(SYNC_CALL_CAPTURE_REGEX.source, SYNC_CALL_CAPTURE_REGEX.flags);
|
||||
const calls = [];
|
||||
|
||||
for (const match of sanitizedSource.matchAll(captureRegex)) {
|
||||
calls.push(match[1]);
|
||||
}
|
||||
|
||||
return {
|
||||
count: calls.length,
|
||||
calls,
|
||||
};
|
||||
}
|
||||
|
||||
function buildReport() {
|
||||
const files = walkFiles(SRC_DIR);
|
||||
const syncEntries = [];
|
||||
@@ -130,22 +267,13 @@ function buildReport() {
|
||||
|
||||
for (const fullPath of files) {
|
||||
const file = relativePath(fullPath);
|
||||
const lines = fs.readFileSync(fullPath, 'utf8').split(/\r?\n/);
|
||||
|
||||
let syncCount = 0;
|
||||
const syncCalls = [];
|
||||
const sourceText = fs.readFileSync(fullPath, 'utf8');
|
||||
const lines = sourceText.split(/\r?\n/);
|
||||
const { count: syncCount, calls: syncCalls } = collectSyncCallSites(sourceText);
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user