()
| 52 | } |
| 53 | } |
| 54 | |
| 55 | function main() { |
| 56 | console.log('\nCitadel Security Test Suite\n' + '='.repeat(40)); |
| 57 | |
| 58 | // ── 1. Path Traversal Protection ── |
| 59 | |
| 60 | console.log('\n▶ Path Traversal Protection'); |
| 61 | |
| 62 | test('protect-files blocks ../../../etc/passwd', () => { |
| 63 | const input = JSON.stringify({ |
| 64 | tool_name: 'Edit', |
| 65 | tool_input: { file_path: '../../../etc/passwd' } |
| 66 | }); |
| 67 | |
| 68 | const result = spawnSync(process.execPath, [PROTECT_FILES_HOOK], { |
| 69 | input, |
| 70 | encoding: 'utf8', |
| 71 | cwd: PLUGIN_ROOT, |
| 72 | }); |
| 73 | |
| 74 | assert(result.status === 2, `Expected exit code 2 (block), got ${result.status}`); |
| 75 | assert( |
| 76 | result.stdout.includes('traversal') || result.stdout.includes('outside'), |
| 77 | 'Expected traversal violation message in stdout' |
| 78 | ); |
| 79 | }); |
| 80 | |
| 81 | test('protect-files blocks absolute path outside project', () => { |
| 82 | const input = JSON.stringify({ |
| 83 | tool_name: 'Write', |
| 84 | tool_input: { file_path: '/etc/passwd' } |
| 85 | }); |
| 86 | |
| 87 | const result = spawnSync(process.execPath, [PROTECT_FILES_HOOK], { |
| 88 | input, |
| 89 | encoding: 'utf8', |
| 90 | cwd: PLUGIN_ROOT, |
| 91 | }); |
| 92 | |
| 93 | assert(result.status === 2, `Expected exit code 2 (block), got ${result.status}`); |
| 94 | }); |
| 95 | |
| 96 | test('protect-files allows absolute read outside project for non-env files', () => { |
| 97 | const input = JSON.stringify({ |
| 98 | tool_name: 'Read', |
| 99 | tool_input: { file_path: path.join(os.tmpdir(), `citadel-reference-${process.pid}.md`) } |
| 100 | }); |
| 101 | |
| 102 | const result = spawnSync(process.execPath, [PROTECT_FILES_HOOK], { |
| 103 | input, |
| 104 | encoding: 'utf8', |
| 105 | cwd: PLUGIN_ROOT, |
| 106 | }); |
| 107 | |
| 108 | assert(result.status === 0, `Expected exit code 0 (allow), got ${result.status}: ${result.stdout}`); |
| 109 | }); |
| 110 | |
| 111 | test('protect-files allows legitimate project-relative path', () => { |
no test coverage detected