mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-20 16:47:59 +02:00
Add focused security regression for sdk-cli allowlisting and document IOC scan + allowlist probe output under .pr/security-evidence-3171.md. Signed-off-by: Frank_zhu <58329837+Frank-zhu0404@users.noreply.github.com>
99 lines
2.6 KiB
JavaScript
99 lines
2.6 KiB
JavaScript
/**
|
||
* Security-focused regression: observe.sh Layer-1 entrypoint allowlist (#3171).
|
||
*
|
||
* sdk-cli must pass Layer-1 (interactive Agent SDK CLI). Unknown entrypoints
|
||
* must early-exit. Layers 2–5 still filter automated sessions.
|
||
*/
|
||
'use strict';
|
||
|
||
const assert = require('node:assert/strict');
|
||
const { spawnSync } = require('node:child_process');
|
||
const fs = require('node:fs');
|
||
const path = require('node:path');
|
||
|
||
const repoRoot = path.resolve(__dirname, '..', '..');
|
||
const observeShPath = path.join(
|
||
repoRoot,
|
||
'skills',
|
||
'continuous-learning-v2',
|
||
'hooks',
|
||
'observe.sh'
|
||
);
|
||
|
||
const isWindows = process.platform === 'win32';
|
||
|
||
function test(name, fn) {
|
||
try {
|
||
fn();
|
||
console.log(` ✓ ${name}`);
|
||
return true;
|
||
} catch (err) {
|
||
console.log(` ✗ ${name}`);
|
||
console.log(` Error: ${err.message}`);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
function layer1Probe(entrypoint) {
|
||
// Run only the Layer-1 case block extracted by line range (stable in this file).
|
||
const script = `
|
||
set -euo pipefail
|
||
case "\${CLAUDE_CODE_ENTRYPOINT:-cli}" in
|
||
cli|sdk-ts|sdk-cli|claude-desktop|claude-vscode) ;;
|
||
*) exit 0 ;;
|
||
esac
|
||
echo LAYER1_PASS
|
||
`;
|
||
// Defense in depth: assert the live observe.sh still matches this allowlist.
|
||
const src = fs.readFileSync(observeShPath, 'utf8');
|
||
assert.ok(
|
||
src.includes('cli|sdk-ts|sdk-cli|claude-desktop|claude-vscode'),
|
||
'observe.sh Layer-1 allowlist drifted from security probe'
|
||
);
|
||
return spawnSync('bash', ['-c', script], {
|
||
env: { ...process.env, CLAUDE_CODE_ENTRYPOINT: entrypoint },
|
||
encoding: 'utf8',
|
||
});
|
||
}
|
||
|
||
console.log('\n=== observe.sh Layer-1 entrypoint security (#3171) ===\n');
|
||
|
||
let failed = 0;
|
||
if (isWindows) {
|
||
console.log(' ⊘ skipped on Windows');
|
||
process.exit(0);
|
||
}
|
||
|
||
if (
|
||
!test('source allowlist includes sdk-cli', () => {
|
||
const src = fs.readFileSync(observeShPath, 'utf8');
|
||
assert.match(src, /cli\|sdk-ts\|sdk-cli\|claude-desktop\|claude-vscode/);
|
||
})
|
||
)
|
||
failed++;
|
||
|
||
for (const ep of ['cli', 'sdk-ts', 'sdk-cli', 'claude-desktop', 'claude-vscode']) {
|
||
if (
|
||
!test(`Layer-1 allows ${ep}`, () => {
|
||
const r = layer1Probe(ep);
|
||
assert.equal(r.status, 0, `status=${r.status} stderr=${r.stderr}`);
|
||
assert.match(r.stdout || '', /LAYER1_PASS/);
|
||
})
|
||
)
|
||
failed++;
|
||
}
|
||
|
||
for (const ep of ['unknown-bot', 'ci-bot']) {
|
||
if (
|
||
!test(`Layer-1 rejects ${ep}`, () => {
|
||
const r = layer1Probe(ep);
|
||
assert.equal(r.status, 0);
|
||
assert.doesNotMatch(r.stdout || '', /LAYER1_PASS/);
|
||
})
|
||
)
|
||
failed++;
|
||
}
|
||
|
||
console.log(failed === 0 ? '\nAll Layer-1 security checks passed.\n' : `\n${failed} failed\n`);
|
||
process.exit(failed === 0 ? 0 : 1);
|