import assert from "node:assert/strict" import { randomUUID } from "node:crypto" import { basename, dirname, resolve } from "node:path" import { execFile } from "node:child_process" import { writeFile } from "node:fs/promises" assert.equal(process.env.MMAPP_OWN_DATABASE_SCHEMA_CONTROL, "true") const databaseUrl = new URL(process.env.DATABASE_URL ?? "") assert.equal(databaseUrl.hostname, "127.0.0.1"); assert.equal(databaseUrl.pathname, "/postgres") assert(process.env.MCP_STATE_DIR && basename(dirname(resolve(process.env.MCP_STATE_DIR))).startsWith("mm-mcp-test-")) const { Pool } = await import("pg") const { pool, closePool } = await import("./index.js") const { applySqlMigrations } = await import("./migrate.js") const { acquireDatabaseSchemaControl } = await import("./database-schema-control.js") const { initialDatabaseSchemaControlState, DatabaseSchemaControlError } = await import("./database-schema-control-model.js") const { runPrivateDatabaseDump } = await import("../services/database-dump-connection.js") const { restorePartitionedDatabase } = await import("../services/system-database-partition-restore.js") type ControlPool = Parameters[0] const names: string[] = [], cases: string[] = [], handles: Awaited>[] = [] const connections: InstanceType[] = [] async function database() { const name = "mm_control_" + randomUUID().replaceAll("-", "") assert(/^mm_control_[a-f0-9]{32}$/.test(name)) await pool.query('CREATE DATABASE "' + name + '" TEMPLATE template0') const url = new URL(databaseUrl); url.pathname = "/" + name const connection = new Pool({ connectionString: url.toString(), max: 6 }) names.push(name); connections.push(connection); return connection } async function seed(connection: InstanceType) { await connection.query("CREATE SCHEMA mmapp_control; CREATE TABLE mmapp_control.database_schema_state(id smallint PRIMARY KEY CHECK(id=1),revision bigint NOT NULL CHECK(revision>=0),state jsonb NOT NULL); CREATE TABLE mmapp_control.database_schema_intents(id uuid PRIMARY KEY,intent jsonb NOT NULL,terminal jsonb)") await connection.query("INSERT INTO mmapp_control.database_schema_state VALUES(1,0,$1::jsonb)", [JSON.stringify(initialDatabaseSchemaControlState())]) } async function acquire(connection: ControlPool) { const owner = await acquireDatabaseSchemaControl(connection); handles.push(owner); return owner } const command = () => ({ type: "begin" as const, id: randomUUID(), kind: "migration" as const, manifestSha256: "a".repeat(64), artifactSha256: "b".repeat(64) }) const terminal = (id: string, outcome: "observed-success" | "observed-failure" | "interrupted-unknown" = "observed-success") => ({ type: "terminal" as const, id, outcome, observationSha256: "c".repeat(64) }) const row = async (connection: InstanceType) => (await connection.query("SELECT revision::text,state FROM mmapp_control.database_schema_state WHERE id=1")).rows[0] const history = async (connection: InstanceType, id: string) => (await connection.query("SELECT intent,terminal FROM mmapp_control.database_schema_intents WHERE id=$1", [id])).rows[0] function lostCommit(connection: InstanceType, number: number): ControlPool { return { async connect() { const client = await connection.connect(); let commits = 0 return { release(destroy?: boolean) { client.release(destroy) }, async query(sql: string, values?: unknown[]) { const result = await client.query(sql, values) if (sql === "COMMIT" && ++commits === number) throw Error("owned fixture lost actual COMMIT acknowledgement") return { rows: result.rows, command: result.command } } } } } } function abortedCommit(connection: InstanceType, number: number): ControlPool { return { async connect() { const client = await connection.connect(); let commits = 0 return { release(destroy?: boolean) { client.release(destroy) }, async query(sql: string, values?: unknown[]) { if (sql === "COMMIT" && ++commits === number) { // A real aborted PostgreSQL transaction acknowledges COMMIT as ROLLBACK. await assert.rejects(client.query("SELECT 1/0")) } const result = await client.query(sql, values) return { rows: result.rows, command: result.command } } } } } } async function commandIo(program: string, args: string[]): Promise { return new Promise((resolve, reject) => { execFile(program, args, { encoding: "buffer", timeout: 30000, maxBuffer: 32 * 1048576, windowsHide: true }, (error, stdout) => error ? reject(Error("Owned PostgreSQL archive command failed: " + program)) : resolve(stdout)) }) } try { // The runner's separate terminal restore fixture uses this owned database. // Control protocol scenarios below each use their own independent database. await applySqlMigrations(pool) const missing = await database() await assert.rejects(acquire(missing), DatabaseSchemaControlError) assert.equal((await missing.query("SELECT count(*)::int AS n FROM pg_namespace WHERE nspname='mmapp_control'")).rows[0].n, 0) cases.push("missing external control refuses without startup DDL or enrollment") const regular = await database(); await seed(regular) let owner = await acquire(regular) const initial = await owner.read(); assert.equal(initial.state.epoch, 1); assert.equal(initial.revision, "1") assert.equal((await owner.admission()).ready, false) await assert.rejects(acquire(regular), DatabaseSchemaControlError) assert.deepEqual(await owner.read(), initial) cases.push("one checked-out session owns exclusive lease; another owner changes no epoch or revision") const begin = command(), intended = await owner.transition(begin) assert.equal(intended.revision, "2"); assert.equal(intended.state.phase, "INTENT") assert.deepEqual((await history(regular, begin.id)).intent, intended.state.intent) assert.equal((await owner.admission()).reason, "UNRESOLVED_INTENT") cases.push("intent singleton and unique immutable history publish atomically before application dispatch") await owner.close(); owner = await acquire(regular) assert.equal((await owner.read()).state.intent?.id, begin.id) await assert.rejects(owner.transition(terminal(begin.id)), DatabaseSchemaControlError) assert.equal((await history(regular, begin.id)).terminal, null) cases.push("restart preserves old intent and cannot claim an unobserved successful outcome") owner = await acquire(regular) const interrupted = await owner.transition(terminal(begin.id, "interrupted-unknown")) assert.equal(interrupted.state.terminal?.outcome, "interrupted-unknown") assert.equal((await owner.admission()).ready, false) assert.deepEqual((await history(regular, begin.id)).terminal, interrupted.state.terminal) cases.push("interrupted unknown can be recorded once but never enables consumers") const second = command(); await owner.transition(second); await owner.transition(terminal(second.id)) const prior = await row(regular) await assert.rejects(owner.transition(begin), DatabaseSchemaControlError) assert.deepEqual(await row(regular), prior) assert.equal((await regular.query("SELECT count(*)::int AS n FROM mmapp_control.database_schema_intents")).rows[0].n, 2) cases.push("reuse of an older completed operation is refused by actual unique history with no singleton advance") for (const stage of ["claim", "intent", "terminal"] as const) { const connection = await database(); await seed(connection) const wrapped = lostCommit(connection, stage === "claim" ? 1 : stage === "intent" ? 2 : 3) const intent = command() if (stage === "claim") await assert.rejects(acquire(wrapped), (error: unknown) => error instanceof DatabaseSchemaControlError && error.outcomeUnknown) else { const handle = await acquire(wrapped) if (stage === "terminal") await handle.transition(intent) await assert.rejects(handle.transition(stage === "intent" ? intent : terminal(intent.id)), (error: unknown) => error instanceof DatabaseSchemaControlError && error.outcomeUnknown) await assert.rejects(handle.read(), DatabaseSchemaControlError) } const fresh = await acquire(connection), observed = await fresh.read() assert.equal(observed.state.epoch, 2); assert.equal(observed.state.phase, "QUARANTINED") assert.equal((await fresh.admission()).ready, false) if (stage === "intent") { assert.equal(observed.state.intent?.id, intent.id); assert.equal((await history(connection, intent.id)).terminal, null) } if (stage === "terminal") { assert.equal(observed.state.intent, null); assert.equal(observed.state.terminal?.intent.id, intent.id); assert.equal(observed.state.terminal?.outcome, "observed-success") } await fresh.close() cases.push("actual server COMMIT with lost " + stage + " ACK destroys owner; restart preserves quarantine and durable observation") } for (const stage of ["claim", "intent", "terminal"] as const) { const connection = await database(); await seed(connection) const wrapped = abortedCommit(connection, stage === "claim" ? 1 : stage === "intent" ? 2 : 3) const intent = command() if (stage === "claim") await assert.rejects(acquire(wrapped), (error: unknown) => error instanceof DatabaseSchemaControlError && error.outcomeUnknown) else { const handle = await acquire(wrapped) if (stage === "terminal") await handle.transition(intent) await assert.rejects(handle.transition(stage === "intent" ? intent : terminal(intent.id)), (error: unknown) => error instanceof DatabaseSchemaControlError && error.outcomeUnknown) await assert.rejects(handle.read(), DatabaseSchemaControlError) } // Readback diagnoses the rolled-back publication without replaying it. const saved = await row(connection) assert.equal(saved.revision, stage === "claim" ? "0" : stage === "intent" ? "1" : "2") assert.equal((await history(connection, intent.id))?.terminal ?? null, null) assert.equal(saved.state.intent?.id ?? null, stage === "terminal" ? intent.id : null) const fresh = await acquire(connection) assert.equal((await fresh.admission()).ready, false) if (stage === "terminal") await assert.rejects(fresh.transition(terminal(intent.id)), DatabaseSchemaControlError) await fresh.close() cases.push("actual aborted " + stage + " transaction returns ROLLBACK command; owner discarded without successful publication or replay") } const altered = await database(); await seed(altered) const stale = await acquire(altered) await altered.query("UPDATE mmapp_control.database_schema_state SET revision=revision+1") await assert.rejects(stale.read(), DatabaseSchemaControlError) cases.push("external revision drift invalidates a live owner before admission") const corrupted = await database(); await seed(corrupted) const corruptOwner = await acquire(corrupted), corruptIntent = command(); await corruptOwner.transition(corruptIntent) await corrupted.query("UPDATE mmapp_control.database_schema_intents SET intent=jsonb_set(intent,'{artifactSha256}',to_jsonb($1::text)) WHERE id=$2", ["d".repeat(64), corruptIntent.id]) await assert.rejects(corruptOwner.read(), DatabaseSchemaControlError) await assert.rejects(acquire(corrupted), DatabaseSchemaControlError) cases.push("immutable history mismatch invalidates both current owner and new owner claim") const reset = await database(); await seed(reset) const resetOwner = await acquire(reset), resetIntent = command(); await resetOwner.transition(resetIntent) // This database was created by this test in the owned disposable cluster. await reset.query("CREATE TABLE public.owned_fixture(id integer); DROP SCHEMA public CASCADE; CREATE SCHEMA public") assert.equal((await resetOwner.read()).state.intent?.id, resetIntent.id) assert.equal((await history(reset, resetIntent.id)).terminal, null) cases.push("control epoch and unresolved history survive replacement of the public application namespace") const archiveDb = await database(); await seed(archiveDb) await archiveDb.query("CREATE TABLE public.servers(id integer PRIMARY KEY); CREATE TABLE public.schema_migrations(id text PRIMARY KEY); INSERT INTO public.servers VALUES(1)") const archiveOwner = await acquire(archiveDb), archiveIntent = command(); await archiveOwner.transition(archiveIntent) const originalState = await row(archiveDb), archiveUrl = new URL(databaseUrl); archiveUrl.pathname = "/" + names.at(-1)! const safeFile = resolve(process.env.MCP_STATE_DIR!, "control-excluded.dump"), unsafeFile = resolve(process.env.MCP_STATE_DIR!, "control-full.dump") const actualPrivateDump = await runPrivateDatabaseDump(archiveUrl.toString(), { authorize: async () => {} }) await writeFile(safeFile, actualPrivateDump, { flag: "wx", mode: 0o600 }) const toc = (await commandIo("pg_restore", ["--list", safeFile])).toString("utf8") assert(!toc.includes("mmapp_control")) await archiveDb.query("UPDATE public.servers SET id=2") let replacements = 0 await restorePartitionedDatabase(safeFile, archiveUrl.toString(), { command: commandIo, prepareSql: file => writeFile(file, "", { flag: "wx", mode: 0o600 }), beforeTargetReplacement: () => { replacements++ }, }) assert.equal(replacements, 1) assert.deepEqual((await archiveDb.query("SELECT id FROM public.servers")).rows, [{ id: 1 }]) assert.deepEqual(await row(archiveDb), originalState) assert.equal((await archiveOwner.read()).state.intent?.id, archiveIntent.id) cases.push("actual private pg_dump excludes control; actual application restore changes public data while preserving live owner epoch and intent") await commandIo("pg_dump", ["-Fc", "--file", unsafeFile, archiveUrl.toString()]) let archiveCommands = 0, preparations = 0 await assert.rejects(restorePartitionedDatabase(unsafeFile, archiveUrl.toString(), { command: async (program, args) => { archiveCommands++; return commandIo(program, args) }, prepareSql: async () => { preparations++ }, beforeTargetReplacement: () => { replacements++ }, })) assert.equal(archiveCommands, 1); assert.equal(preparations, 0); assert.equal(replacements, 1) assert.deepEqual(await row(archiveDb), originalState) cases.push("actual full archive containing control refuses immediately after TOC before SQL decode or target replacement") console.log("Owned database schema control SQL:", JSON.stringify({ cases: cases.length, names: cases, databases: names.length, actualSql: true, lostActualCommitAcks: 3, startupWired: false, readyAuthorized: false, productionDatabaseTouched: false })) } finally { for (const handle of handles) await handle.close().catch(() => {}) for (const connection of connections) await connection.end() await closePool() }