import test from 'node:test'; import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; const read = (path: string) => readFile(new URL(`../${path}`, import.meta.url), 'utf8'); test('persistent custody deployment remains separate, sandbox-only and password authenticated without a database host port', async () => { const compose = (await read('compose.custody.yaml')).replaceAll('\r\n', '\n'); assert.match(compose, /WIKIDECK_CUSTODY_MODE: sandbox/); assert.match(compose, /WIKIDECK_CUSTODY_STORAGE: postgres/); assert.match(compose, /WIKIDECK_PAYMENT_MODE: mock/); assert.match(compose, /financial: \{internal: true\}/); assert.match(compose, /POSTGRES_PASSWORD_FILE:/); assert.doesNotMatch(compose, /POSTGRES_HOST_AUTH_METHOD|LOCAL_TEST|5432:5432|tmpfs:.*postgresql/); const database = compose.split(' database:')[1].split(' migrate:')[0]; assert.doesNotMatch(database, /ports:/); assert.match(database, /pg-data:\/var\/lib\/postgresql\/data/); const application = compose.split(' wikideck:')[1].split('networks:\n financial:')[0]; assert.match(application, /pg-runtime:\/secrets\/runtime:ro/); assert.doesNotMatch(application, /pg-admin:|pg-owner:|pg-tls:/); }); test('database HBA requires TLS+SCRAM over TCP and provisioning refuses partial credential replacement', async () => { const hba = await read('deploy/postgres/pg_hba.conf'), setup = await read('deploy/postgres/setup.mjs'); assert.match(hba, /hostnossl all all all reject/); assert.match(hba, /hostssl wikideck_custody custody_runtime all scram-sha-256/); assert.doesNotMatch(hba, /^host.*trust/m); assert.match(setup, /randomBytes\(32\)/); assert.match(setup, /Partial secret initialization/); assert.match(setup, /subjectAltName=DNS:database/); assert.match(setup, /-checkend/); }); test('standalone Monero observer service is non-root, filesystem-hardened and has no public listener', async () => { const unit = await read('deploy/systemd/wikideck-monero-observer.service'); const guide = await read('deploy/systemd/README.md'); const observer = JSON.parse(await read('deploy/systemd/wallet-rpc.example.json')) as { network: string; url: string }; const mtls = JSON.parse(await read('deploy/systemd/mtls.example.json')) as { url: string; clientPrivateKeyFile: string }; assert.match(unit, /User=wikideck-observer/); assert.match(unit, /ProtectSystem=strict/); assert.match(unit, /ProtectHome=true/); assert.match(unit, /NoNewPrivileges=true/); assert.match(unit, /CapabilityBoundingSet=/); assert.match(unit, /RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX/); assert.match(unit, /WIKIDECK_MONERO_OBSERVER_WORKER=1/); assert.doesNotMatch(unit, /^\s*(?:ListenStream|ListenDatagram|SocketUser)=/m); assert.equal(observer.network, 'mainnet'); assert.equal(observer.url, mtls.url); assert.equal(mtls.clientPrivateKeyFile, '/etc/wikideck/monero-observer/client.key'); assert.match(guide, /migrate-mainnet-schema/); assert.match(guide, /does \*\*not\*\* issue customer deposit addresses/); assert.doesNotMatch(`${unit}\n${guide}`, /(?:password|api[_-]?key)\s*[:=]\s*[^\s<]+/i); });