import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { assessHookAdditionalContext } from '../../scanners/lib/hook-additional-context.mjs'; // B5 (v5.10) — pure heuristic: does a hook script build // hookSpecificOutput.additionalContext from un-grepped / verbose command output? // Low precision by design (ships as an info advisory, never severity-bearing). describe('assessHookAdditionalContext — not applicable', () => { it('empty / missing input → not flagged', () => { assert.equal(assessHookAdditionalContext({}).flagged, false); assert.equal(assessHookAdditionalContext({ scriptContent: '' }).flagged, false); assert.equal(assessHookAdditionalContext().flagged, false); }); it('script with no additionalContext reference → not flagged even if it cats a file', () => { const a = assessHookAdditionalContext({ scriptContent: 'CONTENT="$(cat /var/log/big.log)"\necho "$CONTENT"\n', }); assert.equal(a.buildsAdditionalContext, false); assert.equal(a.flagged, false); }); }); describe('assessHookAdditionalContext — shell hooks', () => { it('additionalContext built from an unfiltered cat → flagged', () => { const a = assessHookAdditionalContext({ scriptContent: 'BODY="$(cat /tmp/notes.md)"\n' + 'echo "{\\"hookSpecificOutput\\":{\\"additionalContext\\":\\"$BODY\\"}}"\n', }); assert.equal(a.buildsAdditionalContext, true); assert.equal(a.hasVerboseCapture, true); assert.equal(a.hasFilter, false); assert.equal(a.capturesUnfiltered, true); assert.equal(a.flagged, true); }); it('additionalContext from a git log → flagged', () => { const a = assessHookAdditionalContext({ scriptContent: 'LOG="$(git log --oneline)"\n' + 'printf \'{"hookSpecificOutput":{"additionalContext":"%s"}}\' "$LOG"\n', }); assert.equal(a.flagged, true); }); it('additionalContext from cat piped through grep → NOT flagged (filtered)', () => { const a = assessHookAdditionalContext({ scriptContent: 'BODY="$(cat /tmp/test.log | grep ERROR)"\n' + 'echo "{\\"hookSpecificOutput\\":{\\"additionalContext\\":\\"$BODY\\"}}"\n', }); assert.equal(a.hasFilter, true); assert.equal(a.capturesUnfiltered, false); assert.equal(a.flagged, false); }); it('additionalContext from a cheap command only ($(date)) → NOT flagged', () => { const a = assessHookAdditionalContext({ scriptContent: 'NOW="$(date)"\n' + 'echo "{\\"hookSpecificOutput\\":{\\"additionalContext\\":\\"$NOW\\"}}"\n', }); assert.equal(a.hasVerboseCapture, false); assert.equal(a.flagged, false); }); }); describe('assessHookAdditionalContext — node hooks', () => { it('execSync(git log) into additionalContext with no slice → flagged', () => { const a = assessHookAdditionalContext({ scriptContent: "const out = execSync('git log --oneline').toString();\n" + "process.stdout.write(JSON.stringify({ hookSpecificOutput: { additionalContext: out } }));\n", }); assert.equal(a.flagged, true); }); it('readFileSync sliced before additionalContext → NOT flagged (bounded)', () => { const a = assessHookAdditionalContext({ scriptContent: "const raw = readFileSync('big.log', 'utf8');\n" + "const out = raw.slice(0, 400);\n" + "process.stdout.write(JSON.stringify({ hookSpecificOutput: { additionalContext: out } }));\n", }); assert.equal(a.hasFilter, true); assert.equal(a.flagged, false); }); });