mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-31 04:45:18 +00:00
fix(ck): reject only parent-traversal segments in the forget guard
Signed-off-by: Wen <jwcastillo@gmail.com>
This commit is contained in:
2 files changed
+33
-2
No files matched your search
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
import { rmSync } from 'fs';
|
||||
import { isAbsolute, relative, resolve } from 'path';
|
||||
import { isAbsolute, relative, resolve, sep } from 'path';
|
||||
import { resolveContext, readProjects, writeProjects, CONTEXTS_DIR } from './shared.mjs';
|
||||
|
||||
const arg = process.argv[2];
|
||||
@@ -30,7 +30,7 @@ const { name, contextDir, projectPath } = resolved;
|
||||
// Remove context directory
|
||||
const contextDirPath = resolve(CONTEXTS_DIR, contextDir);
|
||||
const rel = relative(CONTEXTS_DIR, contextDirPath);
|
||||
if (!rel || rel.startsWith('..') || isAbsolute(rel)) {
|
||||
if (!rel || rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
|
||||
console.log(`ck: refusing to remove '${contextDirPath}' — it is not a project directory inside ${CONTEXTS_DIR}.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -76,6 +76,37 @@ test('forget refuses to remove the contexts root for a legacy empty contextDir',
|
||||
assert.ok(fs.existsSync(path.join(contextsDir(home), 'alpha', 'context.json')), 'alpha context was removed');
|
||||
});
|
||||
|
||||
test('forget removes a legacy contextDir whose name starts with dots', home => {
|
||||
init(home, 'alpha', path.join(home, 'projA'));
|
||||
const projectsFile = path.join(home, '.claude', 'ck', 'projects.json');
|
||||
const projects = JSON.parse(fs.readFileSync(projectsFile, 'utf8'));
|
||||
projects[path.join(home, 'projB')] = { name: 'legacy', contextDir: '..archive', lastUpdated: '2026-01-01' };
|
||||
fs.writeFileSync(projectsFile, JSON.stringify(projects));
|
||||
const targetDir = path.join(contextsDir(home), '..archive');
|
||||
fs.mkdirSync(targetDir);
|
||||
fs.writeFileSync(path.join(targetDir, 'context.json'), JSON.stringify({ version: 2, sessions: [] }));
|
||||
|
||||
const result = run(home, 'forget.mjs', ['legacy']);
|
||||
assert.strictEqual(result.status, 0, result.stdout + result.stderr);
|
||||
assert.ok(!fs.existsSync(targetDir), '..archive directory was not removed');
|
||||
assert.ok(fs.existsSync(path.join(contextsDir(home), 'alpha', 'context.json')), 'alpha context was removed');
|
||||
});
|
||||
|
||||
test('forget refuses a legacy contextDir that escapes the contexts root', home => {
|
||||
init(home, 'alpha', path.join(home, 'projA'));
|
||||
const projectsFile = path.join(home, '.claude', 'ck', 'projects.json');
|
||||
const projects = JSON.parse(fs.readFileSync(projectsFile, 'utf8'));
|
||||
projects[path.join(home, 'projB')] = { name: 'legacy', contextDir: '../outside', lastUpdated: '2026-01-01' };
|
||||
fs.writeFileSync(projectsFile, JSON.stringify(projects));
|
||||
const outside = path.join(home, '.claude', 'ck', 'outside');
|
||||
fs.mkdirSync(outside);
|
||||
fs.writeFileSync(path.join(outside, 'context.json'), JSON.stringify({ version: 2, sessions: [] }));
|
||||
|
||||
const result = run(home, 'forget.mjs', ['legacy']);
|
||||
assert.strictEqual(result.status, 1, result.stdout + result.stderr);
|
||||
assert.ok(fs.existsSync(outside), 'directory outside the contexts root was removed');
|
||||
});
|
||||
|
||||
console.log(`\nPassed: ${passed}`);
|
||||
console.log(`Failed: ${failed}`);
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
Reference in new issue
Block a user