import test from 'node:test'; import assert from 'node:assert/strict'; import { setup } from './test-support.mjs'; import { createLocalServer } from './server.mjs'; import { publicMotherPacket, requestPublicMotherReview } from './public-mother-bridge.mjs'; test('loopback API verifies signatures and does not expose a raw context endpoint', async t => { const f = setup(t), server = createLocalServer({ engine: f.engine }); await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); t.after(() => { server.closeAllConnections(); return new Promise(resolve => server.close(resolve)); }); const url = `http://127.0.0.1:${server.address().port}`; const send = envelope => fetch(url + '/events', { method: 'POST', body: JSON.stringify(envelope) }); assert.equal((await fetch(url + '/health')).status, 200); assert.equal((await fetch(url + '/state')).status, 404); assert.equal((await send({ action: 'CREATE_OS' })).status, 403); assert.equal((await send(f.envelope('alice', 'CREATE_OS'))).status, 200); assert.equal((await send(f.envelope('bob', 'READ_CONTEXT'))).status, 403); const correct = await send(f.envelope('alice', 'SWITCH_CHANNEL', { channelId: 'conversation' })); assert.equal((await correct.json()).channel.id, 'conversation'); assert.equal((await fetch(url + '/execute', { method: 'POST', body: '{}' })).status, 409); }); test('public mother receives only consented application metadata and bound evidence references', async t => { const f = setup(t), app = f.application(); app.privateMemory = 'not for publication'; const packet = publicMotherPacket(app); assert.equal(packet.scope, 'public'); assert.equal(packet.privateContextIncluded, false); assert.ok(!JSON.stringify(packet).includes('not for publication')); await assert.rejects(requestPublicMotherReview(app, {}), /NOT_CONNECTED/); await assert.rejects(requestPublicMotherReview(app, { reviewPublic: async () => ({ action: 'REVIEW_APPLICATION', payload: { digest: 'wrong' } }) }), /NOT_BOUND/); const signed = await requestPublicMotherReview(app, { reviewPublic: async request => f.envelope('mother', 'REVIEW_APPLICATION', { digest: request.applicationDigest, decision: 'HOLD', reason: '需要更多证据' }) }); assert.equal(f.engine.handle(signed).decision, 'HOLD'); app.application.evidenceRefs.push('evidence://demo/changed'); assert.throws(() => publicMotherPacket(app), /DIGEST_MISMATCH/); });