feat(voyage): vendor DOMPurify >=3.1.1 + sanitize annotation-content
This commit is contained in:
parent
e839ba2a7a
commit
fc8c9eecdd
5 changed files with 105 additions and 6 deletions
|
|
@ -413,3 +413,50 @@ test('docs/screenshots/README.md documents mappestruktur + hooks (v4.3 Step 23)'
|
|||
assert.match(text, /window\.__voyage\.scheduleRender/, 'scheduleRender hook documented');
|
||||
assert.match(text, /window\.__voyage\.getProjectArtifacts/, 'getProjectArtifacts hook documented');
|
||||
});
|
||||
|
||||
// v4.3 Step 24 — vendor DOMPurify + sanitize annotation-content
|
||||
test('playground/lib/dompurify.min.js is vendored (v4.3 Step 24)', () => {
|
||||
const path = join(PLAYGROUND, 'lib', 'dompurify.min.js');
|
||||
assert.equal(existsSync(path), true, 'playground/lib/dompurify.min.js must exist (run scripts/vendor-playground-libs.mjs)');
|
||||
const size = statSync(path).size;
|
||||
// Sanity floor — DOMPurify min bundle is ~22 KB; reject empty/0-byte
|
||||
assert.ok(size > 5000, 'dompurify.min.js too small (' + size + ' bytes) — vendor script may have failed');
|
||||
});
|
||||
|
||||
test('playground/lib/VENDOR-MANIFEST.json pins dompurify >= 3.1.1 (v4.3 Step 24)', () => {
|
||||
const path = join(PLAYGROUND, 'lib', 'VENDOR-MANIFEST.json');
|
||||
const manifest = JSON.parse(readFileSync(path, 'utf-8'));
|
||||
assert.ok(manifest.pins && manifest.pins.dompurify, 'manifest must pin dompurify');
|
||||
// semver compare on major.minor: must be >= 3.1.1
|
||||
const m = String(manifest.pins.dompurify).match(/^(\d+)\.(\d+)\.(\d+)/);
|
||||
assert.ok(m, 'invalid dompurify pin format: ' + manifest.pins.dompurify);
|
||||
const [, maj, min] = m;
|
||||
assert.ok(Number(maj) > 3 || (Number(maj) === 3 && Number(min) >= 1), 'dompurify pin must be >= 3.1.1, got ' + manifest.pins.dompurify);
|
||||
assert.ok(manifest.output_files.includes('dompurify.min.js'), 'manifest output_files must list dompurify.min.js');
|
||||
});
|
||||
|
||||
test('voyage-playground.html loads dompurify.min.js (v4.3 Step 24)', () => {
|
||||
const text = readFileSync(HTML, 'utf-8');
|
||||
assert.match(text, /<script src="lib\/dompurify\.min\.js">/, 'lib/dompurify.min.js script tag required');
|
||||
});
|
||||
|
||||
test('voyage-playground.html declares sanitizeAnnotation function with allowlist (v4.3 Step 24)', () => {
|
||||
const text = readFileSync(HTML, 'utf-8');
|
||||
assert.match(text, /function\s+sanitizeAnnotation\s*\(/, 'sanitizeAnnotation() function required');
|
||||
// Must call DOMPurify.sanitize with an ALLOWED_TAGS allowlist
|
||||
assert.match(text, /DOMPurify\.sanitize/, 'DOMPurify.sanitize call required');
|
||||
assert.match(text, /ALLOWED_TAGS:\s*\[/, 'ALLOWED_TAGS allowlist required');
|
||||
});
|
||||
|
||||
test('voyage-playground.html bundle stays under 460 KB HALT-gate (v4.3 Step 24)', () => {
|
||||
// Sums voyage-playground.html + every playground/lib/*.js file. Per plan
|
||||
// critic finding 18 — must be < 460000 bytes (40 KB margin under the
|
||||
// 500 KB NFR).
|
||||
const htmlSize = statSync(HTML).size;
|
||||
const libDir = join(PLAYGROUND, 'lib');
|
||||
const libFiles = readdirSync(libDir).filter((f) => f.endsWith('.js') || f.endsWith('.mjs'));
|
||||
let libTotal = 0;
|
||||
for (const f of libFiles) libTotal += statSync(join(libDir, f)).size;
|
||||
const total = htmlSize + libTotal;
|
||||
assert.ok(total < 460000, 'bundle size ' + total + ' bytes exceeds 460 KB HALT-gate (' + libFiles.length + ' lib files)');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue