import fs from 'node:fs'; import path from 'node:path'; import net from 'node:net'; import {spawn} from 'node:child_process'; import assert from 'node:assert/strict'; import crypto from 'node:crypto'; const state = JSON.parse(fs.readFileSync('C:/laragon/data/sgf-tempo/run/modular-regression-current.json', 'utf8')); const tag = process.argv[2]; if (state.port !== 55439 || !/^[a-f0-9]{12}$/.test(tag ?? '')) throw Error('Owned QA context required'); const root = path.join(state.root, 'private/payable-history-' + tag); const settings = path.join(root, 'settings.json'); const owned = JSON.parse(fs.readFileSync(settings, 'utf8')); if (owned.tag !== tag || owned.cluster !== 'sgf_modular_regression_' + state.id) throw Error('Owned cluster mismatch'); if (fs.existsSync(path.join(root, 'evidence-http.json'))) throw Error('Completed proof exists; preserve it instead of repeating'); await new Promise((resolve, reject) => { const probe = net.createServer(); probe.once('error', () => reject(Error('Owned proof port unavailable'))); probe.listen(8047, '127.0.0.1', () => probe.close(resolve)); }); const log = fs.openSync(path.join(root, 'evidence-http-server.log'), 'a'); const server = spawn('C:/laragon/tools/sgf-tempo/php-8.4.27/php.exe', ['-S', '127.0.0.1:8047', path.resolve('scripts/payable-history-sgf-http-router.php')], { cwd: process.cwd(), env: {...process.env, PAYABLE_HISTORY_QA_SETTINGS: settings}, windowsHide: true, stdio: ['ignore', log, log], }); let checks = 0; const check = (ok, why) => { checks++; assert(ok, why); }; const jar = new Map(); let auth; async function request(url, body, extra = {}) { const headers = {Accept: 'application/json', Cookie: [...jar].map(([k,v]) => k + '=' + v).join('; '), 'X-SGF-Context': auth?.context ?? '', ...extra}; if (body) Object.assign(headers, {'Content-Type': 'application/json', 'X-CSRF-TOKEN': auth?.csrf ?? '', 'Idempotency-Key': crypto.randomUUID()}); const r = await fetch('http://127.0.0.1:8047' + url, {method: body ? 'POST' : 'GET', headers, body: body ? JSON.stringify(body) : undefined, redirect: 'manual', signal: AbortSignal.timeout(8000)}); for (const cookie of r.headers.getSetCookie()) { const pair = cookie.split(';')[0], at = pair.indexOf('='); jar.set(pair.slice(0, at), pair.slice(at + 1)); } const text = await r.text(); let data; try { data = JSON.parse(text); } catch {} return {status: r.status, text, data, headers: r.headers}; } try { for (let n = 0; n < 50 && !auth; n++) { try { const entry = await request('/qa/enter/read'); if (entry.status === 200) auth = entry.data; } catch {} if (!auth) await new Promise(resolve => setTimeout(resolve, 100)); } check(Boolean(auth), 'Owned QA entry'); const id = auth.source_id; const focused = await request('/api/supplier-payables?source=' + id); check(focused.status === 200 && focused.data.documents.length === 1 && focused.data.documents[0].local_id === id, 'Exact source through real HTTP kernel'); check(focused.data.obligations.length === 1 && focused.data.obligations[0].balance_minor === 3000, 'Recognised original position'); check(focused.data.pagination.documents.total === 1 && focused.data.listing_query.source === id, 'Scoped source total and metadata'); const page = await request('/api/supplier-payables?source=' + id + '&proposal_page=2&event_page=2'); check(page.status === 200 && page.data.documents[0].local_id === id && page.data.obligations[0].balance_minor === 3000, 'Evidence pages leave source and position fixed'); const absent = await request('/api/supplier-payables?source=' + id + '&recognition=unrecognised'); check(absent.status === 200 && absent.data.documents.length === 0 && absent.data.events.length === 0, 'Combined predicate excludes all other evidence'); for (const query of ['source=0', 'source=-1', 'source=', 'source%5Ba%5D=1', 'source=true', 'source=999999999999999999999999999999']) { check((await request('/api/supplier-payables?' + query)).status === 422, 'Invalid source rejected'); } check((await request('/api/supplier-payables?source=9223372036854775807')).status === 403, 'Unavailable source does not disclose existence'); check((await request('/api/supplier-payables?source=' + id, undefined, {'X-SGF-Context': 'obsolete'})).status === 409, 'Focus does not bypass current context'); check((await request('/api/supplier-payables/prepare_history', {id, reason: 'Focused source must not grant write rights.'})).status === 403, 'Read-only source link grants no command rights'); const html = await request('/supplier-payables?source=' + id); check(html.status === 200 && html.text.includes('name="source" value="' + id + '"'), 'Rendered form retains source'); check(html.text.includes('ConferĂȘncia da origem #' + id) && html.text.includes('Consultar todas as origens'), 'Focus and exit visible'); check(html.text.includes('href="/supplier-payables?source=' + id + '"'), 'Document evidence link resolves locally'); const injection = await request('/supplier-payables?source=' + id + '&q=' + encodeURIComponent('')); check(injection.status === 200 && !injection.text.includes('') && injection.text.includes('<script>evidence_xss</script>'), 'Focused search remains escaped'); check(focused.headers.get('cache-control').includes('no-store'), 'Private focused response'); const report = {increment: 'SGF-PAYABLE-EVIDENCE-FOCUS-SIM-v1', passed: true, checks, real_http_kernel: true, read_only_actor: true, visual_review: false, browser_interactions_tested: false}; fs.writeFileSync(path.join(root, 'evidence-http.json'), JSON.stringify(report, null, 2) + '\n'); console.log(JSON.stringify(report)); } finally { if (server.exitCode === null) { server.kill(); await new Promise(resolve => server.once('exit', resolve)); } fs.closeSync(log); }