import test from 'node:test'; import assert from 'node:assert/strict'; import { execFileSync, spawnSync } from 'node:child_process'; import { createHash } from 'node:crypto'; import { readFileSync } from 'node:fs'; import { mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { NETWORK, CONSENSUS } from '../shared/testnet.ts'; import { networkProfile } from '../shared/network.ts'; import { CHAIN_ID, GENESIS_TIME, GENESIS_HASH, MAX_TARGET } from '../server/testnet/consensus.ts'; function script(code: string, env: Record = {}) { return execFileSync(process.execPath, ['--experimental-strip-types', '--input-type=module', '-e', code], { env: { ...process.env, WIKIDECK_NETWORK: 'mainnet', WIKIDECK_GENESIS_TIME: '1793491200', ...env }, encoding: 'utf8', timeout: 30000, }).trim(); } test('default profile is mainnet while testnet remains an explicit isolated profile', () => { const hash = (text: string) => createHash('sha256').update(text).digest('hex'); assert.equal(NETWORK, 'wikideck-randomx-testnet-6'); assert.equal(GENESIS_TIME, 1_792_411_200); assert.equal(CHAIN_ID, hash(JSON.stringify(['wikideck-randomx-testnet-6', CONSENSUS, 1_792_411_200, MAX_TARGET]))); assert.equal(networkProfile(undefined), 'mainnet'); assert.equal(networkProfile('testnet'), 'testnet'); assert.throws(() => networkProfile('production')); assert.throws(() => networkProfile('')); }); test('mainnet candidate has distinct deterministic genesis, signatures and strict transaction schemas', () => { const output = JSON.parse(script(` import { NETWORK, nftTransferMessage } from './shared/testnet.ts'; import { CHAIN_ID, GENESIS_HASH, transferSchema } from './server/testnet/consensus.ts'; console.log(JSON.stringify({ NETWORK, CHAIN_ID, GENESIS_HASH, message:nftTransferMessage({chainId:CHAIN_ID,cardHash:'a'.repeat(64),from:'b'.repeat(64),to:'c'.repeat(64),sequence:0}), acceptsTestnet:transferSchema.safeParse({network:'wikideck-randomx-testnet-6',chainId:${JSON.stringify(CHAIN_ID)}, cardHash:'a'.repeat(64),from:'b'.repeat(64),to:'c'.repeat(64),sequence:0,publicKey:'AA==',signature:'A'.repeat(86)+'=='}).success })); `)); assert.equal(output.NETWORK, 'wikideck-randomx-mainnet-1'); assert.notEqual(output.CHAIN_ID, CHAIN_ID); assert.notEqual(output.GENESIS_HASH, GENESIS_HASH); assert.match(output.message, /wikideck-randomx-mainnet-1/); assert.equal(output.acceptsTestnet, false); }); test('mainnet startup is blocked before resources open, while manifest inspection needs no launch approval', () => { const args = ['--experimental-strip-types', 'server/index.ts']; const env = { ...process.env, WIKIDECK_NETWORK: 'mainnet', WIKIDECK_GENESIS_TIME: '1793491200', WIKIDECK_MAINNET_LAUNCH: '', WIKIDECK_MAINNET_RISK_ACK: '' }; const result = spawnSync(process.execPath, args, { env, encoding: 'utf8', timeout: 30000 }); assert.notEqual(result.status, 0); assert.match(result.stderr, /launch-gated/); const manifest = JSON.parse(execFileSync(process.execPath, [...args, '--network-manifest'], { env, encoding: 'utf8' })); assert.equal(manifest.profile, 'mainnet'); assert.equal(manifest.audited, false); assert.equal(manifest.launchStatus, 'candidate-gated'); assert.equal(manifest.privatePeersSupported, true); }); test('mainnet gates require genesis time, chain-specific approval, HTTPS browser origin, and distinct peers', () => { const result = JSON.parse(script(` import { assertLaunchAllowed } from './server/launch.ts'; import { CHAIN_ID, GENESIS_TIME } from './server/testnet/consensus.ts'; const env={WIKIDECK_MAINNET_LAUNCH:CHAIN_ID,WIKIDECK_MAINNET_RISK_ACK:'operator-accepts-unaudited-risk', PUBLIC_ORIGIN:'https://wikideck.example',WIKIDECK_PEERS:'https://peer-a.example,https://peer-b.example'}; const results=[]; for(const [changes,now] of [[{},0],[{WIKIDECK_MAINNET_LAUNCH:'wrong'},Infinity], [{WIKIDECK_MAINNET_RISK_ACK:'not-accepted'},Infinity], [{PUBLIC_ORIGIN:'http://wikideck.example'},Infinity],[{WIKIDECK_PEERS:''},Infinity], [{WIKIDECK_PEERS:'https://peer-a.example,https://peer-a.example/'},Infinity], [{WIKIDECK_ALLOW_PRIVATE_PEERS:'1'},Infinity],[{},Infinity]]) { try { assertLaunchAllowed({...env,...changes},now); results.push(true); } catch { results.push(false); } } console.log(JSON.stringify(results)); `)); assert.deepEqual(result, [false,false,false,false,false,false,true,true]); }); test('private mainnet cluster peers require explicit opt-in and preserve every other launch gate', () => { const result = JSON.parse(script(` import { assertLaunchAllowed } from './server/launch.ts'; import { CHAIN_ID, GENESIS_TIME } from './server/testnet/consensus.ts'; const env={WIKIDECK_MAINNET_LAUNCH:CHAIN_ID,WIKIDECK_MAINNET_RISK_ACK:'operator-accepts-unaudited-risk', PUBLIC_ORIGIN:'https://wikideck.example',WIKIDECK_ALLOW_PRIVATE_PEERS:'1', WIKIDECK_PEERS:'http://wikideck-peer-a.wikideck.svc.cluster.local:80,http://wikideck-peer-b.wikideck.svc.cluster.local:80'}; const cases=[[{},GENESIS_TIME*1000], [{},GENESIS_TIME*1000-1], [{WIKIDECK_ALLOW_PRIVATE_PEERS:'0'},Infinity], [{WIKIDECK_ALLOW_PRIVATE_PEERS:'true'},Infinity], [{WIKIDECK_MAINNET_LAUNCH:'wrong'},Infinity], [{WIKIDECK_MAINNET_RISK_ACK:''},Infinity], [{PUBLIC_ORIGIN:'http://wikideck.example'},Infinity], [{WIKIDECK_PEERS:''},Infinity], [{WIKIDECK_PEERS:'http://peer-a:80,http://peer-a/'},Infinity], [{WIKIDECK_PEERS:'http://peer-a,http://user:password@peer-b'},Infinity], [{WIKIDECK_PEERS:'http://peer-a,http://peer-b/p2p'},Infinity], [{WIKIDECK_PEERS:'http://peer-a,http://peer-b?x=1'},Infinity], [{WIKIDECK_PEERS:'http://peer-a,https://wikideck.example'},Infinity], [{WIKIDECK_PEERS:'http://peer-a,ftp://peer-b'},Infinity]]; console.log(JSON.stringify(cases.map(([changes,now])=>{ try {assertLaunchAllowed({...env,...changes},now);return true;}catch{return false;} }))); `)); assert.deepEqual(result, [true, ...Array(13).fill(false)]); }); test('default mainnet genesis can launch on November 1 and matches browser, Docker and Compose identities', () => { const result = JSON.parse(script(` delete process.env.WIKIDECK_GENESIS_TIME; delete process.env.WIKIDECK_IMAGE_NETWORK; delete process.env.WIKIDECK_IMAGE_GENESIS_TIME; const { assertLaunchAllowed, launchManifest } = await import('./server/launch.ts'); const { expectedChainIdentity } = await import('./shared/chain-identity.ts'); const manifest = launchManifest(); assertLaunchAllowed({WIKIDECK_MAINNET_LAUNCH:manifest.chainId, WIKIDECK_MAINNET_RISK_ACK:'operator-accepts-unaudited-risk',PUBLIC_ORIGIN:'https://wikideck.eom.dev', WIKIDECK_ALLOW_PRIVATE_PEERS:'1', WIKIDECK_PEERS:'http://wikideck-peer-a.wikideck.svc.cluster.local:80,http://wikideck-peer-b.wikideck.svc.cluster.local:80'}, Date.UTC(2026,10,1)); console.log(JSON.stringify({manifest,identity:await expectedChainIdentity()})); `)); assert.equal(result.manifest.genesisTime, 1_793_491_200); assert.equal(result.manifest.chainId, result.identity.chainId); assert.equal(result.manifest.genesis, result.identity.genesis); const dockerfile = readFileSync(new URL('../Dockerfile', import.meta.url), 'utf8'); assert.equal(dockerfile.match(/^ARG WIKIDECK_GENESIS_TIME=1793491200\r?$/gm)?.length, 2); for (const name of ['compose.yaml', 'compose.mainnet.yaml']) { const compose = readFileSync(new URL('../' + name, import.meta.url), 'utf8'); assert.equal(compose.match(/WIKIDECK_GENESIS_TIME:-1793491200/g)?.length, 2); } }); test('runtime cannot silently change the image-baked mainnet genesis', () => { const result = spawnSync(process.execPath, ['--experimental-strip-types', 'server/index.ts', '--network-manifest'], { env: { ...process.env, WIKIDECK_NETWORK: 'mainnet', WIKIDECK_GENESIS_TIME: '1793491200', WIKIDECK_IMAGE_NETWORK: 'mainnet', WIKIDECK_IMAGE_GENESIS_TIME: '1798761600' }, encoding: 'utf8', timeout: 30000, }); assert.notEqual(result.status, 0); assert.match(result.stderr, /Runtime genesis time does not match/); }); test('mainnet ledger uses its isolated folder; testnet backup headers are rejected', async () => { const dir = await mkdtemp(join(tmpdir(), 'wikideck-network-')); try { const result = JSON.parse(script(` import { Ledger } from './server/testnet/ledger.ts'; import { decryptWallet } from './shared/wallet-backup.ts'; import { existsSync } from 'node:fs'; import { join } from 'node:path'; const ledger=await Ledger.open(process.env.PROFILE_TEST_DIR,{hash:async()=>{throw Error('unused')},close(){}}); let rejected=false; try {await decryptWallet({format:'wikideck-wallet-backup',version:1,network:'wikideck-randomx-testnet-6', kdf:'PBKDF2-SHA256',iterations:600000,cipher:'AES-256-GCM',salt:'',iv:'',publicKey:'',ciphertext:''},'password');} catch(e){rejected=/network/.test(e.message);} console.log(JSON.stringify({ledger:existsSync(join(process.env.PROFILE_TEST_DIR,'mainnet','ledger.sqlite')), testnet:existsSync(join(process.env.PROFILE_TEST_DIR,'testnet')),rejected})); ledger.close(); `, { PROFILE_TEST_DIR: dir })); assert.deepEqual(result, { ledger: true, testnet: false, rejected: true }); } finally { await rm(dir, { recursive: true, force: true }); } }); test('operator preflight is read-only, fails closed, and does not disclose credentials', async () => { const dir = await mkdtemp(join(tmpdir(), 'wikideck-preflight-')); try { const { existsSync } = await import('node:fs'); const dataDir = join(dir, 'must-not-be-created'); const secret = 'test-only-sensitive-value-must-not-appear'; const result = spawnSync(process.execPath, ['--experimental-strip-types', 'server/index.ts', '--launch-preflight'], { env: { ...process.env, WIKIDECK_NETWORK: 'mainnet', WIKIDECK_GENESIS_TIME: '1793491200', WIKIDECK_DATA_DIR: dataDir, WIKIDECK_MAINNET_LAUNCH: '', WIKIDECK_MAINNET_RISK_ACK: '', PAYMENT_PROVIDER_API_KEY: secret }, encoding: 'utf8', timeout: 30000, }); assert.equal(result.status, 1); const report = JSON.parse(result.stdout); assert.equal(report.productionReady, false); assert.equal(report.decision, 'NO-GO'); assert.ok(report.checks.some((c: { id: string; status: string }) => c.id === 'consensus-launch-calibration' && c.status === 'blocked')); assert.equal(result.stdout.includes(secret), false); assert.equal(existsSync(dataDir), false); } finally { await rm(dir, { recursive: true, force: true }); } });