mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-17 06:14:30 +00:00
fix: reject case-variant symlinked file paths (#1629)
* fix: reject case-variant symlinked file paths * fix: validate requested case-variant symlink paths
This commit is contained in:
1 parent
53fe7e1e8d
commit
1ee7cac555
2 files changed
+117
-5
No files matched your search
@@ -99,6 +99,82 @@ describe('validateFilePath', () => {
|
||||
expect(result.readonly).toBe(false);
|
||||
});
|
||||
|
||||
test('rejects macOS case-variant paths through symlinked segments', () => {
|
||||
if (process.platform === 'win32') {
|
||||
return;
|
||||
}
|
||||
|
||||
const platformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
|
||||
Object.defineProperty(process, 'platform', { value: 'darwin' });
|
||||
|
||||
try {
|
||||
const ccsDir = path.join(tempDir, '.ccs');
|
||||
const caseVariantCcsDir = path.join(tempDir, '.CCS');
|
||||
const sharedDir = path.join(ccsDir, 'shared');
|
||||
const outsideCommandsDir = path.join(tempDir, '.claude', 'commands');
|
||||
const linkedCommandsDir = path.join(sharedDir, 'commands');
|
||||
|
||||
fs.mkdirSync(sharedDir, { recursive: true });
|
||||
fs.mkdirSync(outsideCommandsDir, { recursive: true });
|
||||
try {
|
||||
fs.symlinkSync(ccsDir, caseVariantCcsDir, 'dir');
|
||||
} catch (error) {
|
||||
const nodeError = error as NodeJS.ErrnoException;
|
||||
if (nodeError.code !== 'EEXIST') {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
fs.symlinkSync(outsideCommandsDir, linkedCommandsDir, 'dir');
|
||||
|
||||
const result = validateFilePath(
|
||||
path.join(caseVariantCcsDir, 'shared', 'commands', 'pwned.md')
|
||||
);
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
expect(result.readonly).toBe(false);
|
||||
} finally {
|
||||
if (platformDescriptor) {
|
||||
Object.defineProperty(process, 'platform', platformDescriptor);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('rejects macOS case-variant CCS directory symlinks', () => {
|
||||
if (process.platform === 'win32') {
|
||||
return;
|
||||
}
|
||||
|
||||
const platformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform');
|
||||
Object.defineProperty(process, 'platform', { value: 'darwin' });
|
||||
|
||||
try {
|
||||
const ccsDir = path.join(tempDir, '.ccs');
|
||||
const caseVariantCcsDir = path.join(tempDir, '.CCS');
|
||||
const outsideDir = path.join(tempDir, 'outside');
|
||||
|
||||
fs.mkdirSync(ccsDir, { recursive: true });
|
||||
fs.mkdirSync(outsideDir, { recursive: true });
|
||||
try {
|
||||
fs.symlinkSync(outsideDir, caseVariantCcsDir, 'dir');
|
||||
} catch (error) {
|
||||
const nodeError = error as NodeJS.ErrnoException;
|
||||
if (nodeError.code === 'EEXIST') {
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
const result = validateFilePath(path.join(caseVariantCcsDir, 'pwned.md'));
|
||||
|
||||
expect(result.valid).toBe(false);
|
||||
expect(result.readonly).toBe(false);
|
||||
} finally {
|
||||
if (platformDescriptor) {
|
||||
Object.defineProperty(process, 'platform', platformDescriptor);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('rejects symlinked Claude settings path', () => {
|
||||
if (process.platform === 'win32') {
|
||||
return;
|
||||
|
||||
Reference in new issue
Block a user