feat(voyage): implement HTML-comment indirect prompt injection mitigation (Sec T4)

This commit is contained in:
Kjell Tore Guttormsen 2026-05-10 18:03:37 +02:00
commit 6293775f30
3 changed files with 144 additions and 1 deletions

View file

@ -460,3 +460,25 @@ test('voyage-playground.html bundle stays under 460 KB HALT-gate (v4.3 Step 24)'
const total = htmlSize + libTotal;
assert.ok(total < 460000, 'bundle size ' + total + ' bytes exceeds 460 KB HALT-gate (' + libFiles.length + ' lib files)');
});
// v4.3 Step 25 — HTML-comment indirect prompt-injection mitigation (Sec T4).
// (Behavioral fixture-tests live in tests/integration/annotation-export-schema.test.mjs.)
test('voyage-playground.html declares stripUnsafeComments anchor-allowlist (v4.3 Step 25)', () => {
const text = readFileSync(HTML, 'utf-8');
assert.match(text, /function\s+stripUnsafeComments\s*\(/, 'stripUnsafeComments() required');
// Filter must use parseAnchor as the allowlist gate
assert.match(text, /parseAnchor\(match\)\s*\?\s*match\s*:\s*''/, 'parseAnchor allowlist gate required');
});
test('voyage-playground.html renderArtifact strips comments before md.render (v4.3 Step 25)', () => {
const text = readFileSync(HTML, 'utf-8');
// The Step 25 hook must precede the md.render call inside renderArtifact.
// Locate renderArtifact body and assert ordering.
const bodyStart = text.indexOf('function renderArtifact');
assert.ok(bodyStart > 0, 'renderArtifact() must exist');
const bodyEnd = text.indexOf('}', bodyStart + 200);
const body = text.slice(bodyStart, bodyEnd + 1);
const stripIdx = body.indexOf('stripUnsafeComments');
const renderIdx = body.indexOf('md.render');
assert.ok(stripIdx > 0 && stripIdx < renderIdx, 'stripUnsafeComments must run before md.render');
});