// Real image boundary: catches missing native modules, proto assets and migrations. const assert = require('node:assert/strict'); const { execFileSync } = require('node:child_process'); const { randomUUID } = require('node:crypto'); const image = process.argv[2]; assert.ok(image, 'Pass a built backend image reference'); const name = `wealthledger-smoke-${randomUUID()}`; const docker = (...args) => execFileSync('docker', args, { encoding: 'utf8' }).trim(); const environment = [ '-e', 'DATABASE_URL=file:/data/wealthledger.db', '-e', 'FRONTEND_ORIGIN=http://localhost', '-e', 'JWT_SECRET=disposable-image-smoke-secret-at-least-32-characters', '-e', 'TOKEN_ENCRYPTION_KEY=MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=', '-e', 'LOG_LEVEL=error', ]; async function ready() { for (let attempt = 0; attempt < 90; attempt++) { const state = JSON.parse(docker('inspect', name, '--format', '{{json .State}}')); assert.equal(state.Running, true, 'Image exited before readiness'); if (state.Health.Status === 'healthy') return; await new Promise((resolve) => setTimeout(resolve, 1000)); } throw new Error('Image readiness timed out'); } (async () => { docker('volume', 'create', name); try { assert.throws(() => docker('run', '--rm', '--read-only', image), 'Missing runtime configuration must prevent startup'); const migrate = () => docker('run', '--rm', '--read-only', '-v', `${name}:/data`, ...environment, image, 'node', 'node_modules/prisma/build/index.js', 'migrate', 'deploy'); migrate(); docker('run', '-d', '--name', name, '--read-only', '-v', `${name}:/data`, ...environment, image); await ready(); assert.deepEqual(JSON.parse(docker('inspect', name, '--format', '{{json .HostConfig.PortBindings}}')), {}); docker('exec', name, 'node', '-e', ` const assert = require('node:assert/strict'); const fs = require('node:fs'); assert.notEqual(process.getuid(), 0); assert.equal(fs.existsSync('src'), false); assert.equal(fs.existsSync('.env'), false); assert.equal(fs.existsSync('node_modules/typescript'), false); assert.equal(fs.existsSync('node_modules/@nestjs/cli'), false); fs.accessSync('dist/src/integrations/tbank/proto/contracts/users.proto'); fetch('http://localhost:3000/api/v1/auth/register', { method: 'POST', headers: {'content-type':'application/json'}, body: JSON.stringify({email:'image-smoke@example.test',password:'fictional-image-smoke-password'}) }).then(async r => {assert.equal(r.status, 200); await r.json()}).catch(e => {console.error(e); process.exitCode=1}); `); docker('stop', name); migrate(); docker('start', name); await ready(); docker('exec', name, 'node', '-e', ` const assert = require('node:assert/strict'); const db = require('better-sqlite3')('/data/wealthledger.db'); assert.equal(db.prepare('SELECT count(*) AS n FROM User').get().n, 1); assert.equal(db.prepare('SELECT count(*) AS n FROM Session').get().n, 1); assert.equal(db.pragma('integrity_check', {simple:true}), 'ok'); db.close(); `); console.log('PASS image: fresh/existing migration, non-root read-only runtime, auth, persistence, proto assets'); } finally { try { docker('rm', '-f', name); } finally { docker('volume', 'rm', name); } } })().catch((error) => { console.error(error); process.exitCode = 1; });