test: strengthen processing cancellation and refusal guards
Bound the halt-abort expectation, check Discord refusal before malformed journal reads, and isolate HTTP origin and valid oversized-body guards. These test changes are committed for the row 191 gate; execution awaits the coordinated slot.
This commit is contained in:
1 parent
7aa18b0f6e
commit
81889b58d5
3 files changed
+26
-3
No files matched your search
@@ -1,7 +1,7 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { mkdirSync, unlinkSync, readFileSync } from 'node:fs';
|
||||
import { mkdirSync, unlinkSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { createConnector } from '../src/connector.mjs';
|
||||
import { initializeControl, assertProcessing, transition } from '../../processing-control/src/state.mjs';
|
||||
@@ -21,6 +21,12 @@ test('halted connector refuses before outbox reconciliation, engine or gateway s
|
||||
transition(f.root, actor);
|
||||
await assert.rejects(createConnector(f.options).start(), e => e.code === 'processing-halted');
|
||||
assert.equal(f.rest.calls.length, 0); assert.equal(f.engine.started, false);
|
||||
const corrupt = fixture(); ensureJournal(corrupt.journalDir);
|
||||
const connector = createConnector(corrupt.options);
|
||||
transition(corrupt.root, actor);
|
||||
writeFileSync(join(corrupt.journalDir, 'outbox.jsonl'), '{broken\n', { mode: 0o600 });
|
||||
await assert.rejects(connector.start(), e => e.code === 'processing-halted');
|
||||
assert.equal(corrupt.rest.calls.length, 0); assert.equal(corrupt.engine.started, false);
|
||||
});
|
||||
test('halt arriving during startup reconciliation prevents engine and gateway start', async () => {
|
||||
const f = fixture(); ensureJournal(f.journalDir);
|
||||
|
||||
@@ -9,7 +9,7 @@ import { initializeControl, transition } from '../src/state.mjs';
|
||||
const api = await import('../src/effects.mjs').catch(e => { if (e.code === 'ERR_MODULE_NOT_FOUND') return {}; throw e; });
|
||||
function fixture(t) { const root = mkdtempSync(join(tmpdir(), 'processing-effect-')); initializeControl(root); t.after(() => rmSync(root, { recursive: true, force: true })); return root; }
|
||||
const actor = { business: 'demo', human: 'jason', halted: true };
|
||||
test('halt aborts an active local request and prevents a subsequent effect after halt/resume', async t => {
|
||||
test('halt aborts an active local request and prevents a subsequent effect after halt/resume', { timeout: 4000 }, async t => {
|
||||
assert.equal(typeof api.withProcessing, 'function');
|
||||
const root = fixture(t); let started;
|
||||
const ready = new Promise(resolve => { started = resolve; });
|
||||
|
||||
@@ -48,7 +48,7 @@ test('processing write fences refuse cross-site, wrong origin, unnamed host, dup
|
||||
{ headers: { ...POST.headers, host: `127.0.0.1:${f.server.address().port}`, 'x-user': undefined } },
|
||||
{ headers: { ...POST.headers, 'x-user': ['jason', 'jason'] } },
|
||||
{ headers: { ...POST.headers, 'content-type': 'text/plain' } },
|
||||
{ body: '{"human":"jason"}' }, { body: '[]' }, { body: 'null' }, { body: ' '.repeat(1025) },
|
||||
{ body: '{"human":"jason"}' }, { body: '[]' }, { body: 'null' }, { body: ' '.repeat(1025) + '{}' },
|
||||
];
|
||||
for (const c of cases) assert.ok((await http(f.server, '/api/processing/halt', { ...POST, ...c })).status >= 400);
|
||||
assert.equal((await http(f.server, '/api/processing/resume', POST)).status, 400);
|
||||
@@ -81,3 +81,20 @@ test('processing writes use the existing SSO signer and still require --send and
|
||||
assert.deepEqual(calls, enabled ? ['halt'] : []);
|
||||
}
|
||||
});
|
||||
|
||||
// Exercise the handler's own origin/site guards independently of serve's outer fence.
|
||||
test('processing handler independently refuses wrong origin and cross-site before its writer', async () => {
|
||||
const { Readable } = await import('node:stream');
|
||||
const { processingHTTP } = await import('../src/processing-http.mjs');
|
||||
for (const changed of [{ origin: ['https://elsewhere'] }, { 'sec-fetch-site': ['cross-site'] }]) {
|
||||
const req = Readable.from([Buffer.from('{}')]); req.method = 'POST';
|
||||
req.headersDistinct = { 'x-user': ['jason'], origin: ['https://console.example'],
|
||||
'sec-fetch-site': ['same-origin'], 'content-type': ['application/json'], ...changed };
|
||||
let status, body, called = false;
|
||||
const res = { writeHead: value => { status = value; }, end: value => { body = JSON.parse(value); } };
|
||||
await processingHTTP(req, res, { path: '/api/processing/halt', search: '', named: true, send: () => {},
|
||||
preview: { host: 'console.example', header: 'x-user', user: 'jason' },
|
||||
processing: { halt: async () => { called = true; return {}; } } });
|
||||
assert.equal(status, 403); assert.equal(called, false); assert.equal(body.sent, false);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user