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 test from 'node:test';
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import { spawnSync } from 'node:child_process';
|
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 { join } from 'node:path';
|
||||||
import { createConnector } from '../src/connector.mjs';
|
import { createConnector } from '../src/connector.mjs';
|
||||||
import { initializeControl, assertProcessing, transition } from '../../processing-control/src/state.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);
|
transition(f.root, actor);
|
||||||
await assert.rejects(createConnector(f.options).start(), e => e.code === 'processing-halted');
|
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);
|
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 () => {
|
test('halt arriving during startup reconciliation prevents engine and gateway start', async () => {
|
||||||
const f = fixture(); ensureJournal(f.journalDir);
|
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; });
|
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; }
|
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 };
|
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');
|
assert.equal(typeof api.withProcessing, 'function');
|
||||||
const root = fixture(t); let started;
|
const root = fixture(t); let started;
|
||||||
const ready = new Promise(resolve => { started = resolve; });
|
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, host: `127.0.0.1:${f.server.address().port}`, 'x-user': undefined } },
|
||||||
{ headers: { ...POST.headers, 'x-user': ['jason', 'jason'] } },
|
{ headers: { ...POST.headers, 'x-user': ['jason', 'jason'] } },
|
||||||
{ headers: { ...POST.headers, 'content-type': 'text/plain' } },
|
{ 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);
|
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);
|
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'] : []);
|
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