Files
wikideck/scripts/custody-deployment-check.ts
2026-10-20 16:24:01 -04:00

51 lines
3.6 KiB
TypeScript
Executable File

import { Pool } from 'pg';
import { generateKeyPairSync, randomUUID, sign } from 'node:crypto';
import { postgresConfig } from '../server/market/postgres-config.ts';
import { auditPostgres } from '../server/market/postgres-custody.ts';
import { custodyMessage, CUSTODY_POLICY, type CustodyCommand, type CustodyPage } from '../shared/custody.ts';
import { address } from '../server/testnet/consensus.ts';
// Run inside the new sandbox application container. Optional explicit fictitious credit probe only.
const credit = process.argv.slice(2);
if (credit.length && (credit.length !== 1 || credit[0] !== '--credit')) throw new Error('Expected no arguments or --credit');
const configuration = await postgresConfig();
const pool = new Pool(configuration);
try {
// Verify server policy too: correct credentials must NOT authenticate over plaintext TCP.
const plaintext = new Pool({ ...configuration, ssl: false, connectionTimeoutMillis: 3000 });
try {
let rejected = false;
try { await plaintext.query('SELECT 1'); } catch { rejected = true; }
if (!rejected) throw new Error('Database unexpectedly permits plaintext authentication');
} finally { await plaintext.end(); }
const c = await pool.connect();
try {
const tls = await c.query('SELECT ssl,version FROM pg_stat_ssl WHERE pid=pg_backend_pid()');
if (tls.rows[0]?.ssl !== true) throw new Error('Database connection is not encrypted');
const role = await c.query('SELECT current_user AS role');
if (role.rows[0].role !== 'custody_runtime') throw new Error('Expected restricted sandbox runtime role');
const page = await fetch('http://127.0.0.1:3001/api/custody', { signal: AbortSignal.timeout(10000) });
if (!page.ok) throw new Error('Custody API unavailable');
const data = await page.json() as CustodyPage;
if (data.info.mode !== 'sandbox' || data.info.liveDeposits || data.info.liveWithdrawals || data.info.nftSettlement) throw new Error('Unexpected custody capabilities');
if (credit.length) {
const keys = generateKeyPairSync('ec', { namedCurve: 'prime256v1' });
const publicKey = keys.publicKey.export({ type: 'spki', format: 'der' }).toString('base64');
const terms: Omit<CustodyCommand, 'signature'> = { version: 1, mode: 'sandbox', policy: CUSTODY_POLICY,
network: data.info.network, chainId: data.info.chainId, custodianId: data.info.custodianId,
actor: address(publicKey), publicKey, nonce: randomUUID(), expiresAt: Date.now() + 60000, action: { type: 'mock-credit' } };
const signature = sign('sha256', Buffer.from(custodyMessage(terms)), { key: keys.privateKey, dsaEncoding: 'ieee-p1363' }).toString('base64');
const result = await fetch('http://127.0.0.1:3001/api/custody/command', { method: 'POST',
headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...terms, signature }), signal: AbortSignal.timeout(10000) });
if (!result.ok || (await result.json()).availableAtomicXmr !== '1000000000000') throw new Error('Fictitious credit probe failed');
// Test key never printed/persisted. The resulting fictitious liability remains in the sandbox journal.
}
await c.query('BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY');
const audit = await auditPostgres(c); await c.query('COMMIT');
console.log(JSON.stringify({ custodianId: data.info.custodianId, tls: tls.rows[0].version,
role: role.rows[0].role, sandbox: true, ...audit }));
} finally { c.release(); }
} catch {
console.error('Sandbox deployment check failed; no connection secrets logged.'); process.exitCode = 1;
} finally { await pool.end(); }