// R5: the sandbox may load parsing helpers, never proxy PIN or host state. import test from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import * as common from '../src/common.mjs'; test('validation has only the exact parsing import and no state or I/O capability', () => { const source = readFileSync(new URL('../src/validation.mjs', import.meta.url), 'utf8'); assert.deepEqual([...source.matchAll(/^import .*;$/gm)].map(m => m[0]), ["import { validateHeaderValue } from 'node:http';"]); assert.equal((source.match(/\bimport\b/g) ?? []).length, 1); assert.doesNotMatch(source, /\b(?:require|process|globalThis|global|fetch|eval|Function|WebSocket|XMLHttpRequest|Buffer|URL|fs|path|PIN|config|state|env)\b/); assert.doesNotMatch(source, /\b(?:readFile|writeFile|open|request|createServer|connect|listen|setTimeout|setInterval)\w*\b/); // No namespace/default import, aliases, reexports or lazy imports can expose node:http I/O. assert.equal((source.match(/\bvalidateHeaderValue\b/g) ?? []).length, 2); assert.doesNotMatch(source, /\bexport\s+(?:\*|\{)|\bimport\s*\(/); }); test('common reexports the exact validation bindings and errors keep their identity', async () => { const validation = await import('../src/validation.mjs'); for (const name of ['ProxyError', 'refuse', 'validManagementKey', 'proxyTiming']) assert.equal(common[name], validation[name], name); assert.throws(() => validation.refuse('fixture-refusal'), e => e instanceof common.ProxyError && e.code === 'fixture-refusal' && e.message === 'fixture-refusal'); assert.throws(() => common.refuse('fixture-refusal'), e => e instanceof validation.ProxyError); }); test('validation retains management header parsing and timing bounds', async () => { const { validManagementKey, proxyTiming, ProxyError } = await import('../src/validation.mjs'); for (const value of ['a', 'fx331-key', '!~']) assert.equal(validManagementKey(value), true); for (const value of ['', 'with space', 'line\n', 'line\r', '\t', '\u007f', '\u0080', null, 7]) assert.equal(validManagementKey(value), false); assert.deepEqual(proxyTiming({}), {}); assert.deepEqual(proxyTiming({ rotateGraceMinutes: 1, firstOutputSeconds: 1 }), { rotateGraceMinutes: 1, firstOutputSeconds: 1 }); assert.deepEqual(proxyTiming({ rotateGraceMinutes: 1440, firstOutputSeconds: 3600 }), { rotateGraceMinutes: 1440, firstOutputSeconds: 3600 }); for (const [field, max, code] of [['rotateGraceMinutes', 1440, 'proxy-rotate-grace-invalid'], ['firstOutputSeconds', 3600, 'proxy-first-output-invalid']]) { for (const value of [0, -1, max + 1, 1.5, '120', null]) assert.throws(() => proxyTiming({ [field]: value }), e => e instanceof ProxyError && e.code === code); } });