scripts/live-test-rest-probe.mjs
Rama main · réplica de lectura del repositorio original.
import { createServer } from 'node:http';
import { randomUUID } from 'node:crypto';
import { appendFileSync, closeSync, openSync, realpathSync } from 'node:fs';
import { dirname, isAbsolute } from 'node:path';
import { execFileSync } from 'node:child_process';
import { pathToFileURL } from 'node:url';
import { parseArgs } from 'node:util';
/** Disposable provider witness. Never records headers, query strings, or bodies. */
export async function startRestProbe({ logPath, bearer, port = 0, timeoutMs = 600_000 }) {
if (!isAbsolute(logPath)) throw new Error('Use an absolute private log path.');
const directory = realpathSync(dirname(logPath));
let inRepository = false;
try {
execFileSync('git', ['-C', directory, 'rev-parse', '--show-toplevel'], { stdio: 'ignore' });
inRepository = true;
} catch { /* A private directory outside Git is expected. */ }
if (inRepository) throw new Error('Probe logs must be outside Git repositories.');
if (!/^qa-synthetic-[A-Za-z0-9_-]{8,100}$/.test(bearer ?? '')) throw new Error('Use a qa-synthetic- test bearer, never a real credential.');
if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error('Invalid port.');
if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 1_800_000) throw new Error('Probe lifetime must be at most 30 minutes.');
const fd = openSync(logPath, 'wx', 0o600);
let requests = 0;
let stopped = false;
let timer;
const server = createServer((request, response) => {
const path = (request.url ?? '').split('?')[0];
const marker = /^\/probe\/([A-Za-z0-9_-]{1,80})$/.exec(path)?.[1];
const method = request.method ?? 'UNKNOWN';
const authorizationMatchesFixture = request.headers.authorization === `Bearer ${bearer}`;
const status = !marker ? 404 : !authorizationMatchesFixture ? 401 : !['GET', 'HEAD'].includes(method) ? 405 : 200;
const nonce = status === 200 ? randomUUID() : undefined;
try {
appendFileSync(fd, `${JSON.stringify({ at: new Date().toISOString(), method, marker: marker ?? null, status, authorizationPresent: !!request.headers.authorization, authorizationMatchesFixture, ...(nonce ? { nonce } : {}) })}\n`);
} catch {
response.writeHead(500).end();
void stop();
return;
}
response.writeHead(status, { 'content-type': 'application/json', 'cache-control': 'no-store' });
response.end(method === 'HEAD' ? undefined : JSON.stringify(nonce ? { nonce, method, marker } : { error: status === 401 ? 'unauthorized' : status === 405 ? 'method_not_allowed' : 'not_found' }));
request.resume();
if (++requests >= 100) void stop();
});
server.requestTimeout = 5_000;
server.headersTimeout = 5_000;
server.maxConnections = 16;
const stop = () => new Promise((resolve) => {
if (stopped) return resolve();
stopped = true;
clearTimeout(timer);
server.close(() => { closeSync(fd); resolve(); });
server.closeAllConnections();
});
try {
await new Promise((resolve, reject) => {
server.once('error', reject);
server.listen(port, '127.0.0.1', resolve);
});
} catch (error) {
closeSync(fd);
throw error;
}
timer = setTimeout(() => void stop(), timeoutMs);
timer.unref();
return { origin: `http://127.0.0.1:${server.address().port}`, stop };
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
const { values } = parseArgs({ options: { log: { type: 'string' }, 'expect-bearer': { type: 'string' }, port: { type: 'string', default: '0' } } });
const probe = await startRestProbe({ logPath: values.log ?? '', bearer: values['expect-bearer'], port: Number(values.port) });
console.log(JSON.stringify({ origin: probe.origin, lifetimeMs: 600_000, maxRequests: 100 }));
for (const signal of ['SIGINT', 'SIGTERM']) process.once(signal, () => void probe.stop());
}