Files
ECC/tests/hooks/observe-entrypoint-security.test.js
T
Frank_zhu 08813f49ff test(security): Layer-1 observe.sh entrypoint allowlist evidence (#3171)
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>
2026-09-19 20:56:34 +08:00

99 lines
2.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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 25 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);