mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-26 18:35:05 +00:00
fix(memory): classify directory traversal failures
This commit is contained in:
1 parent
90ef62cb1d
commit
8321021c54
2 files changed
+58
-4
No files matched your search
@@ -443,6 +443,12 @@ function publicMemoryFileError(error) {
|
||||
};
|
||||
}
|
||||
|
||||
function incompleteMemoryLookupError() {
|
||||
const error = new Error('Memory lookup is incomplete. Inspect the authorized vault before retrying.');
|
||||
error.code = 'ECC_MEMORY_INCOMPLETE';
|
||||
return error;
|
||||
}
|
||||
|
||||
function readMemoryFiles(options = {}) {
|
||||
const roots = options.roots || resolveVaultRoots(options);
|
||||
const scopes = normalizeScopes(options.scopes || DEFAULT_RECALL_SCOPES);
|
||||
@@ -461,7 +467,13 @@ function readMemoryFiles(options = {}) {
|
||||
break;
|
||||
}
|
||||
const root = assertMemoryRootSafe(roots, scope);
|
||||
const walked = walkMemoryRoot(root, MAX_FILES - visitedCount);
|
||||
let walked;
|
||||
try {
|
||||
walked = walkMemoryRoot(root, MAX_FILES - visitedCount);
|
||||
} catch {
|
||||
// Directory open/read/close failures cannot establish a complete lookup.
|
||||
throw incompleteMemoryLookupError();
|
||||
}
|
||||
visitedCount += walked.visitedCount;
|
||||
truncated = truncated || walked.truncated;
|
||||
skippedSymlinkCount += walked.skippedSymlinkCount;
|
||||
@@ -660,9 +672,7 @@ function readMemoryById(id, options = {}) {
|
||||
: null;
|
||||
const loaded = readMemoryFiles(options);
|
||||
if (loaded.truncated || loaded.invalidFileCount > 0) {
|
||||
const error = new Error('Memory lookup is incomplete. Inspect the authorized vault before retrying.');
|
||||
error.code = 'ECC_MEMORY_INCOMPLETE';
|
||||
throw error;
|
||||
throw incompleteMemoryLookupError();
|
||||
}
|
||||
const matches = loaded.entries
|
||||
.filter(entry => entry.memory.id === memoryId)
|
||||
|
||||
@@ -75,6 +75,50 @@ async function main() {
|
||||
fs.openSync = open;
|
||||
}
|
||||
});
|
||||
function failTraversal(roots, phase, fn) {
|
||||
const open = fs.opendirSync;
|
||||
let closed = false;
|
||||
fs.opendirSync = (directory, ...args) => {
|
||||
if (directory !== roots.project) return open(directory, ...args);
|
||||
const fail = () => {
|
||||
const error = new Error('Synthetic private directory detail.');
|
||||
error.code = 'EACCES';
|
||||
throw error;
|
||||
};
|
||||
if (phase === 'open') return fail();
|
||||
const handle = open(directory, ...args);
|
||||
return {
|
||||
readSync: () => phase === 'read' ? fail() : handle.readSync(),
|
||||
closeSync: () => {
|
||||
handle.closeSync(); closed = true;
|
||||
if (phase === 'close') fail();
|
||||
},
|
||||
};
|
||||
};
|
||||
try { fn(); } finally {
|
||||
fs.opendirSync = open;
|
||||
if (phase !== 'open') assert.equal(closed, true);
|
||||
}
|
||||
}
|
||||
for (const phase of ['open', 'read', 'close']) {
|
||||
check(`direct read classifies directory ${phase} failure`, ({ roots, read }) => {
|
||||
failTraversal(roots, phase, () => {
|
||||
assert.throws(read, error => error.code === 'ECC_MEMORY_INCOMPLETE'
|
||||
&& !error.message.includes('Synthetic private directory detail.'));
|
||||
});
|
||||
});
|
||||
check(`MCP read classifies directory ${phase} failure`, ({ roots, mcp }) => {
|
||||
failTraversal(roots, phase, () => {
|
||||
const result = mcp(); assert.equal(result.isError, true);
|
||||
const error = JSON.parse(result.content[0].text).error;
|
||||
assert.equal(error.code, 'MEMORY_READ_INCOMPLETE');
|
||||
assert.equal(error.message.includes('Synthetic private directory detail.'), false);
|
||||
});
|
||||
});
|
||||
}
|
||||
check('unreadable traversal cannot establish missing memory', ({ roots, read }) => {
|
||||
failTraversal(roots, 'open', () => incomplete(() => read('mem_synthetic_missing')));
|
||||
});
|
||||
check('MCP incomplete lookup has a distinct bounded error', ({ mcp, truncate }) => {
|
||||
truncate(); const result = mcp(); assert.equal(result.isError, true);
|
||||
const error = JSON.parse(result.content[0].text).error;
|
||||
|
||||
Reference in new issue
Block a user