Files
MikrotikManager/backend/src/db/controlled-schema-reference.sql.test.ts
T

165 lines
14 KiB
TypeScript

import assert from "node:assert/strict"
import { randomUUID } from "node:crypto"
import { fingerprint, privateSecretFingerprint } from "../modules/mcp/security.js"
import { basename, dirname, resolve } from "node:path"
import { readFile, writeFile } from "node:fs/promises"
assert.equal(process.env.MMAPP_OWN_CONTROLLED_SCHEMA_REFERENCE, "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 { MIGRATION_MANIFEST } = await import("./migration-manifest.js")
const { initialDatabaseSchemaControlState } = await import("./database-schema-control-model.js")
const { executeControlledSqlMigrations } = await import("./controlled-migrations.js")
const { provisionControlledSchemaReference, readControlledSchemaReference, ControlledSchemaReferenceProvisioningError } = await import("./controlled-schema-reference.js")
const { verifyControlledSchemaCurrentState, CONTROLLED_SCHEMA_VERIFICATION_SQL } = await import("./controlled-schema-verification.js")
const originalConnect = pool.connect.bind(pool), cases: string[] = []
let application: InstanceType<typeof Pool> | undefined
async function owned<T>(work: () => Promise<T>) {
assert(application)
pool.connect = application.connect.bind(application) as typeof pool.connect
try { return await work() } finally { pool.connect = originalConnect as typeof pool.connect }
}
try {
await applySqlMigrations(pool)
const name = "mm_reference_app_" + randomUUID().replaceAll("-", "")
assert(/^mm_reference_app_[a-f0-9]{32}$/.test(name))
await pool.query('CREATE DATABASE "' + name + '" TEMPLATE template0')
const url = new URL(databaseUrl); url.pathname = "/" + name
application = new Pool({ connectionString: url.toString(), max: 6 })
await application.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 application.query("INSERT INTO mmapp_control.database_schema_state VALUES(1,0,$1::jsonb)", [JSON.stringify(initialDatabaseSchemaControlState())])
assert.equal((await owned(executeControlledSqlMigrations)).completedFiles, MIGRATION_MANIFEST.length)
assert.equal(await readControlledSchemaReference(), null)
const missing = await owned(verifyControlledSchemaCurrentState)
assert.equal(missing.referenceStatus, "missing"); assert.equal(missing.ready, false); assert.equal(missing.dataFacts.length, 0)
cases.push("missing reference never promotes a controlled40 ledger or probes data as trusted schema")
const before = (await application.query("SELECT count(*)::int AS n FROM pg_database WHERE datname LIKE 'mm_schema_reference_%'")).rows[0].n
const generated = await owned(provisionControlledSchemaReference)
assert.equal(generated.referenceDatabaseDropped, true); assert.equal(generated.readyAuthorized, false)
assert.equal((await application.query("SELECT count(*)::int AS n FROM pg_database WHERE datname LIKE 'mm_schema_reference_%'")).rows[0].n, before)
const reference = await readControlledSchemaReference(); assert(reference)
assert.equal(reference.sha256, generated.logicalSchemaSha256)
assert.equal(reference.format, "pg18-application-schema-v3")
// Reconstruct the retired v2 algorithm from genuine current raw catalogs.
// This is test-only: numeric indkey/tombstones and old fast-default-only
// projection are intentional. Production never upgrades or accepts v2.
const canonical = (value: unknown): string => Array.isArray(value) ? "[" + value.map(canonical).join(",") + "]"
: value && typeof value === "object" ? "{" + Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, item]) => JSON.stringify(key) + ":" + canonical(item)).join(",") + "}"
: JSON.stringify(value) ?? "null"
const sortRows = <T>(rows: T[]): T[] => rows.map(row => canonical(row)).sort().map(row => JSON.parse(row) as T)
const legacySections = structuredClone(reference.sections)
legacySections.constraints = sortRows(legacySections.constraints.map(row => Object.fromEntries(Object.entries(row).filter(([key]) => key !== "restore_definition"))))
const legacyLogical = { ...legacySections, columns: sortRows(legacySections.columns.map(row => Object.fromEntries(Object.entries(row).filter(([key]) => key !== "has_missing" && key !== "missing_value")))) }
const legacyBody = { format: "pg18-application-schema-v2", scope: reference.scope, serverVersion: reference.serverVersion, sections: legacyLogical }
const legacySchema = { ...legacyBody, sections: legacySections, observedPhysical: reference.observedPhysical, canonical: canonical(legacyBody), sha256: fingerprint(legacyBody) }
const compatibilityFile = resolve(process.env.MCP_STATE_DIR!, "database-controlled-schema-reference-v1.json"), v3Bytes = await readFile(compatibilityFile)
const { signature: _v3Signature, canonicalSha256: _v3Canonical, ...v3Payload } = JSON.parse(v3Bytes.toString("utf8"))
const v2Payload = { ...v3Payload, schema: legacySchema }, v2Canonical = fingerprint(v2Payload)
const v2Bytes = Buffer.from(JSON.stringify({ ...v2Payload, canonicalSha256: v2Canonical, signature: await privateSecretFingerprint(v2Canonical, "database-controlled-schema-reference-v1") }) + "\n")
try {
await writeFile(compatibilityFile, v2Bytes)
await assert.rejects(readControlledSchemaReference(), /format\/version/)
await assert.rejects(owned(provisionControlledSchemaReference))
assert.deepEqual(await readFile(compatibilityFile), v2Bytes)
} finally { await writeFile(compatibilityFile, v3Bytes) }
assert.equal((await readControlledSchemaReference())?.sha256, reference.sha256)
cases.push("genuine raw-catalog legacy-v2 algorithm and fixed-issuer HMAC cannot bypass v3 refusal or overwrite existing reference; fresh v3 producer remains valid")
cases.push("fixed producer executes current pins in independently created database and drops only its verified owned UUID before publishing HMAC artifact")
await assert.rejects(owned(provisionControlledSchemaReference))
assert.equal((await readControlledSchemaReference())?.sha256, reference.sha256)
cases.push("existing trusted reference is not overwritten or regenerated by a repeat invocation")
const matching = await owned(verifyControlledSchemaCurrentState)
assert.equal(matching.referenceStatus, "matched")
assert.equal(matching.currentPristineDataInvariants, true, JSON.stringify({ data: matching.dataFacts.filter(f => !f.valid), sequences: matching.sequenceFacts.filter(f => !f.valid) }))
assert.equal(matching.ready, false); assert.equal(matching.historicalDataEquivalent, false)
cases.push("actual PG18 current schema matches independent issuer reference; exact pristine data and sequence invariants are checked without READY")
// Run the genuine fixed predicate on typed, temporary copies of already
// verified pristine rows. No production trigger is bypassed or altered.
const epochProbe = await application.connect()
try {
for (const table of ["traffic_settings", "uptime_settings", "internet_path_settings"]) {
await epochProbe.query('CREATE TEMP TABLE mm_owned_epoch_seed AS SELECT * FROM public."' + table + '"')
const timeFields = ["created_at", "updated_at"]
const seed = (await epochProbe.query("SELECT pg_catalog.to_jsonb(t)-ARRAY['created_at','updated_at','poll_configuration_epoch'] AS seed FROM pg_temp.mm_owned_epoch_seed t")).rows[0].seed
const original = CONTROLLED_SCHEMA_VERIFICATION_SQL.seed(table)
const relation = 'FROM public."' + table + '"'
assert.equal(original.split(relation).length, 2)
const probe = original.replace(relation, 'FROM pg_temp.mm_owned_epoch_seed')
const check = async () => (await epochProbe.query(probe, [JSON.stringify(seed), timeFields])).rows[0].valid
assert.equal(await check(), true)
for (const epoch of [null, "00000000-0000-0000-0000-000000000000", "12345678-1234-1234-9234-123456789abc", "12345678-1234-4234-7234-123456789abc"]) {
await epochProbe.query("UPDATE pg_temp.mm_owned_epoch_seed SET poll_configuration_epoch=$1::uuid", [epoch])
assert.equal(await check(), false)
}
await epochProbe.query("UPDATE pg_temp.mm_owned_epoch_seed SET poll_configuration_epoch=pg_catalog.gen_random_uuid()")
assert.equal(await check(), true)
await epochProbe.query("UPDATE pg_temp.mm_owned_epoch_seed SET enabled=false")
assert.equal(await check(), false)
await epochProbe.query("UPDATE pg_temp.mm_owned_epoch_seed SET enabled=true")
await epochProbe.query("ALTER TABLE pg_temp.mm_owned_epoch_seed ADD COLUMN unrelated_field integer DEFAULT 1")
assert.equal(await check(), false)
await epochProbe.query("DROP TABLE pg_temp.mm_owned_epoch_seed")
}
} finally { epochProbe.release(true) }
assert(matching.gaps.includes("NONDETERMINISTIC_POLL_EPOCH_ORIGIN_UNATTESTED"))
cases.push("actual typed SQL epoch predicates accept UUIDv4 only for three0042 seeds; null/nil/version/variant, changed settings and unknown columns refuse without historical-origin authority")
await application.query("INSERT INTO public.servers(host) VALUES('192.0.2.1')")
const changedData = await owned(verifyControlledSchemaCurrentState)
assert.equal(changedData.referenceStatus, "matched"); assert.equal(changedData.currentPristineDataInvariants, false)
assert(changedData.dataFacts.some(f => f.table === "servers" && !f.valid)); assert(changedData.sequenceFacts.some(f => !f.valid))
cases.push("actual added application row and advanced identity sequence fail pristine data evidence despite equal DDL")
await application.query("ALTER TABLE public.servers ADD COLUMN mm_owned_schema_drift integer")
const drift = await owned(verifyControlledSchemaCurrentState)
assert.equal(drift.referenceStatus, "different"); assert.equal(drift.dataFacts.length, 0)
cases.push("actual schema drift refuses trusted match before any data-probe classification")
const file = resolve(process.env.MCP_STATE_DIR!, "database-controlled-schema-reference-v1.json"), original = await readFile(file)
const oldEnvelope = JSON.parse(original.toString("utf8")); oldEnvelope.prefixLength = 39
await writeFile(file, JSON.stringify(oldEnvelope))
await assert.rejects(readControlledSchemaReference(), /artifact envelope/)
await writeFile(file, original)
cases.push("historical39 reference envelope cannot be promoted to current40 by startup or restore")
const fake = JSON.parse(original.toString("utf8")); fake.signature = "f".repeat(64)
await writeFile(file, JSON.stringify(fake))
await assert.rejects(readControlledSchemaReference())
const untrusted = await owned(verifyControlledSchemaCurrentState)
assert.equal(untrusted.referenceStatus, "invalid"); assert.equal(untrusted.dataFacts.length, 0); assert.equal(untrusted.ready, false)
await writeFile(file, original)
cases.push("forged artifact signature is refused by fixed reader and never authorizes data verification")
const initialStateDirectory = process.env.MCP_STATE_DIR!, faultDirectory = resolve(initialStateDirectory, "owned-reference-create-ack-loss")
let uncertainName = "", creates = 0, drops = 0
process.env.MCP_STATE_DIR = faultDirectory
pool.connect = (async () => {
const client = await application!.connect()
return { release(destroy?: boolean) { client.release(destroy) }, async query(text: string, values?: unknown[]) {
if (text.startsWith("DROP DATABASE ")) drops++
const result = await client.query(text, values)
if (text.startsWith('CREATE DATABASE "mm_schema_reference_')) {
const match = /^CREATE DATABASE "(mm_schema_reference_[a-f0-9]{32})"/.exec(text); assert(match)
uncertainName = match[1]; creates++
throw Error("Owned fixture lost actual reference CREATE acknowledgement")
}
return result
} }
}) as typeof pool.connect
try {
await assert.rejects(provisionControlledSchemaReference(), (error: unknown) => error instanceof ControlledSchemaReferenceProvisioningError && error.referenceDatabase === uncertainName && error.phase === "create-unknown" && !error.publicationAttempted && !error.automaticRetry)
assert.equal(creates, 1); assert.equal(drops, 0); assert.equal(await readControlledSchemaReference(), null)
} finally { pool.connect = originalConnect as typeof pool.connect; process.env.MCP_STATE_DIR = initialStateDirectory }
assert(/^mm_schema_reference_[a-f0-9]{32}$/.test(uncertainName))
const orphan = (await application.query("SELECT datname,pg_get_userbyid(datdba)=current_user AS owned FROM pg_database WHERE datname=$1", [uncertainName])).rows
assert.deepEqual(orphan, [{ datname: uncertainName, owned: true }])
// Explicit test-owner cleanup after independently proving the exact UUID.
// The production producer itself never retries or force-cleans unknown CREATE.
await application.query('DROP DATABASE "' + uncertainName + '"')
cases.push("actual CREATE with lost ACK publishes no reference and never retries or drops uncertain database; test owner independently cleans verified UUID")
console.log("Owned controlled schema reference SQL:", JSON.stringify({ cases: cases.length, names: cases, actualSql: true, referenceGeneratedByRealProducer: true, independentPinnedFiles: MIGRATION_MANIFEST.length, applicationPinnedFiles: MIGRATION_MANIFEST.length, readyAuthorized: false, startupWired: false, productionDatabaseTouched: false }))
} finally {
pool.connect = originalConnect as typeof pool.connect
await application?.end()
await closePool()
}