40 lines
2.6 KiB
TypeScript
Executable File
40 lines
2.6 KiB
TypeScript
Executable File
import { Pool } from 'pg';
|
|
import { postgresConfig } from '../server/market/postgres-config.ts';
|
|
import { migrateCustody, grantCustodyRuntime } from '../server/market/postgres-schema.ts';
|
|
import { IS_MAINNET } from '../shared/network.ts';
|
|
|
|
// Explicit one-shot service in the local persistent sandbox stack, NOT HTTP-startup migrations.
|
|
if (IS_MAINNET || process.env.WIKIDECK_LOCAL_PG_BOOTSTRAP !== 'sandbox-only') throw new Error('Local sandbox bootstrap only');
|
|
const ca = '/secrets/admin/ca.crt';
|
|
const config = (role: string) => postgresConfig({ WIKIDECK_CUSTODY_PG_URL_FILE: `/secrets/${role}/url`, WIKIDECK_CUSTODY_PG_CA_FILE: ca });
|
|
try {
|
|
const admin = new Pool(await config('admin'));
|
|
try {
|
|
const ownerConfig = await config('owner'), runtimeConfig = await config('runtime');
|
|
const backupConfig = await postgresConfig({ WIKIDECK_CUSTODY_PG_URL_FILE: '/secrets/backup/url',
|
|
WIKIDECK_CUSTODY_PG_CA_FILE: '/secrets/backup/ca.crt' });
|
|
for (const [role, password] of [['custody_owner', ownerConfig.password], ['custody_runtime', runtimeConfig.password],
|
|
['custody_backup', backupConfig.password]] as const) {
|
|
// Static role allowlist; password is a generated hex token. Values are never printed, even on error.
|
|
if (typeof password !== 'string' || !/^[a-f0-9]{64}$/.test(password)) throw new Error('Invalid generated credential');
|
|
const exists = await admin.query('SELECT 1 FROM pg_roles WHERE rolname=$1', [role]);
|
|
if (!exists.rowCount) await admin.query(`CREATE ROLE ${role} LOGIN PASSWORD '${password}' NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS`);
|
|
}
|
|
await admin.query('REVOKE CREATE ON SCHEMA public FROM PUBLIC; REVOKE ALL ON DATABASE wikideck_custody FROM PUBLIC');
|
|
await admin.query(`GRANT CONNECT,CREATE ON DATABASE wikideck_custody TO custody_owner;
|
|
GRANT CONNECT ON DATABASE wikideck_custody TO custody_runtime,custody_backup`);
|
|
} finally { await admin.end(); }
|
|
const owner = new Pool(await config('owner'));
|
|
try {
|
|
await migrateCustody(owner); await grantCustodyRuntime(owner, 'custody_runtime');
|
|
await owner.query(`GRANT USAGE ON SCHEMA wk_custody TO custody_backup;
|
|
GRANT SELECT ON ALL TABLES IN SCHEMA wk_custody TO custody_backup;
|
|
GRANT SELECT ON ALL SEQUENCES IN SCHEMA wk_custody TO custody_backup`);
|
|
}
|
|
finally { await owner.end(); }
|
|
console.log('Local PostgreSQL schema and restricted runtime grants ready. Sandbox payments only.');
|
|
} catch {
|
|
console.error('Local PostgreSQL bootstrap failed; inspect roles, secret volumes, TLS and schema privately. No reset or fallback performed.');
|
|
process.exitCode = 1;
|
|
}
|