Files
MikrotikManager/backend/src/modules/mcp/operation-execution-origin.test.ts
T

163 lines
16 KiB
TypeScript

/** Real publisher/ALS/principal/policy/crypto with synthetic SQL boundaries. */
import assert from "node:assert/strict"
import { test } from "node:test"
import { randomUUID } from "node:crypto"
import { mkdtemp, realpath, writeFile, rm } from "node:fs/promises"
import { tmpdir } from "node:os"
import { join, dirname } from "node:path"
import { performance } from "node:perf_hooks"
import { setTimeout as delay } from "node:timers/promises"
import type { McpPrincipal } from "./store.js"
import type { McpConnectionPolicy } from "@mmapp/contracts/mcp"
import { principalSourceRowsForTests } from "../../test/mcp-principal-source-rows.js"
test("ordinary MCP operation publisher before legacy locks; actual private origin with synthetic SQL", async t => {
const parent = await realpath(tmpdir()), directory = await mkdtemp(join(parent, "mm-operation-root-")), prior = process.env.MCP_STATE_DIR
process.env.MCP_STATE_DIR = directory
const generation = Buffer.alloc(32, 91)
await writeFile(join(directory, "encryption-key"), Buffer.alloc(32, 83)); await writeFile(join(directory, "access-generation"), generation)
const { pool, closePool } = await import("../../db/index.js"), actualQuery = pool.query, actualConnect = pool.connect
const source = await import("./operation-execution-origin.js")
const { encryptSecret, fingerprint, redact } = await import("./security.js")
const { findActionByOperation } = await import("./actions.js")
const { withApplicationMutationLock, withConfigMutationLock } = await import("../../services/config-mutation-lock.js")
const { withOperationConfigurationLockClient } = await import("../../services/operation-config-lock-lease.js")
let row: Record<string, unknown> & { id: string; plan_id: string; connection_id: string; operation_state: string; plan_state: string; result: Record<string, unknown> | null; claim_nonce?: unknown; payload: { sealed: string }; owner_permissions: string[] }
let connection: Record<string, unknown> & { owner_id: string; owner_permissions: string[]; owner_claims_issued_at: Date; owner_valid_until: Date; policy: McpConnectionPolicy }
let cleanups = 0, audits = 0, calls = 0
let fault: "none" | "lost-own" | "lost-other" | "rows-only" = "none", claimGate: (() => Promise<void>) | undefined
const clone = <T>(value: T) => structuredClone(value)
const result = (command: string, rows: unknown[]) => ({ command, rowCount: rows.length, rows })
async function query(raw: string | { text: string; values?: unknown[] }, values?: unknown[]) {
calls++; const text = typeof raw === "string" ? raw : raw.text, args = typeof raw === "string" ? values ?? [] : raw.values ?? []
if (text.startsWith("/* mcp-principal:coherent-source-v1 */")) return result("SELECT", principalSourceRowsForTests(connection,
{ credentialId: String(args[0]), credentialExpiresAt: connection.owner_valid_until.toISOString() }, { includeGrants: args[2] === true }))
if (text.startsWith("SELECT pg_current_xact_id_if_assigned")) return result("SELECT", [{ creating_xid: "123" }])
if (text.startsWith("INSERT INTO mcp_operations")) { row.id = String(args[0]); row.plan_id = String(args[1]); row.connection_id = String(args[2]); return result("INSERT", [{ id: row.id, plan_id: row.plan_id, connection_id: row.connection_id, state: "pending", result: null }]) }
if (text.includes("AS creating_transaction")) return result("SELECT", [{ ...clone(row), creating_transaction: true }])
if (text.startsWith("SELECT id FROM mcp_credentials")) return result("SELECT", [{ id: args[0] }])
if (text.startsWith("SELECT * FROM mcp_connections")) return result("SELECT", [clone(connection)])
if (text.startsWith("SELECT invalid_before FROM mcp_owner_revocations")) return result("SELECT", [])
if (text.startsWith("SELECT enabled FROM mcp_settings")) return result("SELECT", [{ enabled: true }])
if (text.startsWith("/* mcp-operation-root:source */")) return result("SELECT", [clone(row)])
if (text.includes("FROM public.mcp_grants")) return result("SELECT", [])
if (text.startsWith("/* mcp-operation-root:claim */")) {
await claimGate?.()
if (fault === "lost-other") { row.operation_state = "running"; row.claim_nonce = randomUUID(); row.result = { [source.MCP_OPERATION_PRIVATE_CLAIM_KEY]: row.claim_nonce }; throw Error("Real zero-row ACK lost after rival winner (synthetic driver)") }
if (row.operation_state !== "pending") return result("UPDATE", [])
row.operation_state = "running"; row.claim_nonce = args[3]; row.result = { [source.MCP_OPERATION_PRIVATE_CLAIM_KEY]: args[3] }
if (fault === "lost-own") throw Error("Applied own claim ACK lost (synthetic driver)")
const ack = result("UPDATE", [{ id: row.id, plan_id: row.plan_id, connection_id: row.connection_id, state: "running", result: clone(row.result) }])
return fault === "rows-only" ? { rows: ack.rows } : ack
}
if (text.startsWith("UPDATE public.mcp_operations SET state='unknown'")) {
if (!(row.operation_state === "pending" && !row.claim_nonce || row.operation_state === "running" && row.claim_nonce === args[3])) return result("UPDATE", [])
cleanups++; row.operation_state = "unknown"; row.result = { needsReview: true, automaticRetry: false }; return result("UPDATE", [{ plan_id: row.plan_id }])
}
if (text.startsWith("UPDATE public.mcp_plans")) { row.plan_state = "completed"; return result("UPDATE", []) }
if (text.startsWith("INSERT INTO mcp_audit")) { audits++; return result("INSERT", []) }
if (text === "BEGIN" || text === "COMMIT") return result(text, [])
if (text.includes("pg_try_advisory_lock")) return result("SELECT", [{ acquired: true }])
if (text.includes("pg_advisory_unlock")) return result("SELECT", [{ released: true }])
throw Error("Unexpected fixture SQL family")
}
pool.query = query as never
const client = { query, release() {}, on() {}, removeListener() {} }
pool.connect = (async () => client) as never
async function fixture(ttl = 30000) {
fault = "none"; claimGate = undefined
const principal: McpPrincipal = { connectionId: randomUUID(), credentialId: randomUUID(), credentialExpiresAt: new Date(Date.now() + 60000).toISOString() }
const expires = Date.now() + ttl, id = randomUUID(), planId = randomUUID(), action = findActionByOperation("users.create")
const evidence = { target: { scope: "global" }, objects: [{ kind: "user", id: "owned-user" }], snapshots: [], warnings: [], steps: [0, 1].map(index => ({ kind: "service", service: "users.create", input: { index } })) }
const input = { user: { name: "owned private input" } }, payload = { sealed: await encryptSecret(JSON.stringify(input)) }, encryptedEvidence = { sealed: await encryptSecret(JSON.stringify(evidence)) }
connection = { id: principal.connectionId, name: "fixture", owner_id: "owned-root-owner", owner_permissions: ["mm:users:write"], generation: generation.toString("hex"), owner_claims_issued_at: new Date(Date.now() - 1000), owner_valid_until: new Date(expires + 1000),
policy: { id: principal.connectionId, version: 1, status: "active", expiresAt: new Date(expires + 1000).toISOString(), mode: "autonomous", permissions: ["mm:users:write"], scope: { serverIds: [], operationIds: ["users.create"], allowGlobal: true }, dangerousPolicy: "explicit-allow", autonomousDangerousOperationIds: ["users.create"], limits: { callsPerMinute: 60, concurrentReads: 4, mutationsPerHour: 10, serversPerPlan: 5, objectsPerPlan: 100 } } }
row = { id, plan_id: planId, connection_id: principal.connectionId, operation_state: "pending", plan_state: "executing", operation_id: "users.create", operation_version: action.operation.version, policy_version: 1,
generation: generation.toString("hex"), connection_generation: generation.toString("hex"), expires_at: new Date(expires), approved_by: null, owner_id: connection.owner_id, owner_permissions: connection.owner_permissions, owner_valid_until: connection.owner_valid_until, policy: connection.policy,
payload, evidence: encryptedEvidence, grants: [], protections: [], concurrent_reads: 0, result: null }
const grant = { proof: fingerprint({ credentialId: principal.credentialId, grant: null }), expiresAt: null, monotonicEnd: Infinity, admissionExpiresAt: expires, admissionMonotonicEnd: performance.now() + ttl }
const start = source.beginMcpOperationAdmission(principal), issued = await source.insertMcpOperationAdmission(client as never, start, planId, randomUUID(), grant)
return { id: issued.operation.id, principal, grant, input, evidence, admission: issued.admission }
}
const terminal = () => { row.operation_state = "applied"; row.plan_state = "completed"; row.result = { confirmedWrites: 2 } }
try {
await t.test("no ambient root, fake/copy tokens and unproved admission cannot mint", async () => {
await fixture(); const before = calls
await assert.rejects(source.captureMcpOperationExecutionOrigin()); await assert.rejects(source.readCurrentMcpOperationExecutionOrigin({}))
await assert.rejects(source.withMcpOperationExecutionOrigin({}, async () => { throw Error("must not enter") })); assert.equal(calls, before)
})
await t.test("publisher exposes whole private operation, fixed lifetime and deeply frozen multi-step evidence", async () => {
const f = await fixture(); let saved: unknown, signal: AbortSignal | undefined
await source.withMcpOperationExecutionOrigin(f.admission, async () => {
const token = await source.captureMcpOperationExecutionOrigin(); saved = token
const metadata = await source.readCurrentMcpOperationExecutionOrigin(token), lifetime = await source.inspectMcpOperationExecutionLifetime(token); signal = lifetime.signal
assert.equal(metadata.operationId, f.id); assert.equal(metadata.evidence.steps.length, 2); assert.deepEqual(metadata.privateInput, f.input); assert.deepEqual(metadata.resources, f.evidence.objects)
assert(!("stepIndex" in metadata)); assert(Object.isFrozen(metadata.evidence.steps)); assert.equal(lifetime.monotonicDeadline, (await source.inspectMcpOperationExecutionLifetime(token)).monotonicDeadline)
const before = calls; for (const fake of [{}, { ...token }, JSON.parse(JSON.stringify(token))]) await assert.rejects(source.readCurrentMcpOperationExecutionOrigin(fake)); assert.equal(calls, before)
terminal()
})
assert.equal(signal?.aborted, true); await assert.rejects(source.readCurrentMcpOperationExecutionOrigin(saved))
})
await t.test("late capture denied under each actual legacy ALS, existing root remains inspectable", async () => {
const f = await fixture()
await source.withMcpOperationExecutionOrigin(f.admission, async () => {
const token = await source.captureMcpOperationExecutionOrigin()
await withApplicationMutationLock(async () => { await assert.rejects(source.captureMcpOperationExecutionOrigin()); await source.readCurrentMcpOperationExecutionOrigin(token) })
await withConfigMutationLock([101, 102], async () => { await assert.rejects(source.captureMcpOperationExecutionOrigin()); await source.readCurrentMcpOperationExecutionOrigin(token) })
await withOperationConfigurationLockClient(client as never, () => {}, new AbortController().signal, async () => { await assert.rejects(source.captureMcpOperationExecutionOrigin()); await source.readCurrentMcpOperationExecutionOrigin(token) })
terminal()
})
})
await t.test("one-shot admitted dual workers cannot publish or enter legacy twice", async () => {
const f = await fixture(); let arrivals = 0, callbacks = 0
claimGate = async () => { arrivals++ }
const outcomes = await Promise.allSettled([0, 1].map(() => source.withMcpOperationExecutionOrigin(f.admission, async () => { callbacks++; terminal() })))
assert.equal(arrivals, 1); assert.equal(callbacks, 1); assert.equal(outcomes.filter(value => value.status === "rejected").length, 1); assert.equal(row.operation_state, "applied")
})
for (const kind of ["lost-own", "lost-other", "rows-only"] as const) await t.test(kind + " claim refuses before legacy callback, exact nonce owns cleanup", async () => {
const f = await fixture(), before = cleanups; fault = kind; let entered = false
await assert.rejects(source.withMcpOperationExecutionOrigin(f.admission, async () => { entered = true }))
assert.equal(entered, false); assert.equal(cleanups - before, kind === "lost-other" ? 0 : 1); assert.equal(row.operation_state, kind === "lost-other" ? "running" : "unknown")
})
await t.test("callback throw or nonterminal return closes only own running claim as unknown", async () => {
for (const fail of [false, true]) { const f = await fixture(), before = cleanups
const work = source.withMcpOperationExecutionOrigin(f.admission, async () => { if (fail) throw Error("Owned callback failed") })
if (fail) await assert.rejects(work); else await work
assert.equal(row.operation_state, "unknown"); assert.equal(cleanups, before + 1)
}
assert(audits > 0)
})
await t.test("same-byte directory clone and expired queued admission cannot revive or leave owned pending", async () => {
const f = await fixture(), cloneDirectory = await mkdtemp(join(parent, "mm-operation-root-clone-"))
try {
await writeFile(join(cloneDirectory, "access-generation"), generation); await writeFile(join(cloneDirectory, "encryption-key"), Buffer.alloc(32, 83))
process.env.MCP_STATE_DIR = cloneDirectory
await assert.rejects(source.withMcpOperationExecutionOrigin(f.admission, async () => { throw Error("must not run from clone") }))
assert.equal(row.operation_state, "unknown")
} finally { process.env.MCP_STATE_DIR = directory; assert.equal(dirname(await realpath(cloneDirectory)), parent); await rm(cloneDirectory, { recursive: true, force: true }) }
const expired = await fixture(500); await delay(550)
await assert.rejects(source.withMcpOperationExecutionOrigin(expired.admission, async () => { throw Error("must not run expired") })); assert.equal(row.operation_state, "unknown")
})
await t.test("current sealed source/claim nonce and current actor permission revoke retained root", async () => {
for (const fault of ["sealed", "nonce", "permission"] as const) { const f = await fixture()
await source.withMcpOperationExecutionOrigin(f.admission, async () => {
const token = await source.captureMcpOperationExecutionOrigin()
if (fault === "sealed") row.payload.sealed += "!"
if (fault === "nonce") { row.claim_nonce = randomUUID(); row.result = { [source.MCP_OPERATION_PRIVATE_CLAIM_KEY]: row.claim_nonce } }
if (fault === "permission") { connection.owner_permissions = []; row.owner_permissions = [] }
await assert.rejects(source.readCurrentMcpOperationExecutionOrigin(token))
})
}
})
await t.test("private nonce stripped from direct result and nested model/UI redaction; terminal results unchanged", async () => {
const value = { confirmedWrites: 2, [source.MCP_OPERATION_PRIVATE_CLAIM_KEY]: "PRIVATE-NONCE" }
assert.deepEqual(source.stripMcpOperationExecutionPrivateResult(value), { confirmedWrites: 2 })
assert.deepEqual(redact({ items: [{ result: value }], operation: { result: value } }), { items: [{ result: { confirmedWrites: 2 } }], operation: { result: { confirmedWrites: 2 } } })
assert(!JSON.stringify(redact(value)).includes("PRIVATE-NONCE")); assert.deepEqual(source.stripMcpOperationExecutionPrivateResult({ confirmedWrites: 2 }), { confirmedWrites: 2 })
})
} finally {
pool.query = actualQuery; pool.connect = actualConnect; process.env.MCP_STATE_DIR = prior; await closePool()
assert.equal(dirname(await realpath(directory)), parent); await rm(directory, { recursive: true, force: true })
}
})