Files
MikrotikManager/backend/src/modules/mcp/integration.test.ts
T

3738 lines
394 KiB
TypeScript

import assert from "node:assert/strict"
import { attestRoutingFixture } from "../../test/mcp-routing-fixture.js"
import { fixtureGrantExpiry } from "../../test/mcp-fixture-expiry.js"
import { verifyMcpGrantExpiryBounds } from "../../test/mcp-grant-expiry-bounds.js"
import { createHash, createHmac, randomUUID } from "node:crypto"
import { performance } from "node:perf_hooks"
import { fileURLToPath } from "node:url"
import { createServer } from "node:http"
import { setTimeout as delay } from "node:timers/promises"
import { pool, closePool } from "../../db/index.js"
import { applySqlMigrations } from "../../db/migrate.js"
import { mcpConnectionCreateSchema } from "@mmapp/contracts/mcp"
import { createMcpConnection, authenticateMcpToken, updateMcpSettings, rotateConnectionToken, setConnectionStatus, revalidateMcpOwner, effectiveMcpConnection } from "./store.js"
import { invokeMcpTool, approvePlan, applyPlan, recoverMcpOperations } from "./runtime.js"
import { decryptSecret, encryptSecret, invalidateMcpAccess, tokenDigest } from "./security.js"
import { addRoutingDependencies } from "./routing-dependencies.js"
import { acceptOspfRouteProofMcp } from "./ospf-route-proof-acceptance.js"
import { acceptWireguardInterfaceDeletion } from "./wireguard-interface-delete-acceptance.js"
import { acceptWireguardPeerUpdate } from "./wireguard-peer-update-acceptance.js"
import { acceptWireguardPeerDeletion } from "./wireguard-peer-delete-acceptance.js"
import { acceptGreRevisionRestore } from "../../test/mcp-gre-revision.js"
import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client"
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio"
import type { AuthUser } from "../../lib/permissions.js"
import { managedComment } from "../../managed-markers.js"
import { compileManagedFilterRules } from "../../services/filter-rules-write-model.js"
// One fixed authority deadline for the long integration suite; never renewed during the run.
const fixtureAuthExpiresAt = Date.now() + 4 * 60 * 60 * 1000
const actor: AuthUser = { id: "integration-owner", email: "[email protected]", name: "Test", apps: ["mm"], permissions: ["mm:settings:admin", "mm:certificates:write", "mm:network:admin", "mm:bgp:admin", "mm:servers:admin", "mm:filters:admin"], expiresAt: fixtureAuthExpiresAt }
let settings = { "rp-filter": "no", "tcp-syncookies": "no", "ipv4-multipath-hash-policy": "l3" }, writes = 0
let reconcileReadHook: (() => Promise<unknown>) | undefined
let reconcileSettingsReads = 0
const emptyEvoCatalog = { modules: { items: [] }, domains: { items: [] }, ip_ranges: { items: [] }, asns: { items: [] }, communities: { items: [] } }
let evoCatalogPayload: unknown = emptyEvoCatalog, evoCatalogCalls = 0, evoCatalogAuthorization: string | undefined, evoCatalogRedirect = false
let evoProbePayload: unknown = { items: [] }, evoProbeCalls = 0, evoProbeAuthorization: string | undefined, evoProbeRedirect = false
let bridge = { ".id": "*fixture", name: "fixture-bridge", comment: "baseline", disabled: "true" }
let healthState = true, failHealthAfterWrite = false, healthUnavailable = false, loseHealthResponse = false
let healthBfdRemote = "192.0.2.2%fixture-ospf"
let fixtureRouteTable: string | undefined
let fixtureRoutingRules: Record<string, string>[] = []
let interfaceFixtures = false, ignoreVrfPlacement = false, vrfWrites = 0
let fixtureVrfs: Record<string, string>[] = []
// Preparation-only native catalogs for the business alias assertions. The
// genuine owned component separately proves actual alias-only execution.
let nativeAliasFixtures = false
const nativeAliasCatalogs: Record<string, unknown> = {
"/rest/ip/vrf": [{ ".id": "*abc", name: "managed-vrf", interfaces: "fixture-gre", disabled: "false", comment: "MikrotikManager: integration" }, { ".id": "*0", name: "main", interfaces: "all", disabled: "false", builtin: "true" }],
"/rest/interface": [{ ".id": "*b1", name: "fixture-gre", type: "gre-tunnel", vrf: "managed-vrf" }, { ".id": "*b2", name: "fixture-bridge", type: "bridge", vrf: "main" }],
"/rest/interface/gre": [{ ".id": "*a1", name: "fixture-gre", disabled: "false", "local-address": "192.0.2.1", "remote-address": "198.51.100.2" }],
"/rest/interface/bridge": [{ ".id": "*a2", name: "fixture-bridge", disabled: "false" }],
"/rest/ip/address": [{ ".id": "*a3", address: "192.0.2.1/30", interface: "fixture-bridge", vrf: "main", dynamic: "false", disabled: "false" }],
"/rest/ip/route": [{ ".id": "*a4", "dst-address": "192.0.2.0/30", "routing-table": "main", gateway: "fixture-bridge", "immediate-gw": "fixture-bridge", dynamic: "true", connect: "true" }],
"/rest/routing/table": [{ ".id": "*0", name: "main", fib: "true", dynamic: "true" }, { ".id": "*abc", name: "managed-vrf", fib: "", dynamic: "true" }],
"/rest/ip/settings": {}, "/rest/ipv6/settings": {},
}
let ospfFixtures = false
let ospfAnalysisFixtures = false, ospfAnalysisDispatches = 0, ospfAnalysisNativeRequests = 0
let ospfAfterCostPatch: (() => void) | undefined
let ospfAnalysisExtraNeighbors: Record<string, string>[] = []
const ospfAnalysisAddresses = [{ ".id": "*la", interface: "fixture-gre", address: "192.0.2.1/30", disabled: "false", invalid: "false" }]
let ospfCostWriteFault = "none"
let ospfPassiveWrites = 0, ospfIgnoreUnset = false
let ospfPreviewPauseConnection:string|undefined
let countCatalogCalls = false, catalogCalls = 0, ospfTemplateFlagReads = 0
let ospfPauseOnTemplatesConnection: string | undefined
let ospfTemplateListsBeforePause = 0
let greCatalogFixtures = false
let recursiveCatalogFixtures = false, recursivePropertyFailure = false
let recursiveCatalogRows: Record<string, unknown>[] = []
let recursiveMutations = false, recursiveMutationCount = 0, recursiveIgnorePayload = false
let recursivePauseConnection: string | undefined
let deviceStateFixtures = false, containerStateFailure: "none" | "envs" | "unsupported" = "none", certificateClockKnown = true
let reverseContainerRows = false
let certificateStateMalformed = false
let filterCatalogFixtures = false, filterCatalogMalformed = false
let legacyRouteContextFixture = false
const legacyRouteContextRows: Record<string, Record<string, unknown>[]> = {
"/routing/table": [{ ".id": "*main", name: "main", fib: "true", dynamic: "true" }],
"/ip/vrf": [{ ".id": "*vrf", name: "main", interfaces: "all", disabled: "false" }],
"/routing/bgp/connection": [{ ".id": "*peer", name: "legacy-peer", instance: "legacy", vrf: "main", "routing-table": "main", afi: "ip", "input.filter": "bgp-in", "output.filter-chain": "", templates: "", disabled: "false" }],
"/routing/bgp/instance": [{ ".id": "*instance", name: "legacy", vrf: "main", "routing-table": "main", disabled: "false" }],
"/routing/bgp/template": [],
"/routing/filter/rule": [{ ".id": "*filter", chain: "bgp-in", rule: compileManagedFilterRules([{ community: "65000:10", gateway: "192.0.2.1", outIface: "", action: "route", description: "" }]), comment: managedComment("test-router"), disabled: "false" }],
"/ip/route": [{ ".id": "*1", "dst-address": "192.0.2.1/32", "routing-table": "main", comment: managedComment("recursive"), disabled: "false" }],
"/routing/ospf/instance": [], "/routing/rip/instance": [], "/routing/isis/instance": [], "/routing/filter/select-rule": [], "/routing/bgp/vpn": [], "/routing/rule": [], "/ip/firewall/mangle": [], "/ipv6/firewall/mangle": [],
}
let greMutationFixtures = false, greMutationIgnored = false, greMutationLost = false, greMutationCommands = 0, greMutationNextId = 100
let greMutationRevoke: string | undefined
let greRevisionAfterCommand: (()=>Promise<void>) | undefined
let greRevisionReads=0
let greNativeCounterTick = false
let greNativeRouteReads = 0, greNativeLateDynamicAt = 0
let greMutationCollections: Record<string, Record<string,string>[]> = {}
let greMutationDependencies: Record<string, Record<string,string>[]> = {}
let preflightFixtures: Record<string, unknown> | undefined, preflightUnavailable = ""
let containerMutationFixtures = false, containerDeletes = 0, containerCommands = 0, ignoreContainerDelete = false, replaceContainerAfterCommand = false
let mutableContainers: Record<string, unknown>[] = []
const containerParent: { ".id": string; name: string; type: string; disabled?: string } = { ".id": "*veth", name: "fixture-veth", type: "veth", disabled: "false" }
let ecmpFixtures = false, ecmpWrites = 0, loseEcmpGateway = false
let fixtureEcmpRoutes: Record<string, string>[] = []
let wanFixtures = false, wanAddressFailure = false
let probeInterfaceFixtures = false, probeNativeCalls = 0, probeReadFailure = false
let liveFixtures = false, liveNativeCalls = 0, liveIncomplete = false
let liveRevokeConnection: string | undefined, liveChangeSource = false
let firewallStateFixtures = false, firewallStateCalls = 0, firewallKnownFlags = false, firewallFailedChunk = "", firewallDuplicate = false
let fwRestoreFixtures = false, fwRestoreCommands = 0, fwRestoreNextId = 1, fwRestoreIgnored = false, fwRestoreLost = false
let fwRestoreRevoke: string | undefined
let fwRestoreCollections: Record<string, Record<string, string>[]> = {}
let addressFixtures = false, addressCommands = 0, addressIgnored = false, addressExpiry = 0
let addressRows: Record<string, string>[] = []
let firewallWriteFixtures = false, firewallWriteCommands = 0, firewallWriteIgnored = false
let firewallWriteRows: Record<string, string>[] = []
let firewallMoveFixtures = false, firewallMoveCommands = 0, firewallIgnoreMove = false
let firewallMoveRows = [1, 2, 3].map(id => ({ ".id": "*" + id, chain: "fixture-move", action: "accept", disabled: "true", dynamic: "false", log: "false", comment: "rule " + id, packets: "0", "connection-mark": "keep-exactly" }))
let vpnFixtures = false, vpnFailurePath = "", vpnAmbiguous = false, vpnUnknownSession = false, vpnDuplicate = false
const vpnCalls: string[] = [], vpnPrivate = "never-return-wg-private-fixture", vpnPsk = "never-return-ipsec-psk-fixture"
const wanDefault = { ".id": "*wan", "dst-address": "0.0.0.0/0", "routing-table": "main", active: "true", distance: "1", gateway: "192.0.2.1", "immediate-gw": "192.0.2.1%ether1" }
let wanRoutes: Record<string, string>[] = [wanDefault]
const fixtureOspf: Record<"instance" | "area" | "interface-template", Record<string, string>[]> = {
instance: [{ ".id": "*ospf", name: "fixture-ospf", vrf: "main", "router-id": "192.0.2.1", version: "2", disabled: "false" }],
area: [{ ".id": "*area", name: "fixture-area", instance: "fixture-ospf", disabled: "false", "area-id": "0.0.0.0" }],
"interface-template": [{ ".id": "*template", area: "fixture-area", interfaces: "fixture-gre", cost: "30", disabled: "false", "use-bfd": "true" }],
}
let bgpFixtures = false
let bgpSessionOverride: unknown = undefined
const fixtureBgp = {
instance: [{ ".id": "*bgp", name: "fixture-bgp", vrf: "main", "routing-table": "main", as: "64512", "router-id": "192.0.2.1", disabled: "false" }],
connection: [{ ".id": "*peer", name: "fixture-peer", instance: "fixture-bgp", "remote.address": "192.0.2.2", "local.address": "192.0.2.1", "remote.as": "64513", "local.role": "ebgp", disabled: "false" }],
session: [{ ".id": "*session", name: "fixture-peer-1", instance: "fixture-bgp", established: "true", "remote.address": "192.0.2.2", "remote.as": "64513", "local.as": "64512", "local.afi": "ip,ipv6", "remote.afi": "ip,ipv6" }],
}
const router = createServer((req, res) => {
if (nativeAliasFixtures) {
res.setHeader("content-type", "application/json")
if (req.method !== "GET") { vrfWrites++; res.statusCode = 405; res.end("{}"); return }
res.end(JSON.stringify(nativeAliasCatalogs[req.url ?? ""] ?? [])); return
}
if (ospfAnalysisFixtures) ospfAnalysisNativeRequests++
if (legacyRouteContextFixture) {
const path = (req.url ?? "").replace(/^\/rest/, ""), collection = path.endsWith("/get") ? path.slice(0, -4) : path
if (collection in legacyRouteContextRows) {
res.setHeader("content-type", "application/json")
if (req.method === "GET" && path === collection) { res.end(JSON.stringify(legacyRouteContextRows[collection])); return }
if (req.method === "POST" && path.endsWith("/get")) {
let raw = ""; req.on("data", chunk => { raw += chunk }); req.on("end", () => {
const args = JSON.parse(raw), row = legacyRouteContextRows[collection].find(item => item[".id"] === args[".id"]), value = row?.[args["value-name"]]
res.end(JSON.stringify(value === undefined ? [] : { ret: value }))
}); return
}
res.statusCode = 405; res.end("{}"); return
}
}
if (req.url === "/v1/modules?limit=1") {
evoProbeCalls++; evoProbeAuthorization = req.headers.authorization
if (evoProbeRedirect) { res.writeHead(302, { Location: "/probe-redirect-target" }); res.end(); return }
res.setHeader("content-type", "application/json"); res.end(JSON.stringify(evoProbePayload)); return
}
if (req.url === "/v1/router-lists/catalog") {
evoCatalogCalls++; evoCatalogAuthorization = req.headers.authorization
if (evoCatalogRedirect) { res.writeHead(302, { Location: "/catalog-redirect-target" }); res.end(); return }
res.setHeader("content-type", "application/json"); res.end(JSON.stringify(evoCatalogPayload)); return
}
if (countCatalogCalls) catalogCalls++
if (vpnFixtures && req.method === "GET") {
const path = req.url ?? ""
vpnCalls.push(path); res.setHeader("content-type", "application/json")
if (path === vpnFailurePath) { res.statusCode = 503; res.end("{}"); return }
const wg = [{ ".id": "*wg1", name: "wg1", "private-key": vpnPrivate, comment: vpnPrivate, disabled: "false", running: "true", "listen-port": "13231", mtu: "1420" }, { ".id": "*wg2", name: "wg2" }]
const identity = { ".id": "*I1", peer: "ike", "auth-method": "pre-shared-key", "remote-id": "key-id:alice", secret: vpnPsk, comment: "MikrotikManager:ipsec user=" + vpnPsk }
const collections: Record<string, unknown[]> = {
"/rest/interface/gre": vpnDuplicate ? [{ ".id": "*G", name: "gre" }, { ".id": "*G", name: "gre" }] : [{ ".id": "*G", name: "gre", disabled: "false", running: "true", "ipsec-secret": vpnPsk, comment: vpnPsk, mtu: "1400", keepalive: "10s,10" }, { ".id": "*U", name: "unknown" }],
"/rest/interface/wireguard": vpnDuplicate ? [wg[0], wg[0]] : wg,
"/rest/interface/wireguard/peers": [1, 2, 3, 4].map(id => ({ ".id": "*P" + id, interface: id === 4 ? "wg2" : "*wg1", "public-key": "public-" + id, "preshared-key": vpnPsk, name: vpnPsk, rx: "0", "persistent-keepalive": "0", disabled: "false", "allowed-address": "192.0.2.0/24,198.51.100.0/24,fd00::/64" })),
"/rest/ip/address": [{ ".id": "*a", interface: "*wg1", address: "192.0.2.1/24", disabled: "false", dynamic: "false", invalid: "false" }], "/rest/ipv6/address": [1, 2, 3].map(id => ({ ".id": "*a" + id, interface: id === 1 ? "*G" : "gre", address: "fd00::" + id + "/64", disabled: "false", dynamic: "false", invalid: "false" })),
"/rest/interface/vxlan": [{ ".id": "*vx1", name: "vx1", vni: "100", port: "4789", mtu: "1420", l2mtu: "65535", arp: "enabled", learning: "true", disabled: "false", running: "true" }],
"/rest/interface/vxlan/vteps": [1, 2, 3].map(id => ({ ".id": "*v" + id, interface: "*vx1", "remote-ip": "198.51.100." + id })),
"/rest/ip/ipsec/peer": [{ ".id": "*ike", name: "ike", "exchange-mode": "ike2", passive: "true", certificate: "ipsec-server" }],
"/rest/ip/ipsec/identity": vpnAmbiguous ? [identity, { ...identity, ".id": "*I2", comment: "MikrotikManager:ipsec user=second" }] : [identity],
"/rest/ip/ipsec/active-peers": [{ ".id": "*active", id: "alice", ...(vpnUnknownSession ? {} : { state: "established" }), "remote-address": "192.0.2.2" }],
"/rest/certificate": [{ ".id": "*CA", name: "ipsec-ca", "key-usage": "key-cert-sign,crl-sign", authority: "true", trusted: "false", "private-key": "true" }, { ".id": "*CRT", name: "ipsec-server", "key-usage": "tls-server", "common-name": "vpn.example.invalid", ca: "ipsec-ca", "invalid-after": "oct/31/2026 12:00:00", trusted: "false", "private-key": "true" }],
}
res.end(JSON.stringify(collections[path] ?? [])); return
}
if (fwRestoreFixtures && /^\/rest\/(?:ip|ipv6)\/firewall\//.test(req.url ?? "")) {
res.setHeader("content-type", "application/json")
const path = decodeURIComponent(req.url ?? ""), getPath = path.endsWith("/get"), base = getPath ? path.slice(0, -4) : path.replace(/\/\*[A-Za-z0-9]+$/, ""), id = path.slice(base.length + 1)
const rows = fwRestoreCollections[base] ?? (fwRestoreCollections[base] = [])
if (req.method === "GET") { res.end(JSON.stringify(rows)); return }
let body = ""; req.on("data", chunk => { body += chunk }); req.on("end", async () => {
const data = body ? JSON.parse(body) : {}
if (getPath) { res.end(JSON.stringify({ ret: rows.find(row => row[".id"] === data[".id"])?.[data["value-name"]] ?? "false" })); return }
fwRestoreCommands++
const fields = Object.fromEntries(Object.entries(data).map(([key, value]) => [key, ["disabled", "log"].includes(key) ? value === "yes" ? "true" : "false" : value])) as Record<string, string>
if (req.method === "PUT" && !fwRestoreIgnored) rows.push({ ".id": "*NEW" + fwRestoreNextId++, dynamic: "false", disabled: "false", ...(base.endsWith("address-list") ? {} : { log: "false" }), ...fields })
if (req.method === "DELETE") fwRestoreCollections[base] = rows.filter(row => row[".id"] !== id)
if (req.method === "PATCH") Object.assign(rows.find(row => row[".id"] === id)!, fields)
if (fwRestoreRevoke) { const connectionId = fwRestoreRevoke; fwRestoreRevoke = undefined; await setConnectionStatus(connectionId, "paused", actor) }
if (fwRestoreLost) { fwRestoreLost = false; res.destroy(); return }
res.end("{}")
}); return
}
if (addressFixtures && /^\/rest\/(?:ip|ipv6)\/firewall\//.test(req.url ?? "")) {
res.setHeader("content-type", "application/json"); const path = decodeURIComponent(req.url ?? ""), base = "/rest/ip/firewall/address-list"
if (req.method === "GET") { res.end(JSON.stringify(path === base ? addressRows.map(row => row[".id"] === "*T" ? { ...row, timeout: Math.max(1, Math.floor((addressExpiry - Date.now()) / 1000)) + "s" } : row) : [])); return }
let body = ""; req.on("data", chunk => { body += chunk }); req.on("end", () => {
const data = body ? JSON.parse(body) : {}
if (path === base + "/get") { res.end(JSON.stringify({ ret: "false" })); return }
addressCommands++
if (!addressIgnored) {
const fields = Object.fromEntries(Object.entries(data).map(([key, value]) => [key, key === "disabled" ? value === "yes" ? "true" : "false" : key === "address" ? String(value).replace(/\/32$/, "") : value])) as Record<string, string>
if (req.method === "PUT") { const id = fields.timeout ? "*T" : "*C"; addressRows.push({ ".id": id, dynamic: fields.timeout ? "true" : "false", disabled: "false", ...fields }); if (fields.timeout) addressExpiry = Date.now() + 60000 }
if (req.method === "PATCH") Object.assign(addressRows.find(row => row[".id"] === path.slice(base.length + 1))!, fields)
if (req.method === "DELETE") addressRows = addressRows.filter(row => row[".id"] !== path.slice(base.length + 1))
}
res.end("{}")
}); return
}
if (firewallWriteFixtures && /^\/rest\/(?:ip|ipv6)\/firewall\//.test(req.url ?? "")) {
res.setHeader("content-type", "application/json")
const path = decodeURIComponent(req.url ?? ""), base = "/rest/ip/firewall/filter"
if (req.method === "GET") { res.end(JSON.stringify(path === base ? firewallWriteRows : [])); return }
let body = ""; req.on("data", chunk => { body += chunk }); req.on("end", () => {
const data = body ? JSON.parse(body) : {}
if (path === base + "/get") { res.end(JSON.stringify({ ret: "false" })); return }
firewallWriteCommands++
if (!firewallWriteIgnored) {
const fields = Object.fromEntries(Object.entries(data).map(([k, v]) => [k, ["disabled", "log"].includes(k) ? v === "yes" ? "true" : "false" : v])) as Record<string, string>
if (req.method === "PUT") firewallWriteRows.push({ ".id": "*C", dynamic: "false", log: "false", disabled: "false", ...fields })
if (req.method === "PATCH") Object.assign(firewallWriteRows.find(row => row[".id"] === path.slice(base.length + 1))!, fields)
if (req.method === "DELETE") firewallWriteRows = firewallWriteRows.filter(row => row[".id"] !== path.slice(base.length + 1))
}
res.end("{}")
}); return
}
if (firewallMoveFixtures && /^\/rest\/(?:ip|ipv6)\/firewall\//.test(req.url ?? "")) {
res.setHeader("content-type", "application/json")
if (req.url === "/rest/ip/firewall/filter/move") {
let body = ""; req.on("data", chunk => { body += chunk }); req.on("end", () => {
const input = JSON.parse(body); firewallMoveCommands++
if (!firewallIgnoreMove) {
const row = firewallMoveRows.find(row => row[".id"] === input.numbers)!
firewallMoveRows = firewallMoveRows.filter(item => item !== row)
const index = input.destination ? firewallMoveRows.findIndex(row => row[".id"] === input.destination) : firewallMoveRows.length
firewallMoveRows.splice(index, 0, row)
}
res.end("{}")
}); return
}
if (req.url === "/rest/ip/firewall/filter") {
for (const row of firewallMoveRows) row.packets = String(Number(row.packets) + 1)
res.end(JSON.stringify(firewallMoveRows)); return
}
res.end("[]"); return
}
if (firewallStateFixtures && /^\/rest\/(?:ip|ipv6)\/firewall\/(?:filter|nat|mangle|raw|address-list)$/.test(req.url ?? "")) {
firewallStateCalls++; res.setHeader("content-type", "application/json")
if (req.url === firewallFailedChunk) { res.statusCode = 503; res.end("{}"); return }
const flags = firewallKnownFlags ? { disabled: "false", dynamic: "false", log: "false" } : {}
const row = req.url!.endsWith("address-list") ? { ".id": "*list", list: "fixture-list", address: "192.0.2.1", ...flags }
: { ".id": "*rule", chain: "forward", action: "accept", packets: "0", "src-address-list": "fixture-list", "dst-address": "192.0.2.0/24", "in-interface": "ether1", "out-interface": "ether2", password: "never-return-firewall-key", ...flags }
res.end(JSON.stringify(firewallDuplicate && req.url === "/rest/ip/firewall/filter" ? [row, row] : [row])); return
}
if (liveFixtures && ["/rest/interface", "/rest/interface/monitor-traffic"].includes(req.url ?? "")) {
liveNativeCalls++; res.setHeader("content-type", "application/json")
if (req.url === "/rest/interface") {
res.end(JSON.stringify(["ether1", "ether2", "lo"].map(name => ({ name, running: "true", disabled: "false" })))); return
}
let body = ""
req.on("data", chunk => { body += chunk })
req.on("end", () => {
const payload = JSON.parse(body), names = String(payload.interface).split(",")
assert.equal(payload.once, "")
const rows = names.slice(0, liveIncomplete ? 1 : undefined).map(name => ({ name, "rx-bits-per-second": "1000000", "tx-bits-per-second": "0", password: "never-return-live-key" }))
const update = liveRevokeConnection ? pool.query("UPDATE mcp_connections SET policy=jsonb_set(policy,'{status}','\"paused\"'::jsonb) WHERE id=$1", [liveRevokeConnection])
: liveChangeSource ? pool.query("UPDATE servers SET updated_at=now() WHERE id=1") : Promise.resolve()
void update.then(() => res.end(JSON.stringify(rows))).catch(() => { res.statusCode = 500; res.end("{}") })
}); return
}
if (probeInterfaceFixtures && ["/rest/interface", "/rest/interface/get", "/rest/ip/address"].includes(req.url ?? "")) {
probeNativeCalls++; res.setHeader("content-type", "application/json")
if (probeReadFailure) { res.statusCode = 503; res.end("{}"); return }
if (req.url === "/rest/interface/get") { req.resume(); req.on("end", () => res.end(JSON.stringify({ ret: "false" }))); return }
const rows = req.url === "/rest/interface" ? [{ ".id": "*p1", name: "ether1", running: "true", disabled: "false" }, { ".id": "*p2", name: "gre-probe", running: "true" }, { ".id": "*p3", name: "unknown-probe", disabled: "false" }]
: [{ ".id": "*a1", interface: "ether1", address: "192.0.2.10/24", disabled: "false", invalid: "false", dynamic: "false", "private-key": "never-return-probe-key" }]
res.end(JSON.stringify(rows)); return
}
if (ospfAnalysisFixtures && req.url === "/rest/ip/address") { res.setHeader("content-type", "application/json"); res.end(JSON.stringify(ospfAnalysisAddresses)); return }
if (ospfFixtures && req.url?.startsWith("/rest/routing/ospf/interface-template") && ["PUT", "PATCH", "DELETE"].includes(req.method ?? "") || ospfFixtures && req.url === "/rest/routing/ospf/interface-template/unset") {
ospfPassiveWrites++
let body = ""; req.on("data", chunk => { body += chunk }); req.on("end", () => {
res.setHeader("content-type", "application/json")
const fields = body ? JSON.parse(body) : {}
const id = req.url?.endsWith("/unset") ? fields[".id"] : decodeURIComponent(req.url!.split("/").at(-1)!)
const row = fixtureOspf["interface-template"].find(row => row[".id"] === id)
if (req.method === "PUT") {
const added = { ...fields, ".id": "*abc123", ...(Object.hasOwn(fields, "passive") ? { passive: "" } : {}) }
fixtureOspf["interface-template"].push(added); res.end(JSON.stringify(added)); return
}
if (!row) { res.statusCode = 404; res.end("{}"); return }
if (req.method === "DELETE") fixtureOspf["interface-template"] = fixtureOspf["interface-template"].filter(item => item !== row)
else if (req.url?.endsWith("/unset")) { if (!ospfIgnoreUnset && fields["value-name"] === "passive") delete row.passive }
else Object.assign(row, fields, Object.hasOwn(fields, "passive") ? { passive: "" } : {})
res.end("{}")
}); return
}
if ((ospfFixtures || ospfAnalysisFixtures) && ["/rest/routing/ospf/interface-template/get", "/rest/routing/ospf/interface-template/print"].includes(req.url ?? "")) {
ospfTemplateFlagReads++
let body = ""; req.on("data", chunk => { body += chunk }); req.on("end", () => {
res.setHeader("content-type", "application/json")
const input = JSON.parse(body)
if (req.url?.endsWith("/print")) {
const query = JSON.stringify(input[".query"])
if (![JSON.stringify(["passive"]), JSON.stringify(["passive", "#!"])].includes(query)) { res.statusCode = 400; res.end("{}"); return }
const absent = query === JSON.stringify(["passive", "#!"])
res.end(JSON.stringify(fixtureOspf["interface-template"].filter(row => ("passive" in row) !== absent).map(row => ({ ".id": row[".id"] })))); return
}
const row = fixtureOspf["interface-template"].find(row => row[".id"] === input[".id"]) as Record<string, unknown> | undefined
if (!row || !["passive", "disabled", "use-bfd"].includes(input["value-name"])) { res.statusCode = 404; res.end("{}"); return }
if (input["value-name"] === "use-bfd" && row.interfaces === "fixture-loop") { res.end("[]"); return }
const key = input["value-name"], value = key === "use-bfd" && ospfAnalysisFixtures ? "false" : key === "passive" && row[key] === "" ? "true" : row[key] ?? "false"
if (key === "passive" && row[key] === undefined) { res.end("[]"); return }
res.end(JSON.stringify({ ret: value }))
}); return
}
if (ospfAnalysisFixtures && req.url?.startsWith("/rest/routing/ospf/")) {
if (req.method !== "GET") ospfAnalysisDispatches++
res.setHeader("content-type", "application/json")
const key = req.url.slice("/rest/routing/ospf/".length)
if (req.method === "PATCH" && key.startsWith("interface-template/")) {
let body = ""; req.on("data", chunk => { body += chunk }); req.on("end", () => {
const id = decodeURIComponent(key.slice("interface-template/".length)), target = fixtureOspf["interface-template"].find(row => row[".id"] === id)
if (!target) { res.statusCode = 404; res.end("{}"); return }
if (ospfCostWriteFault !== "ignored") target.cost = JSON.parse(body).cost
if (ospfCostWriteFault === "changed-field") Object.assign(target, { opaque: "UNEXPECTED_OSPF_CHANGE" })
if (ospfAfterCostPatch) { const work = ospfAfterCostPatch; ospfAfterCostPatch = undefined; work() }
if (ospfCostWriteFault === "lost-response") { req.socket.destroy(); return }
res.end("{}")
}); return
}
const rows = key === "neighbor" ? [{ ".id": "*analysis-neighbor", interface: "fixture-gre", instance: "fixture-ospf", "router-id": "192.0.2.2", address: "192.0.2.2", state: "Full" }, ...ospfAnalysisExtraNeighbors]
: key === "interface-template" ? fixtureOspf["interface-template"].map(row => ({ ...row, "use-bfd": row.interfaces === "fixture-loop" ? undefined : "false" })) : fixtureOspf[key as keyof typeof fixtureOspf] ?? []
if (ospfPauseOnTemplatesConnection && key === "interface-template" && ospfTemplateListsBeforePause-- === 0) {
const connection = ospfPauseOnTemplatesConnection; ospfPauseOnTemplatesConnection = undefined
void pool.query("UPDATE mcp_connections SET policy=jsonb_set(policy,'{status}',to_jsonb('paused'::text)) WHERE id=$1", [connection]).then(() => res.end(JSON.stringify(rows)), () => { res.statusCode = 503; res.end("{}") })
return
}
if(ospfPreviewPauseConnection&&key==="neighbor"){
const connection=ospfPreviewPauseConnection;ospfPreviewPauseConnection=undefined
void pool.query("UPDATE mcp_connections SET policy=jsonb_set(policy,'{status}',to_jsonb('paused'::text)) WHERE id=$1",[connection]).then(()=>res.end(JSON.stringify(rows)),()=>{res.statusCode=503;res.end("{}")})
return
}
res.end(JSON.stringify(rows)); return
}
if (wanFixtures && ["/rest/ip/dhcp-client", "/rest/ip/address", "/rest/ip/route"].includes(req.url ?? "")) {
res.setHeader("content-type", "application/json")
if (wanAddressFailure && req.url === "/rest/ip/address") { res.statusCode = 503; res.end("{}"); return }
const rows = req.url === "/rest/ip/route" ? wanRoutes : req.url === "/rest/ip/address" ? [{ address: "192.0.2.10/24", interface: "ether1" }] : [{ address: "192.0.2.10/24", interface: "ether1", gateway: "192.0.2.1", status: "bound", password: "never-return-wan-key" }]
res.end(JSON.stringify(rows)); return
}
if (containerMutationFixtures && req.url === "/rest/interface") {
res.setHeader("content-type", "application/json"); res.end(JSON.stringify([containerParent])); return
}
if (containerMutationFixtures && req.url?.startsWith("/rest/container")) {
res.setHeader("content-type", "application/json")
if (req.method === "DELETE") {
containerDeletes++
if (!ignoreContainerDelete) mutableContainers = mutableContainers.filter(row => req.url !== "/rest/container/" + encodeURIComponent(String(row[".id"])))
res.end("{}"); return
}
if (req.method === "POST") {
let raw = ""; req.on("data", chunk => { raw += chunk }); req.on("end", () => {
const input = JSON.parse(raw), row = mutableContainers.find(row => row[".id"] === input[".id"])
if (!row) { res.statusCode = 404; res.end("{}"); return }
containerCommands++; row.status = req.url?.endsWith("/start") ? "running" : "stopped"
if (replaceContainerAfterCommand) row.name = "replacement-after-command"
res.end("{}")
}); return
}
res.end(JSON.stringify(mutableContainers)); return
}
if (preflightFixtures && req.url && Object.hasOwn(preflightFixtures, req.url)) {
res.setHeader("content-type", "application/json")
if (req.url === preflightUnavailable) { res.statusCode = 503; res.end("{}"); return }
res.end(JSON.stringify(preflightFixtures[req.url])); return
}
if (greMutationFixtures && req.url?.startsWith("/rest/")) {
greRevisionReads++
res.setHeader("content-type","application/json")
const path = decodeURIComponent(req.url.slice(5)), bases = ["/interface/gre","/ip/address","/ipv6/address"]
const base = bases.find(base=>path===base||path.startsWith(base+"/"))
if (req.method === "GET") {
if(path==="/ip/route"){
greNativeRouteReads++
if(greNativeLateDynamicAt&&greNativeRouteReads>=greNativeLateDynamicAt)greMutationDependencies[path]=[{".id":"*LATEDYNAMIC",dynamic:"true",gateway:"192.0.2.2%native-gre"}]
}
if (base) { res.end(JSON.stringify((greMutationCollections[base]??[]).map(row=>Object.fromEntries(Object.entries(row).filter(([key,value])=>(key!=="comment"||value!=="")&&(base!=="/interface/gre"||key!=="dynamic")))))); return }
if (path==="/interface") { res.end(JSON.stringify(greMutationDependencies[path]??[{ ".id":"*E",name:"ether1",type:"ether" },...(greMutationCollections["/interface/gre"]??[]).map(row=>({".id":row[".id"],name:row.name,type:"gre",...(row.dynamic===undefined?{}:{dynamic:row.dynamic})}))]));return }
if(greNativeCounterTick&&path.includes("/firewall/"))for(const row of greMutationDependencies[path]??[]){row.packets=String(Number(row.packets??"0")+1);row.bytes=String(Number(row.bytes??"0")+100)}
res.end(JSON.stringify(greMutationDependencies[path]??[])); return
}
let body = ""; req.on("data",chunk=>body+=chunk); req.on("end",async()=>{
const data = body?JSON.parse(body):{}
if(path==="/interface/get"){
const row=greMutationDependencies[path]?.find(row=>row[".id"]===data[".id"])
if(row&&data["value-name"]==="dynamic"){res.end(JSON.stringify(row.ret==="empty-array"?[]:{ret:row.ret}));return}
res.statusCode=400;res.end(JSON.stringify({error:400,detail:"Property not available"}));return
}
if(path==="/interface/print"){
assert.deepEqual(data[".query"],[".id="+greMutationDependencies["/interface/get"]?.[0]?.[".id"],data[".query"]?.includes("-dynamic")?"-dynamic":"dynamic","#&"])
const key=data[".query"]?.includes("-dynamic")?"/interface/static-print":"/interface/dynamic-print"
res.end(JSON.stringify(greMutationDependencies[key]??[]));return
}
if (path.endsWith("/get") && base) {
const row = (greMutationCollections[base]??[]).find(row=>row[".id"]===data[".id"])
res.end(JSON.stringify({ret:row?.[data["value-name"]]??(["comment","ipsec-secret","from-pool"].includes(data["value-name"])?"":"false")})); return
}
greMutationCommands++
if(base==="/interface/gre"&&data["ipsec-secret"]===""&&["yes","true"].includes(data["allow-fast-path"])){
res.statusCode=400;res.end(JSON.stringify({error:400,detail:"failure: cannot enable fastpath together with ipsec yet"}));return
}
if (!greMutationIgnored && base) {
const fields = Object.fromEntries(Object.entries(data).map(([key,value])=>[key,value==="yes"?"true":value==="no"?"false":String(value)]))
if (req.method==="PUT") {
const row = base==="/interface/gre"?{".id":"*G"+(greMutationNextId++),"local-address":"0.0.0.0",mtu:"1476",keepalive:"10s,10",dscp:"inherit",disabled:"false",dynamic:"false",running:"false","clamp-tcp-mss":"true","allow-fast-path":"true","ipsec-secret":"",comment:"",...fields}:{".id":"*A"+(greMutationNextId++),disabled:"false",dynamic:"false",invalid:"false",advertise:"false","no-dad":"false","eui-64":"false","from-pool":"",comment:"",...fields}
;(greMutationCollections[base]??=[]).push(row)
} else if (req.method==="PATCH") Object.assign(greMutationCollections[base].find(row=>row[".id"]===path.slice(base.length+1))!,fields)
else if (req.method==="DELETE") greMutationCollections[base]=greMutationCollections[base].filter(row=>row[".id"]!==path.slice(base.length+1))
}
if (greMutationRevoke) { const id=greMutationRevoke;greMutationRevoke=undefined;await pool.query("UPDATE mcp_connections SET policy=jsonb_set(policy,'{status}','\"paused\"'::jsonb) WHERE id=$1",[id]) }
await greRevisionAfterCommand?.()
if (greMutationLost) { greMutationLost=false;req.socket.destroy();return }
res.end("{}")
});return
}
if (filterCatalogFixtures && ["/rest/interface/gre", "/rest/routing/filter/rule"].includes(req.url ?? "")) {
res.setHeader("content-type","application/json")
if (req.url === "/rest/interface/gre") { res.end(JSON.stringify([{ ".id":"*G",name:"filter-gre","local-address":"192.0.2.1","remote-address":"192.0.2.2","ipsec-secret":"NEVER_FILTER_PSK" }])); return }
res.end(JSON.stringify(filterCatalogMalformed ? { rules: [] } : [
{".id":"*F1",chain:"bgp-in",rule:"if (bgp-communities includes 64512:1) { set gw 192.0.2.2; accept; }",disabled:"true","private-key":"NEVER_FILTER_NATIVE_KEY"},
{".id":"*F2",chain:"bgp-in",rule:"jump other;"},
{".id":"*F3",chain:"other",rule:"reject;",disabled:"false"},
])); return
}
if (deviceStateFixtures && req.url?.startsWith("/rest/container")) {
res.setHeader("content-type", "application/json")
if (req.url === "/rest/container") {
if (containerStateFailure === "unsupported") { res.statusCode = 404; res.end("{}"); return }
res.end(JSON.stringify((reverseContainerRows ? [2, 1] : [1, 2]).map(index => ({ ".id": `*c${index}`, name: `fixture-container-${index}`, "remote-image": "test/image:latest", envlists: "fixture-env", cmd: "never-return-this-command", running: index === 1 ? "true" : undefined })))); return
}
if (req.url === "/rest/container/envs") {
if (containerStateFailure === "envs") { res.statusCode = 503; res.end("{}"); return }
res.end(JSON.stringify([{ list: "fixture-env", key: "UNCLASSIFIED_VALUE", value: "never-return-this-env" }])); return
}
res.end("[]"); return
}
if (deviceStateFixtures && req.url === "/rest/system/clock") {
res.setHeader("content-type", "application/json"); res.end(JSON.stringify({ "gmt-offset": certificateClockKnown ? "+07:00" : "unknown" })); return
}
if (deviceStateFixtures && req.url === "/rest/certificate") {
res.setHeader("content-type", "application/json")
if (healthUnavailable) { res.statusCode = 503; res.end("{}"); return }
if (certificateStateMalformed) { res.end(JSON.stringify({ certificates: [] })); return }
res.end(JSON.stringify([{ ".id": "*cert1", name: "fixture-certificate", flags: "T", "invalid-before": "2025-01-01 00:00:00", "invalid-after": "2035-01-01 00:00:00", "private-key": "never-return-certificate-key" }, { ".id": "*cert2", name: "unknown-certificate" }])); return
}
if (recursiveCatalogFixtures && req.url?.startsWith("/rest/ip/route")) {
res.setHeader("content-type", "application/json")
if (healthUnavailable) { res.statusCode = 503; res.end("{}"); return }
if (recursiveMutations && req.method === "PUT") {
let raw = ""; req.on("data", chunk => { raw += chunk }); req.on("end", async () => {
const fields = JSON.parse(raw), row = { ...fields, ".id": `*created-${++recursiveMutationCount}`, static: "true" }
if (recursiveIgnorePayload) row.distance = "254"
recursiveCatalogRows.push(row)
if (recursivePauseConnection) {
await pool.query("UPDATE mcp_connections SET policy=jsonb_set(policy,'{status}',to_jsonb($2::text)) WHERE id=$1", [recursivePauseConnection, "paused"])
recursivePauseConnection = undefined
}
res.end(JSON.stringify(row))
}); return
}
if (recursiveMutations && req.method === "DELETE") {
recursiveMutationCount++
recursiveCatalogRows = recursiveCatalogRows.filter(row => req.url !== "/rest/ip/route/" + encodeURIComponent(String(row[".id"])))
res.end("{}"); return
}
if (req.url.endsWith("/get")) {
let raw = ""; req.on("data", chunk => { raw += chunk }); req.on("end", () => {
if (recursivePropertyFailure) { res.statusCode = 503; res.end("{}"); return }
const input = JSON.parse(raw); res.end(input["value-name"] === "disabled" ? JSON.stringify({ ret: "false" }) : "[]")
}); return
}
res.end(JSON.stringify(recursiveCatalogRows)); return
}
if (greCatalogFixtures && req.url === "/rest/interface/gre") {
res.setHeader("content-type", "application/json")
if (healthUnavailable) { res.statusCode = 503; res.end("{}"); return }
res.end(JSON.stringify([1, 2].map(id => ({ ".id": `*gre${id}`, name: `catalog-gre-${id}`, running: "true", disabled: "false", "ipsec-secret": "never-return-gre-key" })))); return
}
if (bgpFixtures && req.url?.startsWith("/rest/routing/bgp/")) {
const key = req.url.slice("/rest/routing/bgp/".length) as keyof typeof fixtureBgp
if (key in fixtureBgp) { res.setHeader("content-type", "application/json"); if (key === "session" && healthUnavailable) { res.statusCode = 503; res.end("{}"); return }; res.end(JSON.stringify(key === "session" && bgpSessionOverride !== undefined ? bgpSessionOverride : fixtureBgp[key])); return }
}
if (ecmpFixtures && req.url?.startsWith("/rest/ip/route")) {
res.setHeader("content-type", "application/json")
if (req.method === "PATCH") {
let raw = ""; req.on("data", chunk => { raw += chunk }); req.on("end", () => {
const row = fixtureEcmpRoutes.find(row => req.url!.endsWith(encodeURIComponent(row[".id"])))!
Object.assign(row, JSON.parse(raw)); ecmpWrites++
const best = Math.min(...fixtureEcmpRoutes.map(row => Number(row.distance)))
for (const route of fixtureEcmpRoutes) route.active = String(Number(route.distance) === best)
if (loseEcmpGateway) fixtureEcmpRoutes[0]["immediate-gw"] = ""
res.end(JSON.stringify(row))
}); return
}
res.end(JSON.stringify(fixtureEcmpRoutes)); return
}
if (ospfFixtures && req.url?.startsWith("/rest/routing/ospf/")) {
const key = req.url.slice("/rest/routing/ospf/".length) as keyof typeof fixtureOspf
if (key in fixtureOspf) { res.setHeader("content-type", "application/json"); res.end(JSON.stringify(fixtureOspf[key])); return }
}
if (req.url === "/rest/routing/bfd/session") {
res.setHeader("content-type", "application/json")
if (healthUnavailable) { res.statusCode = 503; res.end("{}"); return }
res.end(JSON.stringify([{ ".id": "*bfd", state: healthState ? "up" : "down", "remote-address": healthBfdRemote, "local-address": "192.0.2.1%fixture-ospf" }])); return
}
if (interfaceFixtures && req.url === "/rest/interface/gre") {
res.setHeader("content-type", "application/json"); res.end(JSON.stringify([{ ".id": "*gre", name: "fixture-gre", disabled: "false" }])); return
}
if (interfaceFixtures && req.url === "/rest/interface") {
res.setHeader("content-type", "application/json"); res.end(JSON.stringify([{ ".id": "*gre", name: "fixture-gre", type: "gre" }, { ".id": "*fixture", name: "fixture-bridge", type: "bridge" }])); return
}
if (interfaceFixtures && req.url?.startsWith("/rest/ip/vrf")) {
res.setHeader("content-type", "application/json")
if (req.method === "PUT") {
let raw = ""; req.on("data", chunk => { raw += chunk }); req.on("end", () => {
const { "place-before": before, ...fields } = JSON.parse(raw)
const row = { ".id": "*CREATEDVRF", ...fields }; vrfWrites++
const index = ignoreVrfPlacement ? -1 : fixtureVrfs.findIndex(item => item[".id"] === before)
if (index >= 0) fixtureVrfs.splice(index, 0, row); else fixtureVrfs.push(row)
res.end(JSON.stringify(row))
}); return
}
if (req.method === "DELETE") { fixtureVrfs = fixtureVrfs.filter(row => !req.url!.endsWith(encodeURIComponent(row[".id"]))); vrfWrites++; res.end("{}"); return }
res.end(JSON.stringify(fixtureVrfs)); return
}
if (req.url === "/rest/routing/table" || req.url === "/rest/routing/rule") {
res.setHeader("content-type", "application/json")
res.end(JSON.stringify(req.url.endsWith("/rule") ? fixtureRoutingRules : [{ ".id": "*main", name: "main", fib: "true" }, { ".id": "*table", name: "fixture-table", fib: "" }])); return
}
if (req.url === "/rest/routing/ospf/neighbor" || req.url === "/rest/ip/route") {
res.setHeader("content-type", "application/json")
if (healthUnavailable) { res.statusCode = 503; res.end(JSON.stringify({ error: "fixture unavailable" })); return }
res.end(JSON.stringify(req.url.endsWith("/neighbor") ? [{ ".id": "*neighbor", interface: "fixture-ospf", "router-id": "192.0.2.2", state: healthState ? "Full" : "Down" }] : [{ ".id": "*healthroute", "dst-address": "192.0.2.0/24", "routing-table": fixtureRouteTable, active: healthState ? "true" : "false" }])); return
}
if (req.url === "/rest/interface/bridge" || req.url === "/rest/interface/bridge/*fixture") {
res.setHeader("content-type", "application/json")
if (req.method === "PATCH") {
let raw = ""; req.on("data", chunk => { raw += chunk }); req.on("end", () => { bridge = { ...bridge, ...JSON.parse(raw) }; res.end(JSON.stringify(bridge)) }); return
}
res.end(JSON.stringify([bridge])); return
}
if (req.url === "/rest/system/license") { res.setHeader("content-type", "application/json"); res.end(JSON.stringify({ "system-id": "fixture-primary" })); return }
if (req.url !== "/rest/ip/settings") { res.setHeader("content-type", "application/json"); res.end("[]"); return }
if (req.method === "GET") {
reconcileSettingsReads++
if (reconcileReadHook) {
const hook = reconcileReadHook; reconcileReadHook = undefined
void hook().then(() => { res.setHeader("content-type", "application/json"); res.end(JSON.stringify(settings)) }, () => { res.statusCode = 503; res.end("{}"); })
return
}
}
if (req.method === "PATCH") {
let body = ""; req.on("data", value => { body += value }); req.on("end", () => {
settings = { ...settings, ...JSON.parse(body) }; writes++
if (failHealthAfterWrite) healthState = false
if (loseHealthResponse) healthUnavailable = true
res.setHeader("content-type", "application/json"); res.end(JSON.stringify(settings))
}); return
}
res.setHeader("content-type", "application/json"); res.end(JSON.stringify(settings))
})
await new Promise<void>(resolve => router.listen(0, "127.0.0.1", resolve))
const port = (router.address() as { port: number }).port
let app: Awaited<ReturnType<typeof import("../../index.js")["buildApp"]>> | undefined
try {
const { configurationRows, resourceById } = await import("./resources.js")
const tableSpec = resourceById("routing_table")
assert.equal(configurationRows(tableSpec, [{ ".id": "*1", name: "isolated", fib: "" }])[0].fib, "false")
assert.equal(configurationRows(tableSpec, [{ ".id": "*1", name: "main", fib: "true" }])[0].fib, "true")
assert.equal(configurationRows(tableSpec, [{ ".id": "*1", name: "unknown" }])[0].fib, undefined)
assert.equal(configurationRows(resourceById("bridge"), [{ disabled: "" }])[0].disabled, "")
assert.deepEqual(configurationRows(resourceById("ipv6_address"), [{ ".id": "*auto", address: "fe80::1/64", dynamic: "true" }, { ".id": "*explicit", address: "fe80::2/64", dynamic: "false" }, { ".id": "*global", address: "fd00::1/64", dynamic: "true" }]).map(row => row[".id"]), ["*explicit", "*global"])
const orderedVrfs = [{ ".id": "*a", name: "customer", interfaces: "ether2" }, { ".id": "*b", name: "main", interfaces: "all" }]
assert.deepEqual(configurationRows(resourceById("vrf"), [{ ".id": "*a", name: "customer", interfaces: ["ether3", "ether2"] }]), configurationRows(resourceById("vrf"), [{ ".id": "*a", name: "customer", interfaces: "ether2,ether3" }]))
assert.notDeepEqual(configurationRows(resourceById("vrf"), orderedVrfs), configurationRows(resourceById("vrf"), [...orderedVrfs].reverse()))
await applySqlMigrations(pool)
await applySqlMigrations(pool)
console.log("✓ All migrations apply and are repeatable on PostgreSQL 18")
await (await import("../../test/partition-timezones.js")).verifyPartitionTimezones(pool)
// refreshScheduler starts enabled jobs immediately. Keep external GeoIP
// downloads disabled in this owned fixture before any telemetry refresh.
await pool.query("INSERT INTO geoip_settings(id,enabled) VALUES(1,false) ON CONFLICT(id) DO UPDATE SET enabled=false")
await pool.query("INSERT INTO servers(id,name,host,port,use_ssl) VALUES(1,'test-router','127.0.0.1',$1,false),(2,'outside-scope','127.0.0.1',$1,false)", [port])
await updateMcpSettings({ enabled: true }, actor)
const { registerManagementChannel, verifyManagementChannel } = await import("./management.js")
let alternateIdentity = "fixture-primary"
const alternate = createServer((_req, res) => { res.setHeader("content-type", "application/json"); res.end(JSON.stringify({ "system-id": alternateIdentity })) })
await new Promise<void>(resolve => alternate.listen(0, "127.0.0.2", resolve))
try {
const management = { serverId: 1, host: "127.0.0.2", port: (alternate.address() as { port: number }).port, useSsl: false, verifySsl: true, username: "fixture", password: "fixture", attestation: "Изолированный тестовый канал с отдельным адресом loopback для проверки границы допуска", expiresAt: new Date(Date.now() + 1800000).toISOString() }
await assert.rejects(registerManagementChannel({ ...management, host: "127.0.0.1" }, actor))
alternateIdentity = "different-device"; await assert.rejects(registerManagementChannel(management, actor))
alternateIdentity = "fixture-primary"
const channel = await registerManagementChannel(management, actor)
assert.equal((await verifyManagementChannel(1, channel.id)).channelId, channel.id)
await pool.query("UPDATE mcp_management_channels SET revoked_at=now() WHERE id=$1", [channel.id])
await assert.rejects(verifyManagementChannel(1, channel.id))
console.log("✓ Independent channel rejects primary aliases and different devices; identity verification and revocation work")
} finally { await new Promise<void>(resolve => alternate.close(() => resolve())) }
const input = mcpConnectionCreateSchema.parse({ name: "Integration", mode: "approval", expiresAt: new Date(fixtureAuthExpiresAt).toISOString(), permissions: ["mm:network:write", "mm:servers:read"], scope: { serverIds: [1], operationIds: ["ros.ip_settings.list", "ros.ip_settings.update", "servers.list", "operations.recover", "operations.reconcile"], allowGlobal: false } })
const issued = await createMcpConnection(input, actor)
const principal = await authenticateMcpToken(issued.token)
const credentials = await pool.query("SELECT digest FROM mcp_credentials WHERE connection_id=$1", [issued.connection.id])
assert.equal(credentials.rows[0].digest, tokenDigest(issued.token)); assert.notEqual(credentials.rows[0].digest, issued.token)
const read = await invokeMcpTool(principal, "mm_ip_settings_list", { serverId: 1 }) as { items: unknown[] }
assert.equal(read.items.length, 1)
await assert.rejects(invokeMcpTool(principal, "mm_ip_settings_list", { serverId: 2 }))
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE status='denied'")).rows[0].n, 1)
console.log("✓ Opaque credentials, explicit server scope, denied-call audit")
const wanAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped WAN runtime", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:servers:read"], scope: { serverIds: [1], operationIds: ["servers.wan-runtime.read"], allowGlobal: false } }), actor)
const wanPrincipal = await authenticateMcpToken(wanAccess.token)
await pool.query("UPDATE servers SET wan_uplinks=$1::jsonb WHERE id=1", [JSON.stringify([{ id: "wan", iface: "ether1", name: "Fixture WAN", isp: "Fixture ISP", ip: "192.0.2.10" }])])
wanFixtures = true; countCatalogCalls = true; catalogCalls = 0
try {
type WanState = { defaultRouteStatus: string; defaultInterface: string | null; forwardingVerified: boolean; uplinks: { leasedIp: string | null; defaultKnown: boolean }[] }
const state = await invokeMcpTool(wanPrincipal, "mm_server_wan_runtime_get", { serverId: 1 }) as WanState
assert.equal(state.defaultRouteStatus, "confirmed"); assert.equal(state.defaultInterface, "ether1")
assert.equal(state.uplinks[0].leasedIp, "192.0.2.10"); assert.equal(state.forwardingVerified, false)
assert.equal(catalogCalls, 3); assert.ok(!JSON.stringify(state).includes("never-return-wan-key"))
await assert.rejects(invokeMcpTool(wanPrincipal, "mm_server_wan_runtime_get", { serverId: 2 })); assert.equal(catalogCalls, 3)
await pool.query("UPDATE servers SET enabled=false WHERE id=1")
await assert.rejects(invokeMcpTool(wanPrincipal, "mm_server_wan_runtime_get", { serverId: 1 })); assert.equal(catalogCalls, 3)
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
wanRoutes = [wanDefault, { ...wanDefault, ".id": "*wan2", gateway: "198.51.100.1", "immediate-gw": "198.51.100.1%ether2" }]
const ambiguous = await invokeMcpTool(wanPrincipal, "mm_server_wan_runtime_get", { serverId: 1 }) as WanState
assert.equal(ambiguous.defaultRouteStatus, "ambiguous"); assert.equal(ambiguous.defaultInterface, null); assert.equal(ambiguous.uplinks[0].defaultKnown, false)
wanAddressFailure = true
await assert.rejects(invokeMcpTool(wanPrincipal, "mm_server_wan_runtime_get", { serverId: 1 }))
} finally {
wanFixtures = false; wanAddressFailure = false; countCatalogCalls = false
await pool.query("UPDATE servers SET enabled=true,wan_uplinks='[]'::jsonb WHERE id=1")
}
console.log("✓ WAN runtime: only selected enabled server, native default/lease, explicit ECMP ambiguity, no credential echo or forwarding claim, failed source is not fabricated empty")
const historySections = ["filters", "recursive-routes", "firewall", "wireguard", "ipsec", "gre"]
const historyAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped configuration history", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read", "mm:filters:read"], scope: { serverIds: [1], operationIds: historySections.map(section => `config.${section}.revisions.read`), allowGlobal: false } }), actor)
const historyPrincipal = await authenticateMcpToken(historyAccess.token)
const historyIds: string[] = []
for (const section of historySections) {
for (const sid of [1, 2]) {
const id = randomUUID(); historyIds.push(id)
await pool.query("INSERT INTO config_revisions(id,server_id,section,source,fingerprint,payload,note) VALUES($1,$2,$3,'observed',$4,$5::jsonb,$6)", [id, sid, section, id, JSON.stringify([{ privateKey: "never-return-this-payload", secret: "fixture" }]), `fixture-${sid}-${section}`])
}
const tool = `mm_${section.replaceAll("-", "_")}_revisions_get`
const result = await invokeMcpTool(historyPrincipal, tool, { serverId: 1 }) as { revisions: { serverId: string; section: string; itemCount: number }[]; retentionLimit: number }
assert.equal(result.revisions.length, 1); assert.equal(result.retentionLimit, 50)
assert.equal(result.revisions[0].serverId, "1"); assert.equal(result.revisions[0].section, section); assert.equal(result.revisions[0].itemCount, 1)
assert.ok(!JSON.stringify(result).includes("never-return-this-payload"))
await assert.rejects(invokeMcpTool(historyPrincipal, tool, { serverId: 2 }))
await assert.rejects(invokeMcpTool(historyPrincipal, tool, { serverId: 1, section: "wireguard" }))
}
const historyDenied = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "History permission boundary", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1], operationIds: ["config.filters.revisions.read"], allowGlobal: false } }), actor)
await assert.rejects(invokeMcpTool(await authenticateMcpToken(historyDenied.token), "mm_filters_revisions_get", { serverId: 1 }))
for (let index = 0; index < 51; index++) {
const id = randomUUID(); historyIds.push(id)
await pool.query("INSERT INTO config_revisions(id,server_id,section,source,fingerprint,payload) VALUES($1,1,'gre','observed',$1,'[]'::jsonb)", [id])
}
const boundedHistory = await invokeMcpTool(historyPrincipal, "mm_gre_revisions_get", { serverId: 1 }) as { revisions: unknown[]; incomplete: boolean }
assert.equal(boundedHistory.revisions.length, 50); assert.equal(boundedHistory.incomplete, true)
await pool.query("DELETE FROM config_revisions WHERE id=ANY($1::text[])", [historyIds])
console.log("✓ Six configuration histories share REST metadata service, bound results, reject hidden servers and never expose saved secret payloads")
const greCatalogAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped GRE catalog", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:filters:read"], scope: { serverIds: [1], operationIds: ["routing.gre.catalog.read"], allowGlobal: false } }), actor)
const greCatalogPrincipal = await authenticateMcpToken(greCatalogAccess.token)
greCatalogFixtures = true; countCatalogCalls = true; catalogCalls = 0
const greCatalog = await invokeMcpTool(greCatalogPrincipal, "mm_gre_catalog_get", { limit: 1 }) as { serverIds: number[]; tunnels: { serverId: string }[]; total: number; nextOffset: number; failures: unknown[] }
assert.deepEqual(greCatalog.serverIds, [1]); assert.equal(greCatalog.total, 2); assert.equal(greCatalog.tunnels.length, 1); assert.equal(greCatalog.nextOffset, 1); assert.equal(greCatalog.tunnels[0].serverId, "1"); assert.equal(greCatalog.failures.length, 0); assert.equal(catalogCalls, 2)
assert.ok(!JSON.stringify(greCatalog).includes("never-return-gre-key"))
await assert.rejects(invokeMcpTool(greCatalogPrincipal, "mm_gre_catalog_get", { serverId: 2 })); assert.equal(catalogCalls, 2)
const greNext = await invokeMcpTool(greCatalogPrincipal, "mm_gre_catalog_get", { offset: 1, limit: 1 }) as { tunnels: { name: string }[]; nextOffset: null }
assert.equal(greNext.tunnels[0].name, "catalog-gre-2"); assert.equal(greNext.nextOffset, null)
healthUnavailable = true
const failedGre = await invokeMcpTool(greCatalogPrincipal, "mm_gre_catalog_get", {}) as { failures: { serverId: string }[]; incomplete: boolean }
assert.equal(failedGre.failures.length, 1); assert.equal(failedGre.failures[0].serverId, "1"); assert.equal(failedGre.incomplete, true)
greCatalogFixtures = false; countCatalogCalls = false; healthUnavailable = false
console.log("✓ GRE routing catalog shares REST polling/parser, scopes before polling, paginates, strips IPsec keys and preserves device failures")
await pool.query("INSERT INTO servers(id,name,host,port,use_ssl) VALUES(43,'filter-catalog-owner','127.0.0.1',$1,false),(44,'NEVER_FILTER_FOREIGN','192.0.2.44',1,false)",[port])
await pool.query("INSERT INTO filter_rules(server_id,community,description) VALUES(43,'64512:99','own cached hint'),(44,'64512:100','NEVER_FILTER_CACHED')")
const filterAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({name:"Scoped BGP filters",mode:"observer",expiresAt:new Date(Date.now()+1800000).toISOString(),permissions:["mm:filters:read"],scope:{serverIds:[43],operationIds:["routing.filters.catalog.read"],allowGlobal:false}}),actor)
const filterPrincipal = await authenticateMcpToken(filterAccess.token)
filterCatalogFixtures = true; countCatalogCalls = true; catalogCalls = 0
const { default: FilterFastify } = await import("fastify"), {validatorCompiler: filterValidator,serializerCompiler: filterSerializer} = await import("@fastify/type-provider-zod")
const filterHttp = FilterFastify(); filterHttp.setValidatorCompiler(filterValidator); filterHttp.setSerializerCompiler(filterSerializer); await filterHttp.register((await import("../../routes/filters.js")).default,{prefix:"/api"})
type FilterPage = {rulesets:{serverId:string;live:boolean;stale:boolean;source:string;error:string|null;rules:{items:{community:string}[];total:number};nativeRules:{items:{rosId:string;enabled:boolean|null}[];total:number}|null}[];incomplete:boolean;writesPerformed:boolean}
try {
const beforeCache = (await pool.query("SELECT * FROM filter_rules WHERE server_id=43")).rows
const fresh = await invokeMcpTool(filterPrincipal,"mm_bgp_filter_rules_get",{limit:1}) as FilterPage
assert.equal(catalogCalls,2); assert.equal(fresh.rulesets[0].serverId,"43"); assert.equal(fresh.rulesets[0].live,true); assert.equal(fresh.rulesets[0].rules.items[0].community,"64512:1")
assert.equal(fresh.rulesets[0].nativeRules!.total,2); assert.equal(fresh.rulesets[0].nativeRules!.items[0].enabled,false); assert.equal(fresh.writesPerformed,false); assert.equal(fresh.incomplete,true)
assert.ok(!JSON.stringify(fresh).includes("NEVER_FILTER")); assert.deepEqual((await pool.query("SELECT * FROM filter_rules WHERE server_id=43")).rows,beforeCache)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM config_revisions WHERE server_id=43")).rows[0].n,0)
const second = await invokeMcpTool(filterPrincipal,"mm_bgp_filter_rules_get",{offset:1,limit:1}) as FilterPage
assert.equal(second.rulesets[0].nativeRules!.items[0].rosId,"*F2"); assert.equal(second.rulesets[0].nativeRules!.items[0].enabled,null)
const noPoll = catalogCalls
await assert.rejects(invokeMcpTool(filterPrincipal,"mm_bgp_filter_rules_get",{serverId:44})); assert.equal(catalogCalls,noPoll)
const cache = await invokeMcpTool(filterPrincipal,"mm_bgp_filter_rules_get",{source:"cache"}) as FilterPage
assert.equal(catalogCalls,noPoll); assert.equal(cache.rulesets[0].rules.items[0].community,"64512:99"); assert.equal(cache.rulesets[0].nativeRules,null)
assert.ok(!JSON.stringify(cache).includes("NEVER_FILTER"))
const rest = await filterHttp.inject({method:"GET",url:"/api/filters/rules?serverId=43"}); assert.equal(rest.statusCode,200,rest.body); assert.equal(rest.json().live,true)
assert.deepEqual(rest.json().rulesets[0].rules.map((row:{community:string})=>row.community),fresh.rulesets[0].rules.items.map(row=>row.community))
assert.equal((await pool.query("SELECT count(*)::int AS n FROM config_revisions WHERE server_id=43")).rows[0].n,1)
filterCatalogMalformed = true
const stale = await invokeMcpTool(filterPrincipal,"mm_bgp_filter_rules_get",{}) as FilterPage
assert.equal(stale.rulesets[0].live,false); assert.equal(stale.rulesets[0].stale,true); assert.equal(stale.rulesets[0].source,"cache"); assert.equal(stale.rulesets[0].nativeRules,null); assert.ok(stale.rulesets[0].error)
assert.equal(stale.rulesets[0].rules.items[0].community,"64512:1"); assert.equal(stale.incomplete,true)
const failedRest = await filterHttp.inject({method:"GET",url:"/api/filters/rules?serverId=43"}); assert.equal(failedRest.json().stale,true)
await pool.query("UPDATE servers SET enabled=false WHERE id=43")
const beforeDisabled = catalogCalls
const disabled = await invokeMcpTool(filterPrincipal,"mm_bgp_filter_rules_get",{source:"cache"}) as FilterPage
assert.equal(disabled.rulesets[0].rules.items[0].community,"64512:1"); assert.equal(catalogCalls,beforeDisabled)
assert.equal((await filterHttp.inject({method:"GET",url:"/api/filters/rules?serverId=43"})).json().stale,true); assert.equal(catalogCalls,beforeDisabled)
for(const id of ["","bad","0","1abc"]) assert.equal((await filterHttp.inject({method:"GET",url:"/api/filters/rules?serverId="+id})).statusCode,400)
assert.equal(catalogCalls,beforeDisabled)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE connection_id=$1 AND result::text LIKE '%NEVER_FILTER%'",[filterAccess.connection.id])).rows[0].n,0)
} finally { filterCatalogFixtures = false; filterCatalogMalformed = false; countCatalogCalls = false; await filterHttp.close(); await pool.query("DELETE FROM servers WHERE id IN(43,44)") }
console.log("✓ BGP filters: shared REST/MCP live/cache selection, strict native identity and relative order, unknown/disabled rows, no observer cache/revision writes, scoped fallback, hidden cache/keys, disabled no-poll and malformed GET rejection")
const recursiveAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped recursive catalogs", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1], operationIds: ["routing.recursive.catalog.read", "routing.recursive.gateways.catalog.read", "routing.recursive.routes.read", "routing.recursive.gateways.read"], allowGlobal: false } }), actor)
const recursivePrincipal = await authenticateMcpToken(recursiveAccess.token)
const recursiveFixture = { ".id": "*rec1", static: "true", "dst-address": "192.0.2.0/24", gateway: "192.0.2.1%fixture-gre", distance: "0", scope: "0", "target-scope": "0", "routing-table": "main", comment: "MikrotikManager:recursive fixture" }
recursiveCatalogRows = [recursiveFixture, { ...recursiveFixture, ".id": "*rec2", gateway: "192.0.2.2%fixture-gre", disabled: "true", "check-gateway": "ping", active: "false" }]
recursiveCatalogFixtures = true; countCatalogCalls = true; catalogCalls = 0
await pool.query("INSERT INTO recursive_routes(server_id,sort_order,dst_address,gateway,distance,scope,target_scope,routing_table,check_gateway,country,comment,disabled) VALUES(1,0,'192.0.2.0/24','192.0.2.1%fixture-gre',0,0,0,'main','none','Fixture country','fixture',false)")
const recursiveBeforeObservation = (await pool.query("SELECT * FROM recursive_routes WHERE server_id=1 ORDER BY id")).rows
const recursiveRevisionsBefore = (await pool.query("SELECT * FROM config_revisions WHERE server_id=1 AND section='recursive-routes' ORDER BY id")).rows
const recursiveCatalog = await invokeMcpTool(recursivePrincipal, "mm_recursive_routes_catalog_get", { serverId: 1, limit: 1 }) as { routes: { distance: number; scope: number; disabled: boolean; checkGateway: string; country: string }[]; total: number; nextOffset: number; live: boolean; stale: boolean }
assert.equal(recursiveCatalog.total, 2); assert.equal(recursiveCatalog.nextOffset, 1); assert.equal(recursiveCatalog.routes.length, 1)
assert.equal(recursiveCatalog.live, true); assert.equal(recursiveCatalog.stale, false)
assert.deepEqual(recursiveCatalog.routes[0], { id: "*rec1", dstAddress: "192.0.2.0/24", gateway: "192.0.2.1%fixture-gre", distance: 0, scope: 0, targetScope: 0, routingTable: "main", checkGateway: "none", country: "Fixture country", comment: "fixture", disabled: false })
assert.equal(catalogCalls, 3)
await assert.rejects(invokeMcpTool(recursivePrincipal, "mm_recursive_routes_catalog_get", { serverId: 2 })); assert.equal(catalogCalls, 3)
const recursiveBusinessRead = await invokeMcpTool(recursivePrincipal, "mm_recursive_routes_get", { serverId: 1, limit: 1 }) as { routes: { id: string }[]; total: number; live: boolean; forwardingVerified: boolean }
assert.equal(recursiveBusinessRead.routes[0].id, String(recursiveBeforeObservation[0].id)); assert.equal(recursiveBusinessRead.total, 2); assert.equal(recursiveBusinessRead.live, true); assert.equal(recursiveBusinessRead.forwardingVerified, false)
recursivePropertyFailure = true
await assert.rejects(invokeMcpTool(recursivePrincipal, "mm_recursive_routes_catalog_get", { serverId: 1 }))
recursivePropertyFailure = false
recursiveCatalogRows = [{ ...recursiveFixture, blackhole: "true" }]
await assert.rejects(invokeMcpTool(recursivePrincipal, "mm_recursive_routes_catalog_get", { serverId: 1 }))
const recursiveFallback = await invokeMcpTool(recursivePrincipal, "mm_recursive_routes_get", { serverId: 1 }) as { routes: { id: string }[]; live: boolean; stale: boolean; incomplete: boolean }
assert.equal(recursiveFallback.live, false); assert.equal(recursiveFallback.stale, true); assert.equal(recursiveFallback.incomplete, true); assert.equal(recursiveFallback.routes[0].id, String(recursiveBeforeObservation[0].id))
assert.deepEqual((await pool.query("SELECT * FROM config_revisions WHERE server_id=1 AND section='recursive-routes' ORDER BY id")).rows, recursiveRevisionsBefore)
assert.deepEqual((await pool.query("SELECT * FROM recursive_routes WHERE server_id=1 ORDER BY id")).rows, recursiveBeforeObservation)
recursiveCatalogRows = [{ ".id": "*gw1", gateway: "192.0.2.1%fixture-gre" }, { ".id": "*gw2", gateway: "192.0.2.2%fixture-gre", active: "false" }, { ".id": "*gw3", gateway: "192.0.2.3%fixture-gre", active: "true" }]
const gatewayCatalog = await invokeMcpTool(recursivePrincipal, "mm_recursive_gateways_catalog_get", { serverId: 1, limit: 2 }) as { gateways: { status: string }[]; total: number; nextOffset: number }
assert.deepEqual(gatewayCatalog.gateways.map(row => row.status), ["unknown", "inactive"]); assert.equal(gatewayCatalog.total, 3); assert.equal(gatewayCatalog.nextOffset, 2)
const gatewayLast = await invokeMcpTool(recursivePrincipal, "mm_recursive_gateways_catalog_get", { serverId: 1, offset: 2, limit: 2 }) as { gateways: { status: string }[]; nextOffset: null }
assert.equal(gatewayLast.gateways[0].status, "active"); assert.equal(gatewayLast.nextOffset, null)
const legacyGateways = await invokeMcpTool(recursivePrincipal, "mm_recursive_gateways_get", { serverId: 1 }) as { gateways: { status: string }[]; forwardingVerified: boolean }
assert.deepEqual(legacyGateways.gateways.map(row => row.status), ["unknown", "down", "up"]); assert.equal(legacyGateways.forwardingVerified, false)
const beforeDeniedGateway = catalogCalls
await assert.rejects(invokeMcpTool(recursivePrincipal, "mm_recursive_gateways_catalog_get", { serverId: 2 })); assert.equal(catalogCalls, beforeDeniedGateway)
for (const name of ["mm_recursive_routes_get", "mm_recursive_gateways_get"]) await assert.rejects(invokeMcpTool(recursivePrincipal, name, { serverId: 2 }))
assert.equal(catalogCalls, beforeDeniedGateway)
healthUnavailable = true
await assert.rejects(invokeMcpTool(recursivePrincipal, "mm_recursive_gateways_catalog_get", { serverId: 1 }))
healthUnavailable = false; recursiveCatalogRows = []
assert.equal((await invokeMcpTool(recursivePrincipal, "mm_recursive_routes_catalog_get", { serverId: 1 }) as { total: number }).total, 0)
assert.deepEqual((await pool.query("SELECT * FROM recursive_routes WHERE server_id=1 ORDER BY id")).rows, recursiveBeforeObservation)
recursiveCatalogFixtures = false; countCatalogCalls = false
const { storeRecursiveRoutes } = await import("../../services/recursive-route-store.js")
const { readCachedRecursiveRoutes, applyRecursiveToServer } = await import("../../routes/recursive-routes.js")
const cachedRecursive = await readCachedRecursiveRoutes(1), recursiveId = cachedRecursive[0].id
await storeRecursiveRoutes(1, cachedRecursive, "observed")
assert.deepEqual((await pool.query("SELECT * FROM recursive_routes WHERE server_id=1 ORDER BY id")).rows, recursiveBeforeObservation)
const binding = (await pool.query("INSERT INTO filter_rules(server_id,community,gateway_tunnel_id) VALUES(1,'65000:997',$1) RETURNING id", ["rec:" + recursiveId])).rows[0].id
try {
const changed = [{ ...cachedRecursive[0], id: "*RECREATED", gateway: "192.0.2.99%fixture-gre", distance: 7, country: "" }]
assert.equal((await storeRecursiveRoutes(1, changed, "observed"))[0].id, recursiveId)
assert.equal((await readCachedRecursiveRoutes(1))[0].country, "Fixture country")
for (const rows of [[], [{ ...cachedRecursive[0], dstAddress: "198.51.100.0/24" }], [{ ...cachedRecursive[0], routingTable: "other" }]]) {
const beforeWrites = writes
// Invalid metadata is rejected before constructing the RouterOS client.
await assert.rejects(applyRecursiveToServer({ id: 1 } as Parameters<typeof applyRecursiveToServer>[0], rows, "apply"), /BGP/)
assert.equal(writes, beforeWrites)
}
const beforeForeign = (await pool.query("SELECT * FROM recursive_routes WHERE server_id=1")).rows
await assert.rejects(storeRecursiveRoutes(2, [{ ...cachedRecursive[0] }], "apply"), /сервере/)
assert.deepEqual((await pool.query("SELECT * FROM recursive_routes WHERE server_id=1")).rows, beforeForeign)
assert.equal((await pool.query("SELECT gateway_tunnel_id FROM filter_rules WHERE id=$1", [binding])).rows[0].gateway_tunnel_id, "rec:" + recursiveId)
await storeRecursiveRoutes(1, [{ ...cachedRecursive[0], country: "" }], "apply")
assert.equal((await readCachedRecursiveRoutes(1))[0].country, "")
} finally {
await pool.query("DELETE FROM filter_rules WHERE id=$1", [binding])
await pool.query("DELETE FROM recursive_routes WHERE server_id=1")
}
await pool.query("DELETE FROM config_revisions WHERE server_id=1 AND section='recursive-routes'")
console.log("✓ Recursive shared readers: observer has no cache/revision writes, scoped stale fallback and unknown gateway state; SQL stable IDs, no-op timestamps, country ownership, rec bindings and pre-native referenced-prefix rejection")
const { fingerprintPayload: revisionFingerprint } = await import("../../services/config-revisions.js")
const recursiveRevisionIds: string[] = []
const addRecursiveRevision = async (payload: unknown, sid = 1, section = "recursive-routes") => {
const id = randomUUID(); recursiveRevisionIds.push(id)
await pool.query("INSERT INTO config_revisions(id,server_id,section,source,fingerprint,payload) VALUES($1,$2,$3,'apply',$4,$5::jsonb)", [id, sid, section, revisionFingerprint(payload), JSON.stringify(payload)])
return id
}
const restorePayload = [{ id: "historical-id", dstAddress: "192.0.2.0/24", gateway: "192.0.2.2", distance: 0, scope: 0, targetScope: 0, routingTable: "main", checkGateway: "none", country: "fixture-country", comment: "restore-fixture", disabled: false }]
const restoreRevisionId = await addRecursiveRevision(restorePayload)
const recursiveRestoreAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Recursive revision restore", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], limits: { callsPerMinute: 120, concurrentReads: 4, mutationsPerHour: 50, serversPerPlan: 2, objectsPerPlan: 100 }, scope: { serverIds: [1], operationIds: ["routing.recursive.revision.restore"], allowGlobal: false } }), actor)
const recursiveRestorePrincipal = await authenticateMcpToken(recursiveRestoreAccess.token)
const restoreRevisionArgs = { serverId: 1, revisionId: restoreRevisionId }
const foreignRecursive = { ".id": "*foreign-recursive", "dst-address": "0.0.0.0/0", gateway: "192.0.2.254", distance: "1", static: "true", comment: "Keep foreign default" }
recursiveCatalogRows = [{ ".id": "*old-recursive", "dst-address": "192.0.2.0/24", gateway: "192.0.2.1", distance: "1", scope: "30", "target-scope": "10", "routing-table": "main", static: "true", comment: "MikrotikManager:recursive old" }, { ...foreignRecursive }]
recursiveCatalogFixtures = true; recursiveMutations = true; countCatalogCalls = true; catalogCalls = 0
for (const invalidRevision of [await addRecursiveRevision(restorePayload, 2), await addRecursiveRevision(restorePayload, 1, "gre"), await addRecursiveRevision([{}]), await addRecursiveRevision(Array.from({ length: 51 }, (_, index) => ({ ...restorePayload[0], id: String(index) })))]) {
await assert.rejects(invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", { ...restoreRevisionArgs, revisionId: invalidRevision }))
}
assert.equal(catalogCalls, 0)
await pool.query("UPDATE config_revisions SET fingerprint='corrupt' WHERE id=$1", [restoreRevisionId])
await assert.rejects(invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs)); assert.equal(catalogCalls, 0)
await pool.query("UPDATE config_revisions SET fingerprint=$2 WHERE id=$1", [restoreRevisionId, revisionFingerprint(restorePayload)])
await assert.rejects(invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", { ...restoreRevisionArgs, serverId: 2 })); assert.equal(catalogCalls, 0)
const tableRestoreProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'integration')", [tableRestoreProtection, JSON.stringify({ kind: "routing_table", id: "*main", serverId: 1, protection: "deny" })])
await assert.rejects(invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs)); assert.equal(recursiveMutationCount, 0)
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [tableRestoreProtection])
const lowBudgetRestore = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Recursive batch budget", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], limits: { callsPerMinute: 120, concurrentReads: 4, mutationsPerHour: 2, serversPerPlan: 2, objectsPerPlan: 100 }, scope: { serverIds: [1], operationIds: ["routing.recursive.revision.restore"], allowGlobal: false } }), actor)
const lowBudgetPrincipal = await authenticateMcpToken(lowBudgetRestore.token)
await assert.rejects(invokeMcpTool(lowBudgetPrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs), error => error instanceof Error && "code" in error && error.code === "BUDGET_EXCEEDED")
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_plans WHERE connection_id=$1", [lowBudgetRestore.connection.id])).rows[0].n, 0)
const exactBudgetRestore = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Recursive exact budget", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], limits: { mutationsPerHour: 3 }, scope: { serverIds: [1], operationIds: ["routing.recursive.revision.restore"], allowGlobal: false } }), actor)
const exactBudgetPrincipal = await authenticateMcpToken(exactBudgetRestore.token)
const lowBudgetPlan = await invokeMcpTool(exactBudgetPrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs) as { planId: string; changes: { mutationCost: number } }
assert.equal(lowBudgetPlan.changes.mutationCost, 3)
await approvePlan(lowBudgetPlan.planId, actor, true)
// Another accepted operation consumed part of the budget after preview.
await pool.query("INSERT INTO mcp_budget_buckets(connection_id,kind,bucket,used) VALUES($1,'mutations',date_trunc('hour',now()),1)", [exactBudgetRestore.connection.id])
await assert.rejects(applyPlan(exactBudgetPrincipal, lowBudgetPlan.planId, "batch-budget-denied"), error => error instanceof Error && "code" in error && error.code === "BUDGET_EXCEEDED")
assert.equal(recursiveMutationCount, 0)
await pool.query("INSERT INTO recursive_routes(server_id,sort_order,dst_address,gateway,distance,scope,target_scope,routing_table,check_gateway,country,comment,disabled) VALUES(1,0,'192.0.2.0/24','192.0.2.1',1,30,10,'main','none','','old',false)")
const boundRecursiveId = (await pool.query("SELECT id FROM recursive_routes WHERE server_id=1 LIMIT 1")).rows[0].id
const bindRecursiveFilter = async () => {
const result = await pool.query("INSERT INTO filter_rules(server_id,community,gateway_tunnel_id) VALUES(1,'65000:777',$1) RETURNING id", ["rec:" + boundRecursiveId])
return result.rows[0].id
}
const boundFilterId = await bindRecursiveFilter()
await assert.rejects(invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs))
await pool.query("DELETE FROM filter_rules WHERE id=$1", [boundFilterId])
const lateBindingPlan = await invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs) as { planId: string }
await approvePlan(lateBindingPlan.planId, actor, true)
const lateFilterId = await bindRecursiveFilter()
const waitRecursiveOperation = async (id: string) => {
const deadline = Date.now() + 30000
while (Date.now() < deadline) {
const state = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [id])).rows[0].state
if (!["running", "pending"].includes(state)) return state
await delay(30)
}
const state = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [id])).rows[0]?.state
throw Error(`MCP fixture operation did not finish within 30 seconds (state=${state})`)
}
assert.equal(await waitRecursiveOperation((await applyPlan(recursiveRestorePrincipal, lateBindingPlan.planId, randomUUID())).id), "rejected")
assert.equal(recursiveMutationCount, 0)
await pool.query("DELETE FROM filter_rules WHERE id=$1", [lateFilterId])
const staleRevisionPlan = await invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs) as { planId: string }
await approvePlan(staleRevisionPlan.planId, actor, true)
const changedPayload = [{ ...restorePayload[0], distance: 20 }]
await pool.query("UPDATE config_revisions SET payload=$2::jsonb,fingerprint=$3 WHERE id=$1", [restoreRevisionId, JSON.stringify(changedPayload), revisionFingerprint(changedPayload)])
assert.equal(await waitRecursiveOperation((await applyPlan(recursiveRestorePrincipal, staleRevisionPlan.planId, randomUUID())).id), "rejected")
assert.equal(recursiveMutationCount, 0)
await pool.query("UPDATE config_revisions SET payload=$2::jsonb,fingerprint=$3 WHERE id=$1", [restoreRevisionId, JSON.stringify(restorePayload), revisionFingerprint(restorePayload)])
const restoreRevisionPlan = await invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs) as { planId: string }
await approvePlan(restoreRevisionPlan.planId, actor, true)
const budgetBeforeRestore = (await pool.query("SELECT used FROM mcp_budget_buckets WHERE connection_id=$1 AND kind='mutations' AND bucket=date_trunc('hour',now())", [recursiveRestoreAccess.connection.id])).rows[0]?.used ?? 0
const restoredRevisionOperation = await applyPlan(recursiveRestorePrincipal, restoreRevisionPlan.planId, "restore-recursive-once")
assert.equal(await waitRecursiveOperation(restoredRevisionOperation.id), "applied"); assert.equal(recursiveMutationCount, 2)
assert.deepEqual(recursiveCatalogRows.find(row => row[".id"] === "*foreign-recursive"), foreignRecursive)
assert.equal((await pool.query("SELECT distance,country FROM recursive_routes WHERE server_id=1")).rows[0].distance, 0)
assert.equal((await pool.query("SELECT distance,country FROM recursive_routes WHERE server_id=1")).rows[0].country, "fixture-country")
assert.equal((await pool.query("SELECT used FROM mcp_budget_buckets WHERE connection_id=$1 AND kind='mutations' AND bucket=date_trunc('hour',now())", [recursiveRestoreAccess.connection.id])).rows[0].used - budgetBeforeRestore, 3)
await applyPlan(recursiveRestorePrincipal, restoreRevisionPlan.planId, "restore-recursive-once"); assert.equal(recursiveMutationCount, 2)
recursiveIgnorePayload = true
const mismatchedRestore = await invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs) as { planId: string }
await approvePlan(mismatchedRestore.planId, actor, true)
assert.equal(await waitRecursiveOperation((await applyPlan(recursiveRestorePrincipal, mismatchedRestore.planId, randomUUID())).id), "partial")
recursiveIgnorePayload = false
await pool.query("UPDATE recursive_routes SET country='fixture-before-restore' WHERE server_id=1")
await pool.query("CREATE FUNCTION mcp_fixture_wrong_recursive_cache() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.country := 'unexpected-cache-value'; RETURN NEW; END $$")
await pool.query("CREATE TRIGGER mcp_fixture_wrong_recursive_cache BEFORE INSERT OR UPDATE ON recursive_routes FOR EACH ROW EXECUTE FUNCTION mcp_fixture_wrong_recursive_cache()")
try {
const badCacheRestore = await invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs) as { planId: string }
await approvePlan(badCacheRestore.planId, actor, true)
assert.equal(await waitRecursiveOperation((await applyPlan(recursiveRestorePrincipal, badCacheRestore.planId, randomUUID())).id), "partial")
assert.equal((await pool.query("SELECT country FROM recursive_routes WHERE server_id=1")).rows[0].country, "unexpected-cache-value")
} finally {
await pool.query("DROP TRIGGER mcp_fixture_wrong_recursive_cache ON recursive_routes")
await pool.query("DROP FUNCTION mcp_fixture_wrong_recursive_cache()")
}
const revokedBatch = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Revoke inside recursive batch", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1], operationIds: ["routing.recursive.revision.restore"], allowGlobal: false } }), actor)
const revokedBatchPrincipal = await authenticateMcpToken(revokedBatch.token)
const revokeInsidePlan = await invokeMcpTool(revokedBatchPrincipal, "mm_recursive_revision_restore_plan", restoreRevisionArgs) as { planId: string }
await approvePlan(revokeInsidePlan.planId, actor, true)
const beforeRevokedBatch = recursiveMutationCount
recursivePauseConnection = revokedBatch.connection.id
const revokedBatchOperation = await applyPlan(revokedBatchPrincipal, revokeInsidePlan.planId, randomUUID())
assert.equal(await waitRecursiveOperation(revokedBatchOperation.id), "unknown")
assert.equal(recursiveMutationCount - beforeRevokedBatch, 1, "Revocation must stop DELETE inside the same service step after the first acknowledged PUT")
assert.equal(recursiveCatalogRows.filter(row => String(row.comment).startsWith("MikrotikManager:recursive")).length, 2)
await assert.rejects(applyPlan(revokedBatchPrincipal, revokeInsidePlan.planId, randomUUID()))
assert.equal(recursiveMutationCount - beforeRevokedBatch, 1)
const emptyRecursiveRevision = await addRecursiveRevision([])
const clearRecursivePlan = await invokeMcpTool(recursiveRestorePrincipal, "mm_recursive_revision_restore_plan", { ...restoreRevisionArgs, revisionId: emptyRecursiveRevision }) as { planId: string }
await approvePlan(clearRecursivePlan.planId, actor, true)
assert.equal(await waitRecursiveOperation((await applyPlan(recursiveRestorePrincipal, clearRecursivePlan.planId, randomUUID())).id), "applied")
assert.deepEqual(recursiveCatalogRows, [foreignRecursive]); assert.equal((await pool.query("SELECT count(*)::int AS n FROM recursive_routes WHERE server_id=1")).rows[0].n, 0)
const recursiveWriteAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Recursive full-set editor", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], limits: { callsPerMinute: 120, concurrentReads: 4, mutationsPerHour: 50, serversPerPlan: 2, objectsPerPlan: 100 }, scope: { serverIds: [1], operationIds: ["routing.recursive.routes.replace"], allowGlobal: false } }), actor)
const recursiveWritePrincipal = await authenticateMcpToken(recursiveWriteAccess.token)
const directRecursive = { ...restorePayload[0], id: "", country: "direct-country", disabled: true }
for (const invalid of [{ serverId: 2, routes: [] }, { serverId: 1 }, { serverId: 1, routes: [{ ...directRecursive, distance: -1 }] }, { serverId: 1, routes: Array.from({ length: 51 }, () => directRecursive) }]) await assert.rejects(invokeMcpTool(recursiveWritePrincipal, "mm_recursive_routes_replace_plan", invalid))
const directCreate = await invokeMcpTool(recursiveWritePrincipal, "mm_recursive_routes_replace_plan", { serverId: 1, routes: [directRecursive] }) as { planId: string; changes: { mutationCost: number } }
assert.equal(directCreate.changes.mutationCost, 2)
await assert.rejects(applyPlan(recursiveWritePrincipal, directCreate.planId, randomUUID()))
await approvePlan(directCreate.planId, actor, true)
const directCreated = await applyPlan(recursiveWritePrincipal, directCreate.planId, "recursive-direct-once")
assert.equal(await waitRecursiveOperation(directCreated.id), "applied")
const directCreateCount = recursiveMutationCount
await applyPlan(recursiveWritePrincipal, directCreate.planId, "recursive-direct-once"); assert.equal(recursiveMutationCount, directCreateCount)
const directCached = (await readCachedRecursiveRoutes(1))[0]
const directBinding = (await pool.query("INSERT INTO filter_rules(server_id,community,gateway_tunnel_id) VALUES(1,'65000:998',$1) RETURNING id", ["rec:" + directCached.id])).rows[0].id
try {
for (const routes of [[], [{ ...directCached, dstAddress: "198.51.100.0/24" }]]) await assert.rejects(invokeMcpTool(recursiveWritePrincipal, "mm_recursive_routes_replace_plan", { serverId: 1, routes }), /BGP/)
const edited = { ...directCached, gateway: "192.0.2.3", distance: 2, country: "" }
const editPlan = await invokeMcpTool(recursiveWritePrincipal, "mm_recursive_routes_replace_plan", { serverId: 1, routes: [edited] }) as { planId: string; changes: { mutationCost: number } }
assert.equal(editPlan.changes.mutationCost, 3)
await approvePlan(editPlan.planId, actor, true)
assert.equal(await waitRecursiveOperation((await applyPlan(recursiveWritePrincipal, editPlan.planId, randomUUID())).id), "applied")
assert.equal((await readCachedRecursiveRoutes(1))[0].id, directCached.id); assert.equal((await readCachedRecursiveRoutes(1))[0].country, "")
assert.equal((await pool.query("SELECT gateway_tunnel_id FROM filter_rules WHERE id=$1", [directBinding])).rows[0].gateway_tunnel_id, "rec:" + directCached.id)
const staleMetadataPlan = await invokeMcpTool(recursiveWritePrincipal, "mm_recursive_routes_replace_plan", { serverId: 1, routes: [edited] }) as { planId: string }
await approvePlan(staleMetadataPlan.planId, actor, true)
await pool.query("UPDATE recursive_routes SET country='late-metadata' WHERE id=$1", [directCached.id])
const beforeStale = recursiveMutationCount
assert.equal(await waitRecursiveOperation((await applyPlan(recursiveWritePrincipal, staleMetadataPlan.planId, randomUUID())).id), "rejected")
assert.equal(recursiveMutationCount, beforeStale)
} finally { await pool.query("DELETE FROM filter_rules WHERE id=$1", [directBinding]) }
const directClear = await invokeMcpTool(recursiveWritePrincipal, "mm_recursive_routes_replace_plan", { serverId: 1, routes: [], source: "copy" }) as { planId: string }
await approvePlan(directClear.planId, actor, true)
assert.equal(await waitRecursiveOperation((await applyPlan(recursiveWritePrincipal, directClear.planId, randomUUID())).id), "applied")
assert.deepEqual(recursiveCatalogRows, [foreignRecursive]); assert.deepEqual(await readCachedRecursiveRoutes(1), [])
console.log("✓ Recursive full-set editor: explicit human approval, complete batch cost, empty/create/edit/copy, stable BGP binding, country clear, sealed metadata drift, foreign route retention and no replay")
recursiveCatalogFixtures = false; recursiveMutations = false; countCatalogCalls = false
await pool.query("DELETE FROM config_revisions WHERE server_id=1 AND section='recursive-routes' OR id=ANY($1::text[])", [recursiveRevisionIds])
console.log("✓ Recursive revision restore seals scoped history/full owned set, blocks dependent BGP filters and drift, reserves all batch writes, preserves foreign routes, verifies native/cache/revision and supports explicit empty without replay")
const backupJobActor: AuthUser = { ...actor, id: "backup-job-owner", permissions: ["mm:settings:admin", "mm:backups:read"] }
const backupJobAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped backup progress", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:backups:read"], scope: { serverIds: [1], operationIds: ["backups.jobs.read"], allowGlobal: false } }), backupJobActor)
const backupJobPrincipal = await authenticateMcpToken(backupJobAccess.token)
const { createBackupsRoutes } = await import("../../routes/backups.js"), { databaseBackgroundWork } = await import("../../services/database-background-work.js"), { readBackupJob } = await import("../../services/backup-job-store.js")
let releaseBackupJob!: () => void
const waitBackupJob = new Promise<void>(resolve => { releaseBackupJob = resolve })
const backupJobsHttp = FilterFastify(); backupJobsHttp.setValidatorCompiler(filterValidator); backupJobsHttp.setSerializerCompiler(filterSerializer)
await backupJobsHttp.register(createBackupsRoutes({ listServers: async () => [{ id: 1 }, { id: 2 }], appendEvent: async () => {}, create: async id => {
await waitBackupJob
if (id === "2") throw Error("NEVER_BACKUP_JOB_FAILURE")
return { id: randomUUID(), serverId: 1, serverName: "NEVER_BACKUP_JOB_SERVER", filename: "NEVER_BACKUP_JOB_FILE", sizeBytes: 0, createdAt: new Date().toISOString(), kind: "manual", storage: "both", s3Key: "NEVER_BACKUP_JOB_KEY", uploadError: "NEVER_BACKUP_JOB_UPLOAD", notes: "NEVER_BACKUP_JOB_NOTE" }
} }), { prefix: "/api" })
let singleBackupJobId = ""
const backupWritesBefore = writes
try {
const started = await backupJobsHttp.inject({ method: "POST", url: "/api/backups/create", payload: { serverIds: [1], notes: "NEVER_BACKUP_JOB_NOTES" } })
assert.equal(started.statusCode, 202, started.body); singleBackupJobId = started.json().jobId
const pendingJob = await invokeMcpTool(backupJobPrincipal, "mm_backup_job_get", { jobId: singleBackupJobId }) as { completed: number; terminal: boolean; ephemeral: boolean }
assert.equal(pendingJob.completed, 0); assert.equal(pendingJob.terminal, false); assert.equal(pendingJob.ephemeral, true)
releaseBackupJob(); await databaseBackgroundWork.drain()
const restJob = (await backupJobsHttp.inject({ method: "GET", url: "/api/backups/jobs/" + singleBackupJobId })).json()
const finishedJob = await invokeMcpTool(backupJobPrincipal, "mm_backup_job_get", { jobId: singleBackupJobId, limit: 1 }) as { status: string; completed: number; hasUploadErrors: boolean; created: { items: { sizeBytes: number }[] } }
assert.equal(finishedJob.status, restJob.status); assert.equal(finishedJob.completed, restJob.completed); assert.equal(finishedJob.hasUploadErrors, true); assert.equal(finishedJob.created.items[0].sizeBytes, 0)
assert.equal(JSON.stringify(finishedJob).includes("NEVER_BACKUP_JOB"), false)
const emptyPage = await invokeMcpTool(backupJobPrincipal, "mm_backup_job_get", { jobId: singleBackupJobId, offset: 1, limit: 1 }) as { created: { items: unknown[]; total: number } }
assert.deepEqual(emptyPage.created.items, []); assert.equal(emptyPage.created.total, 1)
const mixed = await backupJobsHttp.inject({ method: "POST", url: "/api/backups/create", payload: { serverIds: [1, 2] } })
assert.equal(mixed.statusCode, 202); await databaseBackgroundWork.drain()
await assert.rejects(invokeMcpTool(backupJobPrincipal, "mm_backup_job_get", { jobId: mixed.json().jobId }), /не найдена/)
await assert.rejects(invokeMcpTool(backupJobPrincipal, "mm_backup_job_get", { jobId: "missing-job" }), /не найдена/)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE connection_id=$1 AND result::text LIKE '%NEVER_BACKUP_JOB%'", [backupJobAccess.connection.id])).rows[0].n, 0)
assert.equal(writes, backupWritesBefore)
} finally { releaseBackupJob(); await databaseBackgroundWork.drain(); await backupJobsHttp.close() }
assert.equal(readBackupJob(singleBackupJobId), undefined)
console.log("✓ Backup jobs share the actual REST queue: scoped whole-job visibility, queued/running/done progress, zero/upload status, bounded pages, no note/path/error leakage in response/audit, no RouterOS requests and app-close invalidation")
const storageActor: AuthUser={...actor,id:"backup-storage-owner",permissions:["mm:settings:admin","mm:backups:admin"]}
const storageServerIds=(await pool.query("SELECT id FROM servers ORDER BY id")).rows.map(row=>Number(row.id))
const storagePolicy={name:"Backup storage settings",mode:"approval",expiresAt:new Date(Date.now()+1800000).toISOString(),permissions:["mm:backups:write"],limits:{callsPerMinute:120,concurrentReads:4,mutationsPerHour:50,serversPerPlan:10,objectsPerPlan:100},scope:{serverIds:storageServerIds,operationIds:["backups.storage.update"],allowGlobal:true}}
const storageAccess=await createMcpConnection(mcpConnectionCreateSchema.parse(storagePolicy),storageActor),storagePrincipal=await authenticateMcpToken(storageAccess.token)
const oldStorageRows=(await pool.query("SELECT * FROM backup_storage_settings WHERE id=1")).rows
const storageSecretIds:string[]=[],storageEntryId=randomUUID(),storageProtection=randomUUID()
const {backupStorageSecretPurpose}=await import("./backup-storage-actions.js"),{withBackupStorageOperation}=await import("../../services/backup-storage-operation.js")
const storageSettings={provider:"s3" as const,s3Endpoint:"https://s3.example.test",s3Region:"us-east-1",s3Bucket:"backups",s3Prefix:"mcp-fixture",s3AccessKeyId:"fixture-access",s3ForcePathStyle:true,keepLocalCopy:true}
const storageSecretValue="NEVER_STORAGE_SECRET_INITIAL"
const addStorageSecret=async(purpose=backupStorageSecretPurpose(storageSettings),owner=storageActor.id,serverId:number|null=null,value=storageSecretValue)=>{
const id=randomUUID();storageSecretIds.push(id)
await pool.query("INSERT INTO mcp_secrets(id,purpose,server_id,ciphertext,created_by) VALUES($1,$2,$3,$4,$5)",[id,purpose,serverId,await encryptSecret(value),owner])
return id
}
const storageWritesBefore=writes
let releaseStorage:()=>void=()=>{},storagePending:Promise<unknown>|undefined
try {
const secretRef=await addStorageSecret(),settingsArgs={settings:storageSettings,secretRef}
const partialAccess=await createMcpConnection(mcpConnectionCreateSchema.parse({...storagePolicy,name:"Partial storage scope",scope:{...storagePolicy.scope,serverIds:[1]}}),storageActor)
await assert.rejects(invokeMcpTool(await authenticateMcpToken(partialAccess.token),"mm_backup_storage_update_plan",settingsArgs),/вне разрешённой области/)
for(const invalid of [{},{settings:{s3SecretAccessKey:"NEVER_STORAGE_LITERAL"}},{settings:{s3Endpoint:"https://user:[email protected]"}},{settings:storageSettings,secretRef:await addStorageSecret("wrong-purpose")},{settings:storageSettings,secretRef:await addStorageSecret(undefined,"other-owner")},{settings:storageSettings,secretRef:await addStorageSecret(undefined,storageActor.id,1)}])await assert.rejects(invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",invalid))
const first=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",settingsArgs) as {planId:string}
assert.equal(JSON.stringify(first).includes(storageSecretValue),false)
await assert.rejects(applyPlan(storagePrincipal,first.planId,randomUUID()))
assert.deepEqual((await pool.query("SELECT * FROM backup_storage_settings WHERE id=1")).rows,oldStorageRows)
await approvePlan(first.planId,storageActor,true)
const applied=await applyPlan(storagePrincipal,first.planId,"storage-config-once")
assert.equal(await waitRecursiveOperation(applied.id),"applied")
const saved=(await pool.query("SELECT * FROM backup_storage_settings WHERE id=1")).rows
assert.equal(saved[0].s3_secret_access_key,storageSecretValue);assert.equal(saved[0].s3_endpoint,storageSettings.s3Endpoint);assert.equal(saved[0].last_test_at,null)
assert.equal((await pool.query("SELECT result FROM mcp_operation_steps WHERE operation_id=$1",[applied.id])).rows[0].result.storageTestVerified,false)
await applyPlan(storagePrincipal,first.planId,"storage-config-once")
assert.deepEqual((await pool.query("SELECT * FROM backup_storage_settings WHERE id=1")).rows,saved)
const newStorageEndpoint="https://other.example.test"
await assert.rejects(invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{s3Endpoint:newStorageEndpoint}}),/новое назначение/)
const moveRef=await addStorageSecret(backupStorageSecretPurpose({...storageSettings,s3Endpoint:newStorageEndpoint}),storageActor.id,null,"NEVER_STORAGE_MOVED")
const movePlan=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{s3Endpoint:newStorageEndpoint},secretRef:moveRef}) as {planId:string}
await approvePlan(movePlan.planId,storageActor,true)
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,movePlan.planId,randomUUID())).id),"applied")
assert.equal((await pool.query("SELECT s3_endpoint,s3_secret_access_key FROM backup_storage_settings WHERE id=1")).rows[0].s3_endpoint,newStorageEndpoint)
const moveBack=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{s3Endpoint:storageSettings.s3Endpoint},secretRef}) as {planId:string}
await approvePlan(moveBack.planId,storageActor,true)
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,moveBack.planId,randomUUID())).id),"applied")
const dormant=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{provider:"local",s3Bucket:""}}) as {planId:string}
await approvePlan(dormant.planId,storageActor,true)
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,dormant.planId,randomUUID())).id),"applied")
assert.equal((await pool.query("SELECT s3_bucket FROM backup_storage_settings WHERE id=1")).rows[0].s3_bucket,"")
await assert.rejects(invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:storageSettings}),/новое назначение/)
const enableAgain=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",settingsArgs) as {planId:string}
await approvePlan(enableAgain.planId,storageActor,true)
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,enableAgain.planId,randomUUID())).id),"applied")
const beforeArchive=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{keepLocalCopy:false}}) as {planId:string}
await approvePlan(beforeArchive.planId,storageActor,true)
await pool.query("INSERT INTO backup_entries(id,server_id,server_name,filename,size_bytes,kind,storage,s3_key,created_at) VALUES($1,1,'fixture',$2,0,'manual','s3','mcp-fixture/object.rsc',now())",[storageEntryId,storageEntryId+".rsc"])
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,beforeArchive.planId,randomUUID())).id),"rejected")
assert.equal((await pool.query("SELECT keep_local_copy FROM backup_storage_settings WHERE id=1")).rows[0].keep_local_copy,true)
for(const settings of [{provider:"local"},{s3Endpoint:"https://other.example.test"},{s3Bucket:"other"},{s3Region:"other"},{s3ForcePathStyle:false}])await assert.rejects(invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings}),/архивы/)
const prefixPlan=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{s3Prefix:"mcp-fixture-new",keepLocalCopy:false}}) as {planId:string}
await approvePlan(prefixPlan.planId,storageActor,true)
await pool.query("UPDATE backup_storage_settings SET last_test_at=now(),last_test_error='NEVER_STORAGE_OBSERVER_ERROR' WHERE id=1")
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,prefixPlan.planId,randomUUID())).id),"applied")
const afterPrefix=(await pool.query("SELECT * FROM backup_storage_settings WHERE id=1")).rows[0]
assert.equal(afterPrefix.keep_local_copy,false);assert.equal(afterPrefix.s3_prefix,"mcp-fixture-new");assert.equal(afterPrefix.s3_secret_access_key,storageSecretValue);assert.equal(afterPrefix.last_test_at,null);assert.equal(afterPrefix.last_test_error,null)
const staleKey=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{keepLocalCopy:true}}) as {planId:string}
await approvePlan(staleKey.planId,storageActor,true)
await pool.query("UPDATE backup_storage_settings SET s3_secret_access_key='NEVER_STORAGE_EXTERNALLY_CHANGED' WHERE id=1")
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,staleKey.planId,randomUUID())).id),"rejected")
await pool.query("UPDATE backup_storage_settings SET s3_secret_access_key=$1 WHERE id=1",[storageSecretValue])
const rotationRef=await addStorageSecret(undefined,storageActor.id,null,"NEVER_STORAGE_ROTATION")
const rotationPlan=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{secretRef:rotationRef}) as {planId:string}
await approvePlan(rotationPlan.planId,storageActor,true)
await pool.query("DELETE FROM mcp_secrets WHERE id=$1",[rotationRef])
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,rotationPlan.planId,randomUUID())).id),"rejected")
const validRotationRef=await addStorageSecret(undefined,storageActor.id,null,"NEVER_STORAGE_ROTATION_VALID")
const validRotation=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{secretRef:validRotationRef}) as {planId:string}
await approvePlan(validRotation.planId,storageActor,true)
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,validRotation.planId,randomUUID())).id),"applied")
assert.equal((await pool.query("SELECT s3_secret_access_key FROM backup_storage_settings WHERE id=1")).rows[0].s3_secret_access_key,"NEVER_STORAGE_ROTATION_VALID")
const newServerPlan=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{keepLocalCopy:true}}) as {planId:string}
await approvePlan(newServerPlan.planId,storageActor,true)
await pool.query("INSERT INTO servers(id,name,host,username,password) VALUES(49,'storage-catalog-fixture','127.0.0.1','admin','fixture')")
try{assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,newServerPlan.planId,randomUUID())).id),"rejected")}finally{await pool.query("DELETE FROM servers WHERE id=49")}
storagePending=withBackupStorageOperation(()=>new Promise<void>(resolve=>{releaseStorage=resolve}))
await Promise.resolve()
await assert.rejects(invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{keepLocalCopy:true}}),/занято/)
releaseStorage();await storagePending
const lateBusy=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{keepLocalCopy:true}}) as {planId:string}
await approvePlan(lateBusy.planId,storageActor,true)
storagePending=withBackupStorageOperation(()=>new Promise<void>(resolve=>{releaseStorage=resolve}))
await Promise.resolve()
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,lateBusy.planId,randomUUID())).id),"rejected")
releaseStorage();await storagePending
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'fixture')",[storageProtection,JSON.stringify({kind:"backup-storage",id:"1",protection:"deny"})])
await assert.rejects(invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{keepLocalCopy:true}}))
await pool.query("DELETE FROM mcp_protections WHERE id=$1",[storageProtection])
await pool.query("CREATE FUNCTION mcp_fixture_ignore_storage() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.keep_local_copy := OLD.keep_local_copy; RETURN NEW; END $$")
await pool.query("CREATE TRIGGER mcp_fixture_ignore_storage BEFORE UPDATE ON backup_storage_settings FOR EACH ROW EXECUTE FUNCTION mcp_fixture_ignore_storage()")
try {
const ignored=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{keepLocalCopy:true}}) as {planId:string}
await approvePlan(ignored.planId,storageActor,true)
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,ignored.planId,randomUUID())).id),"partial")
assert.equal((await pool.query("SELECT keep_local_copy FROM backup_storage_settings WHERE id=1")).rows[0].keep_local_copy,false)
}finally{await pool.query("DROP TRIGGER mcp_fixture_ignore_storage ON backup_storage_settings");await pool.query("DROP FUNCTION mcp_fixture_ignore_storage()")}
await pool.query("CREATE FUNCTION mcp_fixture_change_storage_bucket() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.s3_bucket := 'unexpected-bucket'; RETURN NEW; END $$")
await pool.query("CREATE TRIGGER mcp_fixture_change_storage_bucket BEFORE UPDATE ON backup_storage_settings FOR EACH ROW EXECUTE FUNCTION mcp_fixture_change_storage_bucket()")
try{
const changedUnspecified=await invokeMcpTool(storagePrincipal,"mm_backup_storage_update_plan",{settings:{keepLocalCopy:true}}) as {planId:string}
await approvePlan(changedUnspecified.planId,storageActor,true)
assert.equal(await waitRecursiveOperation((await applyPlan(storagePrincipal,changedUnspecified.planId,randomUUID())).id),"partial")
}finally{await pool.query("DROP TRIGGER mcp_fixture_change_storage_bucket ON backup_storage_settings");await pool.query("DROP FUNCTION mcp_fixture_change_storage_bucket()")}
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE connection_id=$1 AND result::text LIKE '%NEVER_STORAGE%'",[storageAccess.connection.id])).rows[0].n,0)
assert.equal(writes,storageWritesBefore)
}finally{
releaseStorage();await storagePending
await pool.query("DELETE FROM mcp_protections WHERE id=$1",[storageProtection])
await pool.query("DELETE FROM backup_entries WHERE id=$1",[storageEntryId])
await pool.query("DELETE FROM mcp_secrets WHERE id=ANY($1::uuid[])",[storageSecretIds])
await pool.query("DELETE FROM backup_storage_settings WHERE id=1")
if(oldStorageRows[0])await pool.query("INSERT INTO backup_storage_settings SELECT * FROM jsonb_populate_record(NULL::backup_storage_settings,$1::jsonb)",[JSON.stringify(oldStorageRows[0])])
}
console.log("✓ Backup storage shares REST mutation: full global scope, human approval, private credential/secret-ref proof, destination/owner binding, remote archives, late catalog/credential/busy drift, preserved key, test invalidation, protection, partial verification and no replay or network dispatch")
const internetPathAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped Internet path history", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1], operationIds: ["routing.internet-path.latest.read"], allowGlobal: false } }), actor)
const internetPathPrincipal = await authenticateMcpToken(internetPathAccess.token)
const internetPathHttp = FilterFastify(); internetPathHttp.setValidatorCompiler(filterValidator); internetPathHttp.setSerializerCompiler(filterSerializer)
await internetPathHttp.register((await import("../../routes/internet-path.js")).default,{prefix:"/api"})
const internetPathIds: number[]=[]
const pathSnapshotTime=new Date().toISOString()
const {ensurePartitionFor:ensurePathPartition}=await import("../../db/partitions.js")
for(const delta of [-3600000,0,3600000])await ensurePathPartition(pool,"internet_path_snapshots","week",new Date(Date.parse(pathSnapshotTime)+delta))
const pathPayload={collectionComplete:true,sampledAt:pathSnapshotTime,internetTarget:"1.1.1.1",
servers:[{id:"1",name:"Visible home",type:"home-router",enabled:true,password:"NEVER_PATH_SECRET"},{id:"2",name:"NEVER_PATH_HIDDEN",enabled:"malformed"}],
greTunnels:[{id:"gre1",serverId:"1",name:"fixture-gre",enabled:true,status:"up",ipsec:{secret:"NEVER_PATH_SECRET"},comment:"NEVER_PATH_SECRET"},{id:"NEVER_PATH_HIDDEN",serverId:"2",mtu:"bad"}],
filtersRulesets:[{serverId:"1",rules:[{id:"r1",community:"65000:1",action:"route",gateway:"192.0.2.1",description:"NEVER_PATH_SECRET"},{id:"r2",community:"65000:2",action:"blackhole"}]},{serverId:"2",rules:"malformed"}],
speedProbes:[{id:"p1",srcServerId:"1",dstServerId:"1",lastTxAvgMbps:0,lastError:"NEVER_PATH_SECRET"},{id:"NEVER_PATH_HIDDEN",srcServerId:"1",dstServerId:"2",lastTxAvgMbps:"bad"}],
routeLookupByServerId:{"1":{gateway:null,routingMark:null},"2":"NEVER_PATH_HIDDEN"},
wanRuntimeByHomeId:{"1":{defaultGateway:null,defaultInterface:null,uplinks:[{id:"wan",iface:"ether1",isDefault:false,password:"NEVER_PATH_SECRET"} ]},"2":"malformed"},
}
countCatalogCalls=true;catalogCalls=0
try {
assert.equal((await pool.query("SELECT count(*)::int AS n FROM internet_path_snapshots")).rows[0].n,0)
assert.equal((await invokeMcpTool(internetPathPrincipal,"mm_internet_path_latest_get",{}) as {snapshot:unknown}).snapshot,null)
const id=(await pool.query("INSERT INTO internet_path_snapshots(sampled_at,payload_json) VALUES($1,$2::jsonb) RETURNING id",[pathSnapshotTime,JSON.stringify(pathPayload)])).rows[0].id
internetPathIds.push(id)
const observed=await invokeMcpTool(internetPathPrincipal,"mm_internet_path_latest_get",{limit:1}) as {snapshot:{servers:{items:{id:number}[]};greTunnels:{items:{mtu:null}[]};speedProbes:{items:{lastTxAvgMbps:number;lastRxAvgMbps:null}[];total:number};filtersRulesets:{items:{rules:{total:number;nextOffset:number}}[]};live:boolean;forwardingVerified:boolean;stale:boolean};incomplete:boolean}
assert.equal(observed.snapshot.servers.items.length,1);assert.equal(observed.snapshot.servers.items[0].id,1)
assert.equal(observed.snapshot.speedProbes.total,1);assert.equal(observed.snapshot.speedProbes.items[0].lastTxAvgMbps,0);assert.equal(observed.snapshot.speedProbes.items[0].lastRxAvgMbps,null)
assert.equal(observed.snapshot.greTunnels.items[0].mtu,null);assert.equal(observed.snapshot.filtersRulesets.items[0].rules.total,2);assert.equal(observed.snapshot.filtersRulesets.items[0].rules.nextOffset,1)
assert.equal(observed.snapshot.live,false);assert.equal(observed.snapshot.forwardingVerified,false);assert.equal(observed.snapshot.stale,false);assert.equal(observed.incomplete,true)
assert.equal(JSON.stringify(observed).includes("NEVER_PATH"),false)
const rest=await internetPathHttp.inject({method:"GET",url:"/api/internet-path/latest"})
assert.equal(rest.statusCode,200);assert.equal(rest.json().sampledAt,pathSnapshotTime);assert.equal(rest.json().snapshot.servers.length,2)
await assert.rejects(invokeMcpTool(internetPathPrincipal,"mm_internet_path_latest_get",{serverId:2}))
const updatePath=async(payload:unknown,time=pathSnapshotTime)=>pool.query("UPDATE internet_path_snapshots SET payload_json=$2::jsonb,sampled_at=$3 WHERE id=$1",[id,JSON.stringify(payload),time])
for(const bad of [{...pathPayload,greTunnels:[pathPayload.greTunnels[0],pathPayload.greTunnels[0]]},{...pathPayload,greTunnels:[{id:"unbound"}]},{...pathPayload,servers:{bad:true}},"legacy serialized payload",{...pathPayload,filtersRulesets:[{serverId:"1",rules:"bad"}]}]){
await updatePath(bad);await assert.rejects(invokeMcpTool(internetPathPrincipal,"mm_internet_path_latest_get",{}),/не подтверждён/)
}
const pastTime=new Date(Date.now()-3600000).toISOString()
await updatePath({...pathPayload,sampledAt:pastTime},pastTime)
assert.equal((await invokeMcpTool(internetPathPrincipal,"mm_internet_path_latest_get",{}) as {snapshot:{stale:boolean}}).snapshot.stale,true)
const futureTime=new Date(Date.now()+3600000).toISOString()
await updatePath({...pathPayload,sampledAt:futureTime},futureTime)
const future=await invokeMcpTool(internetPathPrincipal,"mm_internet_path_latest_get",{}) as {snapshot:{clockSkew:boolean;stale:boolean}}
assert.equal(future.snapshot.clockSkew,true);assert.equal(future.snapshot.stale,true)
assert.equal(catalogCalls,0)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE connection_id=$1 AND result::text LIKE '%NEVER_PATH%'",[internetPathAccess.connection.id])).rows[0].n,0)
} finally {countCatalogCalls=false;await internetPathHttp.close();await pool.query("DELETE FROM internet_path_snapshots WHERE id=ANY($1::bigint[])",[internetPathIds])}
console.log("✓ Stored Internet path: shared latest REST source, SQL projection before parsing hidden/mixed records, nested pages, zero/unknown fields, omitted GRE keys/notes, stale/future/malformed source, scoped audit and no device requests; no current routing claim")
const deviceStateAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped device states", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read", "mm:certificates:read"], scope: { serverIds: [1], operationIds: ["containers.state.read", "certificates.state.read"], allowGlobal: false } }), { ...actor, permissions: [...actor.permissions, "mm:certificates:admin"] })
const deviceStatePrincipal = await authenticateMcpToken(deviceStateAccess.token)
deviceStateFixtures = true; countCatalogCalls = true; catalogCalls = 0
const containerState = await invokeMcpTool(deviceStatePrincipal, "mm_containers_state_get", { limit: 1 }) as { servers: { serverId: number; availability: string; containers: { status: string; envs: { value: string }[] }[]; total: number; nextOffset: number; failures: unknown[] }[] }
assert.equal(containerState.servers.length, 1); assert.equal(containerState.servers[0].serverId, 1); assert.equal(containerState.servers[0].total, 2); assert.equal(containerState.servers[0].nextOffset, 1)
assert.equal(containerState.servers[0].availability, "available"); assert.equal(containerState.servers[0].containers[0].status, "running"); assert.equal(containerState.servers[0].failures.length, 0)
assert.equal(containerState.servers[0].containers[0].envs[0].value, "[redacted]")
assert.ok(!JSON.stringify(containerState).includes("never-return")); assert.equal(catalogCalls, 3)
await assert.rejects(invokeMcpTool(deviceStatePrincipal, "mm_containers_state_get", { serverId: 2 })); assert.equal(catalogCalls, 3)
const containerNext = await invokeMcpTool(deviceStatePrincipal, "mm_containers_state_get", { offset: 1, limit: 1 }) as typeof containerState
assert.equal(containerNext.servers[0].containers[0].status, "unknown")
containerStateFailure = "envs"
const partialContainers = await invokeMcpTool(deviceStatePrincipal, "mm_containers_state_get", {}) as { servers: { failures: { resource: string }[] }[]; incomplete: boolean }
assert.equal(partialContainers.servers[0].failures[0].resource, "envs"); assert.equal(partialContainers.incomplete, true)
containerStateFailure = "unsupported"
const unsupportedContainers = await invokeMcpTool(deviceStatePrincipal, "mm_containers_state_get", {}) as { servers: { availability: string; containers: unknown[] }[]; incomplete: boolean }
assert.equal(unsupportedContainers.servers[0].availability, "unsupported"); assert.equal(unsupportedContainers.servers[0].containers.length, 0); assert.equal(unsupportedContainers.incomplete, true)
containerStateFailure = "none"; catalogCalls = 0
const certificateState = await invokeMcpTool(deviceStatePrincipal, "mm_certificates_state_get", { limit: 1 }) as { servers: { serverId: string; certificates: { status: string; validUntil: string | null }[]; total: number; nextOffset: number; error: string | null }[]; incomplete: boolean }
assert.equal(certificateState.servers.length, 1); assert.equal(certificateState.servers[0].serverId, "1"); assert.equal(certificateState.servers[0].total, 2); assert.equal(certificateState.servers[0].nextOffset, 1)
assert.equal(certificateState.servers[0].certificates[0].status, "valid"); assert.equal(certificateState.servers[0].certificates[0].validUntil, "2034-12-31T17:00:00.000Z"); assert.equal(certificateState.servers[0].error, null)
assert.ok(!JSON.stringify(certificateState).includes("never-return")); assert.equal(catalogCalls, 3)
await assert.rejects(invokeMcpTool(deviceStatePrincipal, "mm_certificates_state_get", { serverId: 2 })); assert.equal(catalogCalls, 3)
certificateClockKnown = false
const unknownCertificate = await invokeMcpTool(deviceStatePrincipal, "mm_certificates_state_get", {}) as typeof certificateState
assert.equal(unknownCertificate.servers[0].certificates[0].status, "unknown"); assert.equal(unknownCertificate.servers[0].certificates[0].validUntil, null)
certificateClockKnown = true; healthUnavailable = true
const failedCertificates = await invokeMcpTool(deviceStatePrincipal, "mm_certificates_state_get", {}) as typeof certificateState
assert.ok(failedCertificates.servers[0].error); assert.equal(failedCertificates.incomplete, true)
healthUnavailable = false
const beforeEmptyPage = catalogCalls
const emptyDevicePage = await invokeMcpTool(deviceStatePrincipal, "mm_containers_state_get", { serverOffset: 1 }) as { servers: unknown[]; incomplete: boolean }
assert.equal(emptyDevicePage.servers.length, 0); assert.equal(emptyDevicePage.incomplete, true); assert.equal(catalogCalls, beforeEmptyPage)
await pool.query("UPDATE servers SET enabled=false WHERE id=1")
assert.equal((await invokeMcpTool(deviceStatePrincipal, "mm_certificates_state_get", {}) as typeof certificateState).servers.length, 0)
assert.equal(catalogCalls, beforeEmptyPage)
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE connection_id=$1 AND result::text LIKE '%never-return%'", [deviceStateAccess.connection.id])).rows[0].n, 0)
const { default: ContainersFastify } = await import("fastify")
const { validatorCompiler: containerValidator, serializerCompiler: containerSerializer } = await import("@fastify/type-provider-zod")
const containersHttp = ContainersFastify(); containersHttp.setValidatorCompiler(containerValidator); containersHttp.setSerializerCompiler(containerSerializer)
await containersHttp.register((await import("../../routes/containers.js")).default, { prefix: "/api" })
await containersHttp.register((await import("../../routes/certificates.js")).default, { prefix: "/api" })
const otherEnabled = (await pool.query("SELECT id FROM servers WHERE enabled AND id<>1")).rows.map(row => row.id)
await pool.query("UPDATE servers SET enabled=false WHERE id=ANY($1::bigint[])", [otherEnabled])
try {
const fullState = await invokeMcpTool(deviceStatePrincipal, "mm_containers_state_get", {}) as { servers: { containers: { id:string; rosId:string; status:string; startOnBoot:boolean|null; envs:{value:string}[] }[] }[] }
for (const url of ["/api/containers", "/api/servers/1/containers"]) {
const response = await containersHttp.inject({method:"GET",url}); assert.equal(response.statusCode,200,response.body)
const restRows = response.json().containers as typeof fullState.servers[0]["containers"]
assert.deepEqual(restRows.map(row=>({id:row.id,rosId:row.rosId,status:row.status,startOnBoot:row.startOnBoot})),fullState.servers[0].containers.map(row=>({id:row.id,rosId:row.rosId,status:row.status,startOnBoot:row.startOnBoot})))
assert.equal(restRows[0].envs[0].value,"never-return-this-env"); assert.equal(fullState.servers[0].containers[0].envs[0].value,"[redacted]")
}
reverseContainerRows = true
assert.equal((await invokeMcpTool(deviceStatePrincipal,"mm_containers_state_get",{limit:1}) as typeof fullState).servers[0].containers[0].rosId,"*c1")
const exhausted = await invokeMcpTool(deviceStatePrincipal,"mm_containers_state_get",{offset:100}) as {incomplete:boolean;servers:{containers:unknown[]}[]}
assert.equal(exhausted.incomplete,true); assert.equal(exhausted.servers[0].containers.length,0)
containerStateFailure = "envs"
for (const url of ["/api/containers","/api/servers/1/containers"]) assert.equal((await containersHttp.inject({method:"GET",url})).statusCode,502)
containerStateFailure = "unsupported"
assert.deepEqual((await containersHttp.inject({method:"GET",url:"/api/containers"})).json(),{containers:[]})
assert.equal((await invokeMcpTool(deviceStatePrincipal,"mm_containers_state_get",{}) as {servers:{availability:string}[]}).servers[0].availability,"unsupported")
for (const method of ["GET","POST"] as const) {
const response = await containersHttp.inject({method,url:method==="GET"?"/api/certificates":"/api/certificates/refresh"})
assert.equal(response.statusCode,200,response.body); assert.equal(response.json().failures.length,0)
const observed = await invokeMcpTool(deviceStatePrincipal,"mm_certificates_state_get",{}) as {servers:{certificates:{id:string;name:string;status:string;validUntil:string|null}[]}[]}
assert.deepEqual(response.json().certificates.map((row:{id:string;name:string})=>({id:row.id,name:row.name})),observed.servers[0].certificates.map(row=>({id:row.id,name:row.name})))
assert.equal(observed.servers[0].certificates[0].validUntil,"2034-12-31T17:00:00.000Z"); assert.equal(observed.servers[0].certificates[1].status,"unknown")
assert.ok(!JSON.stringify(response.json()).includes("never-return-certificate-key"))
}
const certificateEnd = await invokeMcpTool(deviceStatePrincipal,"mm_certificates_state_get",{offset:100}) as {incomplete:boolean;servers:{certificates:unknown[]}[]}
assert.equal(certificateEnd.incomplete,true); assert.equal(certificateEnd.servers[0].certificates.length,0)
const { listCertificatesFromServers: legacyCertificateCatalog } = await import("../../services/certificates-service.js")
const noCertificatePolls = catalogCalls; assert.deepEqual(await legacyCertificateCatalog([]),{certificates:[],failures:[]}); assert.equal(catalogCalls,noCertificatePolls)
certificateStateMalformed = true
for (const method of ["GET","POST"] as const) {
const response = await containersHttp.inject({method,url:method==="GET"?"/api/certificates":"/api/certificates/refresh"})
assert.equal(response.statusCode,200,response.body); assert.equal(response.json().certificates.length,0); assert.equal(response.json().failures.length,1)
assert.equal(response.json().failures[0].error,"Некорректный ответ каталога сертификатов")
}
const invalidCertificates = await invokeMcpTool(deviceStatePrincipal,"mm_certificates_state_get",{}) as {incomplete:boolean;servers:{error:string}[]}
assert.equal(invalidCertificates.incomplete,true); assert.equal(invalidCertificates.servers[0].error,"Некорректный ответ каталога сертификатов")
} finally {
containerStateFailure = "none"; reverseContainerRows = false; certificateStateMalformed = false
await pool.query("UPDATE servers SET enabled=true WHERE id=ANY($1::bigint[])",[otherEnabled]); await containersHttp.close()
}
deviceStateFixtures = false; countCatalogCalls = false
console.log("✓ Container/certificate states use shared collectors with pre-poll scope, paging, explicit unsupported/partial/unknown, timezone evidence and no env/command/key leakage in response or audit")
const serverHistoryAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Server history and source address", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:servers:read"], scope: { serverIds: [1], operationIds: ["servers.snapshots.read", "servers.source-address.read"], allowGlobal: false } }), actor)
const serverHistoryPrincipal = await authenticateMcpToken(serverHistoryAccess.token)
await (await import("../../db/partitions.js")).ensurePartitionFor(pool, "server_snapshots", "week", new Date("2026-10-03T00:00:00Z"))
await pool.query("INSERT INTO server_snapshots(server_id,polled_at,status,cpu_load,identity_name) VALUES(1,'2026-10-03T00:00:00Z','online',0,'visible-old'),(1,'2026-10-03T00:00:01Z','offline',NULL,'visible-new'),(2,'2026-10-03T00:00:02Z','online',99,'hidden-server')")
const serverHistory = await invokeMcpTool(serverHistoryPrincipal, "mm_server_snapshots_get", { serverId: 1, limit: 1 }) as { serverId: number; snapshots: { status: string; identityName: string }[]; incomplete: boolean }
assert.equal(serverHistory.serverId, 1); assert.equal(serverHistory.snapshots.length, 1); assert.equal(serverHistory.snapshots[0].status, "offline"); assert.equal(serverHistory.snapshots[0].identityName, "visible-new"); assert.equal(serverHistory.incomplete, true)
assert.ok(!JSON.stringify(serverHistory).includes("hidden-server"))
await assert.rejects(invokeMcpTool(serverHistoryPrincipal, "mm_server_snapshots_get", { serverId: 2 }))
await assert.rejects(invokeMcpTool(serverHistoryPrincipal, "mm_server_snapshots_get", { serverId: 1, limit: 201 }))
const sourceAddress = await invokeMcpTool(serverHistoryPrincipal, "mm_server_source_address_get", { serverId: 1 }) as { host: string; ipv4: string; interfaceAddressVerified: boolean }
assert.equal(sourceAddress.host, "127.0.0.1"); assert.equal(sourceAddress.ipv4, "127.0.0.1"); assert.equal(sourceAddress.interfaceAddressVerified, false)
await assert.rejects(invokeMcpTool(serverHistoryPrincipal, "mm_server_source_address_get", { serverId: 2 }))
await assert.rejects(invokeMcpTool(serverHistoryPrincipal, "mm_server_source_address_get", { serverId: 1, host: "outside.example.invalid" }))
await pool.query("DELETE FROM server_snapshots WHERE identity_name IN ('visible-old','visible-new','hidden-server')")
console.log("✓ Server history uses the shared bounded SQL service; source resolution accepts only the registered host and does not attest interface ownership")
countCatalogCalls = true
const beforeTrafficHistoryCalls = catalogCalls
await (await import("../../test/mcp-traffic-history.js")).verifyMcpTrafficHistory(actor)
await (await import("../../test/mcp-user-traffic-history.js")).verifyMcpUserTrafficHistory(actor)
await (await import("../../test/mcp-bgp-export.js")).verifyMcpBgpExport(actor)
await (await import("../../test/mcp-bgp-filter-binding.js")).verifyMcpBgpFilterBinding(actor)
await (await import("../../test/mcp-bgp-community-policy.js")).verifyMcpBgpCommunityPolicy(actor)
await (await import("../../test/mcp-bgp-prefixes.js")).verifyMcpBgpPrefixes(actor)
await (await import("../../test/mcp-filter-shared.js")).verifySharedFilterWrites()
await (await import("../../test/mcp-filter-write.js")).verifyMcpFilterWrites(actor)
await (await import("../../test/mcp-uptime-overview.js")).verifyMcpUptimeOverview(actor)
await (await import("../../test/mcp-network-hosts.js")).verifyMcpNetworkHosts(actor)
assert.equal(catalogCalls, beforeTrafficHistoryCalls)
await (await import("../../test/mcp-sidebar-counts.js")).verifyMcpSidebarCounts(actor, () => catalogCalls)
countCatalogCalls = false
const { preflightPaths } = await import("./ecmp-preflight.js")
await (await import("../../test/mcp-path-completion.js")).verifyMcpPathCompletion(actor)
await (await import("../../test/mcp-log-artifacts.js")).verifyMcpLogArtifacts(actor)
await (await import("../../test/mcp-alerts-outbox.js")).verifyMcpAlertsOutbox(actor)
preflightFixtures = Object.fromEntries(Object.values(preflightPaths("ipv4")).map(path => ["/rest" + path, []]))
preflightFixtures["/rest/ip/route"] = [1, 2].map(index => ({ ".id": `*p${index}`, "dst-address": "192.0.2.0/24", gateway: `192.0.2.${index}`, "immediate-gw": `192.0.2.${index}%same-gre`, "routing-table": "main", distance: "10", active: "true", disabled: "false" }))
preflightFixtures["/rest/ip/settings"] = { "rp-filter": "strict", "ipv4-multipath-hash-policy": "l3" }
preflightFixtures["/rest/ip/firewall/connection/tracking"] = { enabled: "auto" }
preflightFixtures["/rest/ip/firewall/filter"] = [{ ".id": "*ft", action: "fasttrack-connection", disabled: "false" }]
preflightFixtures["/rest/ip/firewall/nat"] = [{ ".id": "*nat", action: "masquerade", disabled: "false" }]
const preflightAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Read-only ECMP preflight", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1], operationIds: ["routing.ecmp.preflight.read"], allowGlobal: false } }), actor)
const preflightPrincipal = await authenticateMcpToken(preflightAccess.token), preflightWritesBefore = writes
countCatalogCalls = true; catalogCalls = 0
const preflightInput = { serverId: 1, family: "ipv4", routeIds: ["*p1", "*p2"] }
const preflight = await invokeMcpTool(preflightPrincipal, "mm_ecmp_preflight_get", preflightInput) as { configurationObserved: boolean; findings: { code: string }[]; networkValidation: string }
assert.equal(preflight.configurationObserved, true); assert.equal(preflight.networkValidation, "not-performed"); assert.equal(catalogCalls, 10)
for (const code of ["SHARED_EGRESS_INTERFACE", "STRICT_RPF_REVIEW", "FASTTRACK_REVIEW", "NAT_AFFINITY_REVIEW"]) assert.ok(preflight.findings.some(item => item.code === code), code)
await assert.rejects(invokeMcpTool(preflightPrincipal, "mm_ecmp_preflight_get", { ...preflightInput, serverId: 2 })); assert.equal(catalogCalls, 10)
preflightUnavailable = "/rest/ip/firewall/nat"
const unknownPreflight = await invokeMcpTool(preflightPrincipal, "mm_ecmp_preflight_get", preflightInput) as typeof preflight
assert.equal(unknownPreflight.configurationObserved, false); assert.ok(unknownPreflight.findings.some(item => item.code === "OBSERVATION_UNAVAILABLE")); assert.equal(writes, preflightWritesBefore)
preflightFixtures = undefined; preflightUnavailable = ""; countCatalogCalls = false
console.log("✓ ECMP preflight is read-only, scopes before polling, detects shared egress/FastTrack/NAT/strict RPF and preserves unknown resources without claiming network acceptance")
const removalAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Container removal", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1], operationIds: ["containers.remove", "containers.restart", "containers.start"], allowGlobal: false } }), actor)
const removalPrincipal = await authenticateMcpToken(removalAccess.token)
const legacyRemovalAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Legacy container delete alias", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1], operationIds: ["ros.container.delete"], allowGlobal: false } }), actor)
const legacyRemovalPrincipal = await authenticateMcpToken(legacyRemovalAccess.token)
const removalRow = { ".id": "*remove", name: "fixture-container", interface: "fixture-veth", status: "stopped", "start-on-boot": "false", cmd: "never-return-command-identity", comment: "fixture" }
const containerArgs = { serverId: 1, id: "*remove" }
const waitContainerOperation = async (id: string) => {
for (let attempt = 0; attempt < 100; attempt++) {
const state = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [id])).rows[0].state
if (!["running", "pending"].includes(state)) return state
await delay(30)
}
throw Error("Container operation timed out")
}
containerMutationFixtures = true
for (const badStatus of ["running", "unknown", "starting", "error"]) {
mutableContainers = [{ ...removalRow, status: badStatus }]
await assert.rejects(invokeMcpTool(removalPrincipal, "mm_container_remove_plan", containerArgs))
await assert.rejects(invokeMcpTool(legacyRemovalPrincipal, "mm_container_delete_plan", containerArgs))
}
assert.equal(containerDeletes, 0); assert.equal(containerCommands, 0)
mutableContainers = [{ ...removalRow }]
for (const kind of ["interface", "veth"]) {
const protection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'integration')", [protection, JSON.stringify({ kind, id: "*veth", serverId: 1, protection: "deny" })])
await assert.rejects(invokeMcpTool(removalPrincipal, "mm_container_remove_plan", containerArgs))
await assert.rejects(invokeMcpTool(legacyRemovalPrincipal, "mm_container_delete_plan", containerArgs))
await assert.rejects(invokeMcpTool(removalPrincipal, "mm_container_start_plan", containerArgs))
await assert.rejects(invokeMcpTool(removalPrincipal, "mm_container_restart_plan", containerArgs))
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [protection])
}
for (const drift of ["configuration", "state", "parent"]) {
mutableContainers = [{ ...removalRow }]; containerParent.name = "fixture-veth"
const prepared = await invokeMcpTool(removalPrincipal, "mm_container_remove_plan", containerArgs) as { planId: string }
assert.ok(!JSON.stringify(prepared).includes("never-return-command-identity"))
await approvePlan(prepared.planId, actor, true)
if (drift === "configuration") mutableContainers[0].name = "replacement-same-id"
if (drift === "state") mutableContainers[0].status = "running"
if (drift === "parent") containerParent.name = "renamed-veth"
assert.equal(await waitContainerOperation((await applyPlan(removalPrincipal, prepared.planId, randomUUID())).id), "rejected")
}
assert.equal(containerDeletes, 0); containerParent.name = "fixture-veth"
mutableContainers = [{ ...removalRow }]
const restartPlan = await invokeMcpTool(removalPrincipal, "mm_container_restart_plan", containerArgs) as { planId: string }
await approvePlan(restartPlan.planId, actor, true)
assert.equal(await waitContainerOperation((await applyPlan(removalPrincipal, restartPlan.planId, randomUUID())).id), "applied")
assert.equal(containerCommands, 1); assert.equal(mutableContainers[0].status, "running")
const runningRestart = await invokeMcpTool(removalPrincipal, "mm_container_restart_plan", containerArgs) as { planId: string }
await approvePlan(runningRestart.planId, actor, true)
assert.equal(await waitContainerOperation((await applyPlan(removalPrincipal, runningRestart.planId, randomUUID())).id), "applied")
assert.equal(containerCommands, 3); assert.equal(mutableContainers[0].status, "running")
mutableContainers = [{ ...removalRow }]
const replacedStart = await invokeMcpTool(removalPrincipal, "mm_container_start_plan", containerArgs) as { planId: string }
await approvePlan(replacedStart.planId, actor, true); replaceContainerAfterCommand = true
assert.equal(await waitContainerOperation((await applyPlan(removalPrincipal, replacedStart.planId, randomUUID())).id), "partial")
replaceContainerAfterCommand = false
mutableContainers = [{ ...removalRow }]
const commandsBeforeRemoval = containerCommands
const removePlan = await invokeMcpTool(legacyRemovalPrincipal, "mm_container_delete_plan", containerArgs) as { planId: string }
await approvePlan(removePlan.planId, actor, true)
const removed = await applyPlan(legacyRemovalPrincipal, removePlan.planId, "remove-container-once")
assert.equal(await waitContainerOperation(removed.id), "applied"); assert.equal(containerDeletes, 1); assert.equal(mutableContainers.length, 0); assert.equal(containerCommands, commandsBeforeRemoval)
await applyPlan(legacyRemovalPrincipal, removePlan.planId, "remove-container-once"); assert.equal(containerDeletes, 1)
mutableContainers = [{ ...removalRow }]; ignoreContainerDelete = true
const unconfirmedRemoval = await invokeMcpTool(removalPrincipal, "mm_container_remove_plan", containerArgs) as { planId: string }
await approvePlan(unconfirmedRemoval.planId, actor, true)
const unconfirmed = await applyPlan(removalPrincipal, unconfirmedRemoval.planId, "unconfirmed-container-removal")
assert.equal(await waitContainerOperation(unconfirmed.id), "unknown"); assert.equal(containerDeletes, 2)
await applyPlan(removalPrincipal, unconfirmedRemoval.planId, "unconfirmed-container-removal"); assert.equal(containerDeletes, 2)
ignoreContainerDelete = false; delete containerParent.disabled
mutableContainers = [{ ...removalRow }]
const omittedParentFlag = await invokeMcpTool(removalPrincipal, "mm_container_remove_plan", containerArgs) as { planId: string }
await approvePlan(omittedParentFlag.planId, actor, true)
assert.equal(await waitContainerOperation((await applyPlan(removalPrincipal, omittedParentFlag.planId, randomUUID())).id), "applied")
assert.equal(containerDeletes, 3)
containerParent.disabled = "false"; containerMutationFixtures = false
console.log("✓ Container removal shares REST stopped-only service; native alias cannot bypass state/parent protections, drift and ID reuse reject writes, command identity and failed delete verification never claim success or replay")
const tableAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "routing-dependency-test", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read", "mm:network:write"], scope: { serverIds: [1], operationIds: ["ros.routing_table.delete", "ros.ipv4_route.create"], allowGlobal: false } }), actor)
const tablePrincipal = await authenticateMcpToken(tableAccess.token)
await assert.rejects(invokeMcpTool(tablePrincipal, "mm_ipv4_route_create_plan", { serverId: 1, fields: { "dst-address": "192.0.2.0/24", "routing-table": "missing" } }), /Таблица маршрутизации/)
fixtureRouteTable = "fixture-table"
await assert.rejects(invokeMcpTool(tablePrincipal, "mm_routing_table_delete_plan", { serverId: 1, id: "*table" }), /Таблица используется/)
fixtureRouteTable = undefined
try {
for (const path of ["/rest/ip/route", "/rest/ipv6/route"]) for (const target of ["fixture-table", "*table"]) {
preflightFixtures = { "/rest/ip/route": [], "/rest/ipv6/route": [], [path]: [{ ".id": "*LOOKUP", "routing-table": "main", gateway: "fixture-gre@" + target, dynamic: "false" }] }
await assert.rejects(invokeMcpTool(tablePrincipal, "mm_routing_table_delete_plan", { serverId: 1, id: "*table" }), /Таблица используется/)
}
preflightFixtures = { "/rest/ip/route": [{ ".id": "*BADLOOKUP", "routing-table": "main", gateway: {} }], "/rest/ipv6/route": [] }
await assert.rejects(invokeMcpTool(tablePrincipal, "mm_routing_table_delete_plan", { serverId: 1, id: "*table" }), (error: { code?: string }) => error.code === "STATE_UNAVAILABLE")
} finally { preflightFixtures = undefined }
fixtureRoutingRules = [{ ".id": "*rule", table: "fixture-table", action: "lookup" }]
await assert.rejects(invokeMcpTool(tablePrincipal, "mm_routing_table_delete_plan", { serverId: 1, id: "*table" }), /Таблица используется/)
fixtureRoutingRules = []
const tablePlan = await invokeMcpTool(tablePrincipal, "mm_routing_table_delete_plan", { serverId: 1, id: "*table" }) as { planId: string }
await approvePlan(tablePlan.planId, actor, true)
fixtureRoutingRules = [{ ".id": "*late-rule", table: "fixture-table", action: "lookup" }]
const tableOperation = await applyPlan(tablePrincipal, tablePlan.planId, randomUUID())
for (let attempt = 0; attempt < 100; attempt++) {
const state = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [tableOperation.id])).rows[0].state
if (!["pending", "running"].includes(state)) { assert.equal(state, "rejected"); break }
assert.ok(attempt < 99, "Table dependency operation did not finish")
await delay(30)
}
assert.equal((await pool.query("SELECT error_code FROM mcp_operations WHERE id=$1", [tableOperation.id])).rows[0].error_code, "STATE_CONFLICT")
fixtureRoutingRules = []
console.log("✓ Routing tables: missing table rejected, route/rule references protected, post-approval dependency changes reject before write")
interfaceFixtures = true
const initialVrfs: Record<string, string>[] = [{ ".id": "*older", name: "older", interfaces: "ether9" }, { ".id": "*MAINVRF", name: "main", interfaces: "all", builtin: "true" }]
fixtureVrfs = [...initialVrfs]
const interfaceAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "overlay-dependency-test", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read", "mm:network:write"], scope: { serverIds: [1], operationIds: ["ros.vrf.create", "ros.vrf.update", "ros.vrf.delete", "ros.ipv4_address.create", "ros.gre.delete", "operations.recover"], allowGlobal: false } }), actor)
const interfacePrincipal = await authenticateMcpToken(interfaceAccess.token)
const awaitOperation = async (id: string, expected: string) => {
for (let attempt = 0; attempt < 100; attempt++) {
const state = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [id])).rows[0].state
if (!["pending", "running"].includes(state)) { assert.equal(state, expected); return }
await delay(30)
}
assert.fail("Interface fixture operation did not finish")
}
const addressArgs = { serverId: 1, fields: { address: "192.0.2.1/30", interface: "fixture-gre" } }
const addressPlan = await invokeMcpTool(interfacePrincipal, "mm_ipv4_address_create_plan", addressArgs) as { planId: string }
const addressEvidence = JSON.parse(await decryptSecret((await pool.query("SELECT evidence FROM mcp_plans WHERE id=$1", [addressPlan.planId])).rows[0].evidence.sealed))
assert.ok(addressEvidence.objects.some((row: { kind: string; id: string }) => row.kind === "gre" && row.id === "*gre"))
const greProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'integration')", [greProtection, JSON.stringify({ kind: "gre", id: "*gre", serverId: 1, protection: "deny" })])
await assert.rejects(invokeMcpTool(interfacePrincipal, "mm_ipv4_address_create_plan", addressArgs))
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [greProtection])
// This legacy fixture has symbolic IDs and no native companions. It cannot
// grant production execution. Full CRUD/order/ACK/readback is covered by the
// registered genuine VRF production component with native raw vectors.
const vrfArgs = { serverId: 1, fields: { name: "owned-vrf", interfaces: "fixture-gre" } }
const plansBeforeLegacyVrf = Number((await pool.query("SELECT count(*)::int AS n FROM mcp_plans WHERE connection_id=$1", [interfaceAccess.connection.id])).rows[0].n)
for (const action of ["create", "update", "delete"]) await assert.rejects(invokeMcpTool(interfacePrincipal, `mm_vrf_${action}_plan`, { ...vrfArgs, ...(action === "create" ? {} : { id: "*CREATEDVRF" }) }), /productionAdmission:true/)
assert.equal(Number((await pool.query("SELECT count(*)::int AS n FROM mcp_plans WHERE connection_id=$1", [interfaceAccess.connection.id])).rows[0].n), plansBeforeLegacyVrf)
assert.equal(vrfWrites, 0)
// Synthetic existing state is only a dependency fixture, not an ACK proof.
fixtureVrfs.unshift({ ".id": "*CREATEDVRF", name: "owned-vrf", interfaces: "fixture-gre", disabled: "false" })
const ownedVrfId = String(fixtureVrfs[0][".id"]), beforeReferencedVrf = vrfWrites
try {
for (const path of ["/rest/ip/route", "/rest/ipv6/route"]) for (const target of ["owned-vrf", ownedVrfId]) {
preflightFixtures = { "/rest/ip/route": [], "/rest/ipv6/route": [], [path]: [{ ".id": "*RESOLVER", "dst-address": path.includes("ipv6") ? "fd00::2/128" : "192.0.2.2/32", "routing-table": "main", gateway: "fixture-gre@" + target, dynamic: "false" }] }
await assert.rejects(invokeMcpTool(interfacePrincipal, "mm_vrf_delete_plan", { serverId: 1, id: ownedVrfId, productionAdmission: true }), /VRF используется gateway/)
await assert.rejects(invokeMcpTool(interfacePrincipal, "mm_vrf_update_plan", { serverId: 1, id: ownedVrfId, productionAdmission: true, fields: { name: "renamed-vrf" } }), /VRF используется gateway/)
await assert.rejects(invokeMcpTool(interfacePrincipal, "mm_vrf_update_plan", { serverId: 1, id: ownedVrfId, productionAdmission: true, fields: { disabled: true } }), /VRF используется gateway/)
}
preflightFixtures = { "/rest/ip/route": [{ ".id": "*SELF", "dst-address": "192.0.2.0/30", "routing-table": "owned-vrf", gateway: "fixture-gre@owned-vrf", dynamic: "true" }], "/rest/ipv6/route": [] }
// Preserve the dynamic self-route exception at its actual dependency
// layer; this incomplete symbolic fixture is not raw admission evidence.
await addRoutingDependencies(1, "vrf", "delete", fixtureVrfs[0], {}, [], [])
preflightFixtures["/rest/ip/route"] = [{ ".id": "*OWNSTATIC", "dst-address": "192.0.2.0/30", "routing-table": "owned-vrf", gateway: "fixture-gre", dynamic: "false" }]
await assert.rejects(invokeMcpTool(interfacePrincipal, "mm_vrf_delete_plan", { serverId: 1, id: ownedVrfId, productionAdmission: true }), /VRF используется настроенным маршрутом/)
const lateGateway = { ".id": "*RESOLVER", "dst-address": "192.0.2.2/32", "routing-table": "main", gateway: "fixture-gre@owned-vrf-other", dynamic: "false" }
preflightFixtures = { "/rest/ip/route": [lateGateway], "/rest/ipv6/route": [] }
await addRoutingDependencies(1, "vrf", "delete", fixtureVrfs[0], {}, [], [])
lateGateway.gateway = "fixture-gre@owned-vrf"
await assert.rejects(addRoutingDependencies(1, "vrf", "delete", fixtureVrfs[0], {}, [], []), /VRF используется gateway/)
assert.equal(vrfWrites, beforeReferencedVrf)
} finally { preflightFixtures = undefined }
await assert.rejects(invokeMcpTool(interfacePrincipal, "mm_gre_delete_plan", { serverId: 1, id: "*gre" }), /используется/)
// Late post-approval gateway drift, ignored ordering, full CRUD and explicit
// no-inverse/read-only reconciliation are tested by the genuine component.
fixtureVrfs = [...initialVrfs, { ".id": "*MANAGEDVRF", name: "managed-vrf", interfaces: "fixture-gre", comment: "MikrotikManager: integration" }]
const vrfAliasAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "VRF alias dependency", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read", "mm:network:write"], scope: { serverIds: [1], operationIds: ["routing.vrf.update"], allowGlobal: false } }), actor)
const vrfAliasPrincipal = await authenticateMcpToken(vrfAliasAccess.token)
nativeAliasFixtures = true
try {
const oldParentProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'integration')", [oldParentProtection, JSON.stringify({ kind: "gre", id: "*a1", serverId: 1, protection: "deny" })])
await assert.rejects(invokeMcpTool(vrfAliasPrincipal, "mm_vrf_plan", { serverId: 1, id: "*abc", interfaces: ["fixture-bridge"] }), { code: "PROTECTED_OBJECT" })
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [oldParentProtection])
const connectedAliasRoutes = nativeAliasCatalogs["/rest/ip/route"]
try {
nativeAliasCatalogs["/rest/ip/route"] = []
await assert.rejects(invokeMcpTool(vrfAliasPrincipal, "mm_vrf_plan", { serverId: 1, id: "*abc", interfaces: ["fixture-bridge"] }), /dependency connected route identity/)
} finally { nativeAliasCatalogs["/rest/ip/route"] = connectedAliasRoutes }
const vrfAliasPlan = await invokeMcpTool(vrfAliasPrincipal, "mm_vrf_plan", { serverId: 1, id: "*abc", interfaces: ["fixture-bridge"] }) as { planId: string; vrfTicket: { ticketId: string } }
assert.ok(vrfAliasPlan.vrfTicket.ticketId)
const vrfAliasEvidence = JSON.parse(await decryptSecret((await pool.query("SELECT evidence FROM mcp_plans WHERE id=$1", [vrfAliasPlan.planId])).rows[0].evidence.sealed))
assert.ok(vrfAliasEvidence.objects.some((row: { kind: string; id: string }) => row.kind === "gre" && row.id === "*a1"))
assert.ok(vrfAliasEvidence.objects.some((row: { kind: string; id: string }) => row.kind === "ipv4_address" && row.id === "*a3"))
assert.ok(vrfAliasEvidence.objects.some((row: { kind: string; id: string }) => row.kind === "ipv4_route" && row.id === "*a4"))
assert.equal(vrfAliasEvidence.snapshots.filter((row: { resource: string }) => row.resource === "vrf").length, 1)
assert.equal(vrfWrites, 0)
} finally { nativeAliasFixtures = false }
ospfFixtures = true
fixtureVrfs = [...initialVrfs]
const ospfAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "OSPF dependency test", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read", "mm:network:write"], scope: { serverIds: [1], operationIds: ["ros.ospf_instance.create", "ros.ospf_instance.delete", "ros.ospf_area.delete", "ros.ospf_template.create", "ros.ospf_template.update", "ros.ospf_template.delete", "operations.recover", "ros.bfd_configuration.create"], allowGlobal: false } }), actor)
const ospfPrincipal = await authenticateMcpToken(ospfAccess.token)
const { readRosSnapshot: readPassiveSnapshot } = await import("./resources.js")
const passiveFixture = fixtureOspf["interface-template"][0] as Record<string, unknown>, previousPassive = passiveFixture.passive
try {
passiveFixture.passive = ""
assert.equal((await readPassiveSnapshot(1, "ospf_template")).rows[0].passive, "true")
assert.equal(passiveFixture.passive, "", "Effective reads must not rewrite the native fixture")
delete passiveFixture.passive
assert.equal((await readPassiveSnapshot(1, "ospf_template")).rows[0].passive, "false")
} finally { if (previousPassive === undefined) delete passiveFixture.passive; else passiveFixture.passive = previousPassive }
const passiveCall = async (tool: string, args: Record<string, unknown>) => {
const plan = await invokeMcpTool(ospfPrincipal, tool, args) as { planId: string }
await approvePlan(plan.planId, actor, true)
const key = randomUUID(), operation = await applyPlan(ospfPrincipal, plan.planId, key)
return { ...plan, key, operation, state: await waitRecursiveOperation(operation.id) }
}
try {
const created = await passiveCall("mm_ospf_template_create_plan", { serverId: 1, fields: { area: "fixture-area", interfaces: "fixture-bridge", cost: 30, passive: false } })
assert.equal(created.state, "applied")
assert.equal((await readPassiveSnapshot(1, "ospf_template")).rows.find(row => row[".id"] === "*abc123")!.passive, "false")
assert.equal((await passiveCall("mm_ospf_template_update_plan", { serverId: 1, id: "*abc123", fields: { passive: true, cost: 40 } })).state, "applied")
const writesBefore = ospfPassiveWrites
const changed = await passiveCall("mm_ospf_template_update_plan", { serverId: 1, id: "*abc123", fields: { passive: false, cost: 30 } })
assert.equal(changed.state, "applied"); assert.equal(ospfPassiveWrites, writesBefore + 2)
const intended = (await pool.query("SELECT intended_state FROM mcp_operation_steps WHERE operation_id=$1 ORDER BY step_index", [changed.operation.id])).rows
assert.deepEqual(intended.map(row => row.intended_state.step.fields), [{ cost: "30" }, { passive: "false" }])
assert.equal((await passiveCall("mm_operation_recovery_plan", { operationId: changed.operation.id })).state, "applied")
let row = (await readPassiveSnapshot(1, "ospf_template")).rows.find(row => row[".id"] === "*abc123")!
assert.equal(row.passive, "true"); assert.equal(row.cost, "40")
ospfIgnoreUnset = true
const beforeIgnored = ospfPassiveWrites
const ignored = await passiveCall("mm_ospf_template_update_plan", { serverId: 1, id: "*abc123", fields: { passive: false, cost: 30 } })
assert.equal(ignored.state, "partial"); assert.equal(ospfPassiveWrites, beforeIgnored + 2)
assert.equal((await applyPlan(ospfPrincipal, ignored.planId, ignored.key)).id, ignored.operation.id); assert.equal(ospfPassiveWrites, beforeIgnored + 2)
row = (await readPassiveSnapshot(1, "ospf_template")).rows.find(row => row[".id"] === "*abc123")!
assert.equal(row.passive, "true"); assert.equal(row.cost, "30")
console.log("✓ OSPF passive switch: false create omits switch, true PATCH, explicit unset with separate write intent, combined fields/inverse, ignored unset is partial and never replayed")
} finally {
ospfIgnoreUnset = false
fixtureOspf["interface-template"] = fixtureOspf["interface-template"].filter(row => row[".id"] !== "*abc123")
}
await assert.rejects(invokeMcpTool(ospfPrincipal, "mm_ospf_instance_delete_plan", { serverId: 1, id: "*ospf" }), /используется областью/)
await assert.rejects(invokeMcpTool(ospfPrincipal, "mm_ospf_area_delete_plan", { serverId: 1, id: "*area" }), /используется шаблоном/)
await assert.rejects(invokeMcpTool(ospfPrincipal, "mm_ospf_template_create_plan", { serverId: 1, fields: { area: "missing", interfaces: "fixture-gre", cost: 10 } }), /Не подтверждена зависимость/)
await assert.rejects(invokeMcpTool(ospfPrincipal, "mm_bfd_configuration_create_plan", { serverId: 1, fields: { interfaces: "fixture-gre", addresses: "0.0.0.0/0", vrf: "main" } }), /один явный адрес/)
const vrfProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'integration')", [vrfProtection, JSON.stringify({ kind: "vrf", id: "*MAINVRF", serverId: 1, protection: "deny" })])
await assert.rejects(invokeMcpTool(ospfPrincipal, "mm_ospf_instance_create_plan", { serverId: 1, fields: { name: "blocked-ospf", "router-id": "192.0.2.1", version: "3", vrf: "main" } }))
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [vrfProtection])
bgpFixtures = true
const bgpAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "BGP dependency test", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:bgp:read", "mm:bgp:write", "mm:network:read"], scope: { serverIds: [1], operationIds: ["ros.bgp_instance.delete", "ros.bgp_instance.update", "ros.bgp_connection.create", "ros.vrf.delete"], allowGlobal: false } }), actor)
const bgpPrincipal = await authenticateMcpToken(bgpAccess.token)
await assert.rejects(invokeMcpTool(bgpPrincipal, "mm_bgp_instance_delete_plan", { serverId: 1, id: "*bgp" }), /используется подключением/)
const peerFields = { name: "new-peer", instance: "missing", "remote.address": "192.0.2.2", "local.address": "192.0.2.1", "remote.as": 64513, "local.role": "ebgp" }
await assert.rejects(invokeMcpTool(bgpPrincipal, "mm_bgp_connection_create_plan", { serverId: 1, fields: peerFields }), /Не подтверждена зависимость/)
await assert.rejects(invokeMcpTool(bgpPrincipal, "mm_bgp_connection_create_plan", { serverId: 1, fields: { ...peerFields, instance: "fixture-bgp", "local.address": "fd00::1" } }), /одного семейства/)
await assert.rejects(invokeMcpTool(bgpPrincipal, "mm_bgp_connection_create_plan", { serverId: 1, fields: { ...peerFields, instance: "fixture-bgp", "remote.address": "0.0.0.0/0" } }))
const peerProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'integration')", [peerProtection, JSON.stringify({ kind: "bgp_connection", id: "*peer", serverId: 1, protection: "deny" })])
await assert.rejects(invokeMcpTool(bgpPrincipal, "mm_bgp_instance_update_plan", { serverId: 1, id: "*bgp", fields: { as: 64514 } }))
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [peerProtection])
const bgpCatalogAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped BGP catalog", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:bgp:read"], scope: { serverIds: [1], operationIds: ["routing.bgp.catalog.read"], allowGlobal: false } }), actor)
const bgpCatalogPrincipal = await authenticateMcpToken(bgpCatalogAccess.token)
fixtureBgp.session.push({ ...fixtureBgp.session[0], ".id": "*other-session", name: "other-session" })
countCatalogCalls = true; catalogCalls = 0
const bgpCatalog = await invokeMcpTool(bgpCatalogPrincipal, "mm_bgp_catalog_get", { limit: 1 }) as { serverIds: number[]; items: { serverId: number }[]; total: number; nextOffset: number; failures: unknown[] }
assert.deepEqual(bgpCatalog.serverIds, [1]); assert.equal(bgpCatalog.total, 2); assert.equal(bgpCatalog.items.length, 1); assert.equal(bgpCatalog.nextOffset, 1); assert.equal(bgpCatalog.items[0].serverId, 1); assert.equal(bgpCatalog.failures.length, 0); assert.equal(catalogCalls, 1)
await assert.rejects(invokeMcpTool(bgpCatalogPrincipal, "mm_bgp_catalog_get", { serverId: 2 })); assert.equal(catalogCalls, 1)
healthUnavailable = true
const failedBgp = await invokeMcpTool(bgpCatalogPrincipal, "mm_bgp_catalog_get", {}) as { failures: { serverId: number }[]; incomplete: boolean }
assert.equal(failedBgp.failures.length, 1); assert.equal(failedBgp.failures[0].serverId, 1); assert.equal(failedBgp.incomplete, true)
healthUnavailable = false; countCatalogCalls = false
const bgpSessionAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "BGP session diagnostics", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:bgp:read"], scope: { serverIds: [1], operationIds: ["routing.bgp.sessions.read", "routing.bgp.sessions.raw.read"], allowGlobal: false } }), actor)
const bgpSessionPrincipal = await authenticateMcpToken(bgpSessionAccess.token)
bgpSessionOverride = fixtureBgp.session.map(row => ({ ...row, "prefix-count": "0", "tcp-md5-key": "never-return-bgp-key" }))
countCatalogCalls = true; catalogCalls = 0
try {
const parsed = await invokeMcpTool(bgpSessionPrincipal, "mm_bgp_sessions_get", { serverId: 1, limit: 1 }) as { sessions: { serverId: number; prefixesRx: number | null; prefixesTx: number | null; holdTime: number | null }[]; nextOffset: number; total: number }
assert.equal(parsed.total, 2); assert.equal(parsed.nextOffset, 1); assert.equal(parsed.sessions[0].serverId, 1)
assert.equal(parsed.sessions[0].prefixesRx, 0); assert.equal(parsed.sessions[0].prefixesTx, null); assert.equal(parsed.sessions[0].holdTime, null)
const raw = await invokeMcpTool(bgpSessionPrincipal, "mm_bgp_sessions_raw_get", { serverId: 1, limit: 1 }) as { raw: Record<string, unknown>[]; total: number; nextOffset: number }
assert.equal(raw.total, 2); assert.equal(raw.nextOffset, 1); assert.equal(raw.raw[0]["tcp-md5-key"], "[redacted]")
assert.ok(!JSON.stringify(raw).includes("never-return-bgp-key")); assert.equal(catalogCalls, 2)
await assert.rejects(invokeMcpTool(bgpSessionPrincipal, "mm_bgp_sessions_raw_get", { serverId: 2 })); assert.equal(catalogCalls, 2)
await assert.rejects(invokeMcpTool(bgpSessionPrincipal, "mm_bgp_sessions_get", { serverId: 2 })); assert.equal(catalogCalls, 2)
await pool.query("UPDATE servers SET enabled=false WHERE id=1")
await assert.rejects(invokeMcpTool(bgpSessionPrincipal, "mm_bgp_sessions_raw_get", { serverId: 1 })); assert.equal(catalogCalls, 2)
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
for (const invalid of [[null], [fixtureBgp.session[0], fixtureBgp.session[0]]]) {
bgpSessionOverride = invalid
const result = await invokeMcpTool(bgpSessionPrincipal, "mm_bgp_sessions_get", {}) as { sessions: unknown[]; failures: unknown[]; incomplete: boolean }
assert.deepEqual(result.sessions, []); assert.equal(result.failures.length, 1); assert.equal(result.incomplete, true)
}
bgpSessionOverride = [null]
await assert.rejects(invokeMcpTool(bgpSessionPrincipal, "mm_bgp_sessions_raw_get", { serverId: 1 }))
bgpSessionOverride = []
const emptySessions = await invokeMcpTool(bgpSessionPrincipal, "mm_bgp_sessions_get", {}) as { total: number; failures: unknown[]; incomplete: boolean }
assert.equal(emptySessions.total, 0); assert.deepEqual(emptySessions.failures, []); assert.equal(emptySessions.incomplete, false)
const diagnosticsAudit = (await pool.query("SELECT result FROM mcp_requests WHERE connection_id=$1", [bgpSessionAccess.connection.id])).rows
assert.ok(!JSON.stringify(diagnosticsAudit).includes("never-return-bgp-key"))
} finally {
bgpSessionOverride = undefined; countCatalogCalls = false; fixtureBgp.session.pop()
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
}
console.log("✓ Shared BGP sessions/raw: scope before polling, bounded pages, known zero versus unknown, source/duplicate failure preserved, disabled raw refused and native keys absent from result/audit")
bgpFixtures = false
const catalogAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped OSPF catalog", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1], operationIds: ["routing.ospf.catalog.read"], allowGlobal: false } }), actor)
const catalogPrincipal = await authenticateMcpToken(catalogAccess.token)
countCatalogCalls = true; catalogCalls = 0; ospfTemplateFlagReads = 0
fixtureOspf.instance.push({ ...fixtureOspf.instance[0], ".id": "*another", name: "another-instance" })
const ospfCatalog = await invokeMcpTool(catalogPrincipal, "mm_ospf_catalog_get", { limit: 1 }) as { serverIds: number[]; totalServers: number; failures: unknown[]; collections: { instances: { items: { serverId: number }[]; total: number; nextOffset: number | null } } }
assert.deepEqual(ospfCatalog.serverIds, [1]); assert.equal(ospfCatalog.totalServers, 1); assert.equal(ospfCatalog.failures.length, 0)
assert.equal(ospfCatalog.collections.instances.total, 2); assert.equal(ospfCatalog.collections.instances.items.length, 1); assert.equal(ospfCatalog.collections.instances.nextOffset, 1)
assert.equal(ospfCatalog.collections.instances.items[0].serverId, 1); assert.equal(catalogCalls, 9, "Seven collections and two complementary passive query receipts expected")
assert.equal(ospfTemplateFlagReads, 2)
await assert.rejects(invokeMcpTool(catalogPrincipal, "mm_ospf_catalog_get", { serverId: 2 }))
assert.equal(catalogCalls, 9); assert.equal(ospfTemplateFlagReads, 2)
const stateAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped OSPF/BFD state", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1], operationIds: ["routing.ospf.state.read", "routing.bfd.sessions.read"], allowGlobal: false } }), actor)
const statePrincipal = await authenticateMcpToken(stateAccess.token)
type StatePage = { totalServers: number; servers: { serverId: number; collections: Record<string, { items: Record<string, unknown>[]; total: number; nextOffset: number | null }> | null }[]; failures: unknown[]; incomplete: boolean }
const stateBefore = catalogCalls
const ospfStatePage = await invokeMcpTool(statePrincipal, "mm_ospf_state_get", { limit: 1 }) as StatePage
assert.equal(catalogCalls, stateBefore + 9); assert.equal(ospfTemplateFlagReads, 4); assert.equal(ospfStatePage.totalServers, 1); assert.deepEqual(ospfStatePage.failures, [])
assert.equal(ospfStatePage.servers[0].serverId, 1); assert.equal(ospfStatePage.servers[0].collections!.instances.total, 2)
assert.equal(ospfStatePage.servers[0].collections!.instances.nextOffset, 1); assert.equal(ospfStatePage.incomplete, true)
assert.equal(ospfStatePage.servers[0].collections!.areas.items[0].areaId, "0.0.0.0")
const bfd = await invokeMcpTool(statePrincipal, "mm_bfd_sessions_get", {}) as StatePage
assert.equal(catalogCalls, stateBefore + 10); assert.equal(bfd.servers[0].collections!.sessions.items[0].packetsRx, null)
assert.equal(bfd.servers[0].collections!.sessions.items[0].state, "Up")
await assert.rejects(invokeMcpTool(statePrincipal, "mm_bfd_sessions_get", { serverId: 2 })); assert.equal(catalogCalls, stateBefore + 10); assert.equal(ospfTemplateFlagReads, 4)
await pool.query("UPDATE servers SET enabled=false WHERE id=1")
const disabledState = await invokeMcpTool(statePrincipal, "mm_ospf_state_get", { serverId: 1 }) as StatePage
assert.equal(disabledState.totalServers, 0); assert.deepEqual(disabledState.servers, []); assert.equal(catalogCalls, stateBefore + 10); assert.equal(ospfTemplateFlagReads, 4)
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
healthUnavailable = true
const failedBfd = await invokeMcpTool(statePrincipal, "mm_bfd_sessions_get", {}) as StatePage
assert.equal(failedBfd.servers[0].collections, null); assert.equal(failedBfd.failures.length, 1); assert.equal(failedBfd.incomplete, true)
const failedState = await invokeMcpTool(statePrincipal, "mm_ospf_state_get", {}) as StatePage
assert.equal(failedState.servers[0].collections, null); assert.equal(failedState.failures.length, 1)
const failedCatalog = await invokeMcpTool(catalogPrincipal, "mm_ospf_catalog_get", { serverId: 1 }) as { failures: { serverId: number }[]; incomplete: boolean }
assert.equal(failedCatalog.failures.length, 1); assert.equal(failedCatalog.failures[0].serverId, 1); assert.equal(failedCatalog.incomplete, true)
healthUnavailable = false; countCatalogCalls = false; fixtureOspf.instance.pop()
console.log("✓ Shared OSPF/BFD state adapters: strict observed fields and areas, one scoped poll, BFD-only query, per-device paging, source failure and no poll for hidden/disabled devices")
await acceptOspfRouteProofMcp(actor)
await acceptWireguardPeerDeletion(actor)
await acceptWireguardPeerUpdate(actor)
await acceptWireguardInterfaceDeletion(actor)
await (await import("./wireguard-interface-create-acceptance.js")).acceptWireguardInterfaceCreation(actor)
await (await import("./routing-community-context-acceptance.js")).acceptRouteCommunityContextMcp(actor)
await (await import("./wireguard-peer-create-acceptance.js")).acceptWireguardPeerCreation(actor)
await (await import("../../test/mcp-flow-analytics.js")).verifyMcpFlowAnalytics(actor)
await (await import("../../test/mcp-flow-map.js")).verifyMcpFlowMap(actor)
await (await import("../../test/mcp-flow-live.js")).verifyMcpFlowLive(actor)
await (await import("../../test/mcp-flow-overlay.js")).verifyMcpFlowOverlay(actor)
await (await import("../../test/mcp-acme-test.js")).verifyMcpAcmeTest(actor)
await (await import("../../test/mcp-acme-settings.js")).verifyMcpAcmeSettings(actor)
await (await import("../../test/mcp-geoip-update.js")).verifyMcpGeoipUpdate(actor)
await (await import("../../test/mcp-telegram-settings.js")).verifyMcpTelegramSettings(actor)
await (await import("../../test/mcp-telegram-test.js")).verifyMcpTelegramTest(actor)
ospfFixtures = false
interfaceFixtures = false; fixtureVrfs = []; ignoreVrfPlacement = false
console.log("✓ GRE/VRF: parent protection, dependent delete rejection, ordered placement/read-back, inverse cleanup and reorder conflict")
const fwAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped firewall state", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1], operationIds: ["firewall.state.read"], allowGlobal: false } }), actor)
const fwPrincipal = await authenticateMcpToken(fwAccess.token)
type FirewallPage = { serverIds: number[]; collections: { rules: { items: { enabled: boolean | null; hits: number | null; log: boolean | null; matches: { srcAddress: string | null; inInterface: string; outInterface: string } }[]; total: number; nextOffset: number | null }; addressLists: { total: number } }; failures: unknown[]; incomplete: boolean; unknownRuleStates: number }
const fwRevisions = async () => Number((await pool.query("SELECT count(*)::int AS n FROM config_revisions WHERE server_id=1 AND section='firewall'")).rows[0].n)
const revisionsBeforeUnknown = await fwRevisions()
firewallStateFixtures = true; firewallStateCalls = 0
try {
const unknownFw = await invokeMcpTool(fwPrincipal, "mm_firewall_state_get", { limit: 1 }) as FirewallPage
assert.equal(firewallStateCalls, 10); assert.deepEqual(unknownFw.serverIds, [1]); assert.deepEqual(unknownFw.failures, [])
assert.equal(unknownFw.collections.rules.total, 8); assert.equal(unknownFw.collections.addressLists.total, 2)
assert.equal(unknownFw.collections.rules.items[0].hits, 0); assert.equal(unknownFw.collections.rules.items[0].enabled, null)
assert.equal(unknownFw.collections.rules.items[0].log, null); assert.equal(unknownFw.unknownRuleStates, 8)
assert.equal(unknownFw.collections.rules.items[0].matches.srcAddress, null)
assert.equal(unknownFw.collections.rules.items[0].matches.inInterface, "ether1"); assert.equal(unknownFw.collections.rules.items[0].matches.outInterface, "ether2")
assert.equal(unknownFw.collections.rules.nextOffset, 1); assert.equal(unknownFw.incomplete, true)
assert.equal(await fwRevisions(), revisionsBeforeUnknown, "Unknown flags cannot be persisted as a confirmed observed revision")
assert.ok(!JSON.stringify(unknownFw).includes("never-return-firewall-key"))
await assert.rejects(invokeMcpTool(fwPrincipal, "mm_firewall_state_get", { serverId: 2 })); assert.equal(firewallStateCalls, 10)
await pool.query("UPDATE servers SET enabled=false WHERE id=1")
assert.deepEqual((await invokeMcpTool(fwPrincipal, "mm_firewall_state_get", {}) as FirewallPage).serverIds, []); assert.equal(firewallStateCalls, 10)
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
firewallKnownFlags = true
const knownFw = await invokeMcpTool(fwPrincipal, "mm_firewall_state_get", { offset: 1, limit: 1 }) as FirewallPage
assert.equal(knownFw.collections.rules.items[0].enabled, true); assert.equal(knownFw.collections.rules.items[0].log, false); assert.equal(knownFw.unknownRuleStates, 0)
assert.equal(await fwRevisions(), revisionsBeforeUnknown + 1)
firewallFailedChunk = "/rest/ipv6/firewall/nat"
const partialFw = await invokeMcpTool(fwPrincipal, "mm_firewall_state_get", {}) as FirewallPage
assert.equal(partialFw.failures.length, 1); assert.equal(partialFw.collections.rules.total, 7); assert.equal(partialFw.incomplete, true)
assert.equal(await fwRevisions(), revisionsBeforeUnknown + 1)
firewallFailedChunk = ""; firewallDuplicate = true
const invalidFw = await invokeMcpTool(fwPrincipal, "mm_firewall_state_get", {}) as FirewallPage
assert.equal(invalidFw.failures.length, 1); assert.equal(invalidFw.collections.rules.total, 7)
assert.equal(await fwRevisions(), revisionsBeforeUnknown + 1)
} finally {
firewallStateFixtures = false; firewallKnownFlags = false; firewallFailedChunk = ""; firewallDuplicate = false
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
}
console.log("✓ Firewall shared catalog: exactly 10 scoped reads, legacy versus nullable flags/counters, preserved matches, paging, failed/duplicate slices, no secret reflection or speculative observed revision")
const fwMoveAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Firewall move plans", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1], operationIds: ["firewall.rules.move"] }, limits: { mutationsPerHour: 50 } }), actor)
const fwMovePrincipal = await authenticateMcpToken(fwMoveAccess.token), fwMoveArgs = { serverId: 1, move: { family: "ip", table: "filter", rosId: "*1", destinationRosId: "*3" } }
const waitFirewallMove = async (operationId: string) => {
for (let attempt = 0; attempt < 200; attempt++) {
const state = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [operationId])).rows[0].state as string
if (!["pending", "running"].includes(state)) return state
await delay(25)
}
throw new Error("Firewall move did not complete")
}
firewallMoveFixtures = true; firewallMoveCommands = 0
try {
const { withConfigMutationLock: fwConfigLock } = await import("../../services/config-mutation-lock.js")
const { moveFirewallRule: sharedFirewallMove } = await import("../../services/firewall-rule-move.js")
const { server: fwServer } = await (await import("./resources.js")).routerClient(1)
let releaseFwLease!: () => void, markFwLeaseReady!: () => void
const fwLeaseReady = new Promise<void>(resolve => { markFwLeaseReady = resolve })
const fwLeaseRelease = new Promise<void>(resolve => { releaseFwLease = resolve })
const fwLease = fwConfigLock([1], async () => { markFwLeaseReady(); await fwLeaseRelease })
await fwLeaseReady
try { await assert.rejects(sharedFirewallMove(fwServer, { family: "ip", table: "filter", rosId: "*1", destinationRosId: "*3" }), /изменяется другой операцией/); assert.equal(firewallMoveCommands, 0) }
finally { releaseFwLease(); await fwLease }
await assert.rejects(sharedFirewallMove({ ...fwServer, host: "changed.invalid" }, { family: "ip", table: "filter", rosId: "*1", destinationRosId: "*3" }), /Источник Firewall изменился/)
assert.equal(firewallMoveCommands, 0)
await assert.rejects(invokeMcpTool(fwMovePrincipal, "mm_firewall_rule_move_plan", { ...fwMoveArgs, serverId: 2 }))
const protectedMove = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,$3)", [protectedMove, JSON.stringify({ kind: "ip_filter", id: "*2", serverId: 1, protection: "deny" }), actor.id])
await assert.rejects(invokeMcpTool(fwMovePrincipal, "mm_firewall_rule_move_plan", fwMoveArgs))
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [protectedMove])
const staleMove = await invokeMcpTool(fwMovePrincipal, "mm_firewall_rule_move_plan", fwMoveArgs) as { planId: string }
await approvePlan(staleMove.planId, actor, true)
firewallMoveRows[0]["connection-mark"] = "externally-changed"
assert.equal(await waitFirewallMove((await applyPlan(fwMovePrincipal, staleMove.planId, randomUUID())).id), "rejected"); assert.equal(firewallMoveCommands, 0)
firewallMoveRows[0]["connection-mark"] = "keep-exactly"
const movePlan = await invokeMcpTool(fwMovePrincipal, "mm_firewall_rule_move_plan", fwMoveArgs) as { planId: string }
await approvePlan(movePlan.planId, actor, true)
const moveKey = randomUUID(), moved = await applyPlan(fwMovePrincipal, movePlan.planId, moveKey)
assert.equal(await waitFirewallMove(moved.id), "applied"); assert.equal(firewallMoveCommands, 1)
assert.deepEqual(firewallMoveRows.map(row => row[".id"]), ["*2", "*1", "*3"])
assert.ok(firewallMoveRows.every(row => row["connection-mark"] === "keep-exactly"))
assert.equal((await applyPlan(fwMovePrincipal, movePlan.planId, moveKey)).id, moved.id); assert.equal(firewallMoveCommands, 1)
const movedStep = (await pool.query("SELECT result FROM mcp_operation_steps WHERE operation_id=$1", [moved.id])).rows[0].result
assert.equal(movedStep.verified, true); assert.equal(movedStep.revisionRecorded, true)
await assert.rejects(invokeMcpTool(fwMovePrincipal, "mm_firewall_rule_move_plan", fwMoveArgs), /уже находится/)
const ignoredArgs = { ...fwMoveArgs, move: { ...fwMoveArgs.move, destinationRosId: "*2" } }
const ignoredMove = await invokeMcpTool(fwMovePrincipal, "mm_firewall_rule_move_plan", ignoredArgs) as { planId: string }
await approvePlan(ignoredMove.planId, actor, true); firewallIgnoreMove = true
assert.equal(await waitFirewallMove((await applyPlan(fwMovePrincipal, ignoredMove.planId, randomUUID())).id), "partial"); assert.equal(firewallMoveCommands, 2)
firewallIgnoreMove = false; firewallMoveRows[0].dynamic = "true"
await assert.rejects(invokeMcpTool(fwMovePrincipal, "mm_firewall_rule_move_plan", ignoredArgs), /статического/); assert.equal(firewallMoveCommands, 2)
} finally {
firewallMoveFixtures = false; firewallIgnoreMove = false
firewallMoveRows = [1, 2, 3].map(id => ({ ".id": "*" + id, chain: "fixture-move", action: "accept", disabled: "true", dynamic: "false", log: "false", comment: "rule " + id, packets: "0", "connection-mark": "keep-exactly" }))
}
console.log("✓ Firewall move uses shared REST service: exact ordered proof, opaque matcher drift, protected table rows, counter changes tolerated, native/read-back/revision, no-op/dynamic rejection, partial and no replay")
const fwWriteAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Firewall form writes", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1], operationIds: ["firewall.rules.create", "firewall.rules.update", "firewall.rules.toggle", "firewall.rules.delete"] }, limits: { mutationsPerHour: 50 } }), actor)
const fwWritePrincipal = await authenticateMcpToken(fwWriteAccess.token)
const fwFields = { chain: "fixture-form", action: "accept", disabled: true, comment: "created", tlsHost: "*.example.invalid", layer7Proto: "fixture" }
const fwInput = (operation: string, extra: Record<string, unknown>) => ({ serverId: 1, rule: { family: "ip", table: "filter", operation, ...extra } })
const fwFormPlan = async (operation: string, extra: Record<string, unknown>) => invokeMcpTool(fwWritePrincipal, "mm_firewall_rule_form_" + operation + "_plan", fwInput(operation, extra)) as Promise<{ planId: string }>
const fwFormApply = async (planId: string) => { await approvePlan(planId, actor, true); const key = randomUUID(), op = await applyPlan(fwWritePrincipal, planId, key); return { op, key, state: await waitFirewallMove(op.id) } }
const fwFormProtection = randomUUID()
firewallWriteFixtures = true; firewallWriteCommands = 0; firewallWriteRows = [{ ".id": "*A", chain: "fixture-form", action: "drop", disabled: "true", dynamic: "false", log: "false", "connection-mark": "opaque" }]
try {
await assert.rejects(invokeMcpTool(fwWritePrincipal, "mm_firewall_rule_form_create_plan", { ...fwInput("create", { fields: fwFields }), serverId: 2 })); assert.equal(firewallWriteCommands, 0)
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,$3)", [fwFormProtection, JSON.stringify({ kind: "ethernet", id: "*parent", serverId: 1, protection: "deny" }), actor.id])
await assert.rejects(fwFormPlan("create", { fields: fwFields })); assert.equal(firewallWriteCommands, 0)
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [fwFormProtection])
const { writeFirewallRule: writeSharedFirewall } = await import("../../services/firewall-rule-write.js"), { withConfigMutationLock: holdFormLock } = await import("../../services/config-mutation-lock.js")
const formSource = (await (await import("./resources.js")).routerClient(1)).server
await assert.rejects(writeSharedFirewall({ ...formSource, host: "changed.invalid" }, { operation: "create", family: "ip", table: "filter", fields: fwFields }), /Источник/); assert.equal(firewallWriteCommands, 0)
let unlockForm!: () => void, readyForm!: () => void
const lockFormReady = new Promise<void>(resolve => { readyForm = resolve }), lockFormRelease = new Promise<void>(resolve => { unlockForm = resolve })
const formLease = holdFormLock([1], async () => { readyForm(); await lockFormRelease }); await lockFormReady
try { await assert.rejects(writeSharedFirewall(formSource, { operation: "create", family: "ip", table: "filter", fields: fwFields }), /другой операцией/); assert.equal(firewallWriteCommands, 0) } finally { unlockForm(); await formLease }
const created = await fwFormApply((await fwFormPlan("create", { fields: fwFields })).planId)
assert.equal(created.state, "applied"); assert.equal(firewallWriteCommands, 1); assert.equal(firewallWriteRows.length, 2)
assert.equal(firewallWriteRows[1]["tls-host"], "*.example.invalid"); assert.equal(firewallWriteRows[1]["layer7-protocol"], "fixture")
assert.equal((await applyPlan(fwWritePrincipal, (await pool.query("SELECT plan_id FROM mcp_operations WHERE id=$1", [created.op.id])).rows[0].plan_id, created.key)).id, created.op.id); assert.equal(firewallWriteCommands, 1)
const stale = await fwFormPlan("toggle", { rosId: "*C", disabled: false }); firewallWriteRows[0]["connection-mark"] = "changed"
assert.equal((await fwFormApply(stale.planId)).state, "rejected"); assert.equal(firewallWriteCommands, 1); firewallWriteRows[0]["connection-mark"] = "opaque"
const updated = await fwFormApply((await fwFormPlan("update", { rosId: "*C", fields: { ...fwFields, comment: "edited", action: "drop" } })).planId)
assert.equal(updated.state, "applied"); assert.equal(firewallWriteRows[1].comment, "edited"); assert.equal(firewallWriteRows[0]["connection-mark"], "opaque")
const toggled = await fwFormApply((await fwFormPlan("toggle", { rosId: "*C", disabled: false })).planId)
assert.equal(toggled.state, "applied"); assert.equal(firewallWriteRows[1].disabled, "false")
const receipt = (await pool.query("SELECT result FROM mcp_operation_steps WHERE operation_id=$1", [toggled.op.id])).rows[0].result
assert.equal(receipt.verified, true); assert.equal(receipt.revisionRecorded, true)
firewallWriteIgnored = true
const ignored = await fwFormApply((await fwFormPlan("toggle", { rosId: "*C", disabled: true })).planId)
assert.equal(ignored.state, "partial"); firewallWriteIgnored = false
assert.equal((await fwFormApply((await fwFormPlan("delete", { rosId: "*C" })).planId)).state, "applied"); assert.deepEqual(firewallWriteRows.map(row => row[".id"]), ["*A"])
firewallWriteRows[0].dynamic = "true"; await assert.rejects(fwFormPlan("delete", { rosId: "*A" }), /статическое/)
firewallWriteRows[0].dynamic = "false"
const { default: FastifyForm } = await import("fastify"), { validatorCompiler: formValidator, serializerCompiler: formSerializer } = await import("@fastify/type-provider-zod")
const formHttp = FastifyForm(); formHttp.setValidatorCompiler(formValidator); formHttp.setSerializerCompiler(formSerializer)
await formHttp.register((await import("../../routes/firewall.js")).default, { prefix: "/api" })
try {
for (const rosId of ["*A,*B", "*A/../../", "not-native"]) {
const invalid = await formHttp.inject({ method: "DELETE", url: "/api/firewall/rules", payload: { serverId: "1", family: "ip", table: "filter", rosId } }); assert.equal(invalid.statusCode, 400)
}
for (const [method, payload] of [["POST", { ...fwFields }], ["PUT", { ...fwFields, rosId: "*C", comment: "REST edit" }], ["PATCH", { rosId: "*C", disabled: false }], ["DELETE", { rosId: "*C" }]] as const) {
const response = await formHttp.inject({ method, url: "/api/firewall/rules", payload: { serverId: "1", family: "ip", table: "filter", ...payload } })
assert.equal(response.statusCode, method === "POST" ? 201 : 200, response.body); assert.equal(response.json().ok, true); assert.equal(response.json().revisionRecorded, true)
}
assert.deepEqual(firewallWriteRows.map(row => row[".id"]), ["*A"])
} finally { await formHttp.close() }
} finally { firewallWriteFixtures = false; firewallWriteIgnored = false; await pool.query("DELETE FROM mcp_protections WHERE id=$1", [fwFormProtection]) }
console.log("✓ Firewall form REST service: create/edit/toggle/delete, TLS/L7, opaque matcher preservation, scope/protected parent, stale proof, read-back/revision, partial and idempotency")
const addrAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Address-list forms", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1], operationIds: ["firewall.addressLists.create", "firewall.addressLists.update", "firewall.addressLists.toggle", "firewall.addressLists.delete"] }, limits: { mutationsPerHour: 60 } }), actor)
const addrPrincipal = await authenticateMcpToken(addrAccess.token), addrFields = { list: "fixture-list", address: "192.0.2.2/32", disabled: true, comment: "fixture" }
const addrPlan = async (operation: string, extra: Record<string, unknown>) => invokeMcpTool(addrPrincipal, "mm_firewall_address_list_" + operation + "_plan", { serverId: 1, address: { family: "ip", operation, ...extra } }) as Promise<{ planId: string }>
const addrApply = async (planId: string) => { await approvePlan(planId, actor, true); const key = randomUUID(), op = await applyPlan(addrPrincipal, planId, key); return { op, key, state: await waitFirewallMove(op.id) } }
const addressProtection = randomUUID()
addressFixtures = true; addressCommands = 0; addressRows = [{ ".id": "*A", list: "unrelated", address: "198.51.100.1", disabled: "true", dynamic: "false", comment: "keep" }]
try {
await assert.rejects(invokeMcpTool(addrPrincipal, "mm_firewall_address_list_create_plan", { serverId: 2, address: { operation: "create", family: "ip", fields: addrFields } })); assert.equal(addressCommands, 0)
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,$3)", [addressProtection, JSON.stringify({ kind: "ip_filter", id: "*rule-using-list", serverId: 1, protection: "deny" }), actor.id])
await assert.rejects(addrPlan("create", { fields: addrFields })); assert.equal(addressCommands, 0); await pool.query("DELETE FROM mcp_protections WHERE id=$1", [addressProtection])
const createdPlan = await addrPlan("create", { fields: addrFields }), created = await addrApply(createdPlan.planId)
assert.equal(created.state, "applied"); assert.equal(addressRows[1].address, "192.0.2.2"); assert.equal(addressCommands, 1)
assert.equal((await applyPlan(addrPrincipal, createdPlan.planId, created.key)).id, created.op.id); assert.equal(addressCommands, 1)
const stale = await addrPlan("toggle", { rosId: "*C", disabled: false }); addressRows[0].comment = "foreign drift"
assert.equal((await addrApply(stale.planId)).state, "rejected"); assert.equal(addressCommands, 1); addressRows[0].comment = "keep"
assert.equal((await addrApply((await addrPlan("update", { rosId: "*C", fields: { ...addrFields, comment: "edited" } })).planId)).state, "applied")
assert.equal((await addrApply((await addrPlan("toggle", { rosId: "*C", disabled: false })).planId)).state, "applied")
addressIgnored = true; assert.equal((await addrApply((await addrPlan("delete", { rosId: "*C" })).planId)).state, "partial"); addressIgnored = false
assert.equal((await addrApply((await addrPlan("delete", { rosId: "*C" })).planId)).state, "applied")
assert.equal((await addrApply((await addrPlan("create", { fields: { ...addrFields, timeout: "1m" } })).planId)).state, "applied")
const timerPlan = await addrPlan("delete", { rosId: "*T" }), writesBeforeTimer = addressCommands
addressExpiry += 60000
assert.equal((await addrApply(timerPlan.planId)).state, "rejected"); assert.equal(addressCommands, writesBeforeTimer)
const natural = await addrPlan("delete", { rosId: "*T" }); await delay(1200)
assert.equal((await addrApply(natural.planId)).state, "applied"); assert.deepEqual(addressRows.map(row => row[".id"]), ["*A"])
const { default: AddrFastify } = await import("fastify"), { validatorCompiler: addrValidator, serializerCompiler: addrSerializer } = await import("@fastify/type-provider-zod")
const addrHttp = AddrFastify(); addrHttp.setValidatorCompiler(addrValidator); addrHttp.setSerializerCompiler(addrSerializer); await addrHttp.register((await import("../../routes/firewall.js")).default, { prefix: "/api" })
try { for (const [method, payload] of [["POST", { ...addrFields }], ["PUT", { ...addrFields, rosId: "*C", comment: "REST edited" }], ["PATCH", { rosId: "*C", disabled: false }], ["DELETE", { rosId: "*C" }]] as const) {
const response = await addrHttp.inject({ method, url: "/api/firewall/address-lists", payload: { serverId: "1", family: "ip", ...payload } }); assert.equal(response.statusCode, method === "POST" ? 201 : 200, response.body); assert.equal(response.json().revisionRecorded, true)
} } finally { await addrHttp.close() }
} finally { addressFixtures = false; addressIgnored = false; await pool.query("DELETE FROM mcp_protections WHERE id=$1", [addressProtection]) }
console.log("✓ Address-list shared REST/MCP forms: canonical hosts, CRUD, protected dependent rule, scope/stale/partial/idempotency, finite lifetime and countdown versus renewal drift")
const fwRevisionAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Firewall revision restore", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1], operationIds: ["firewall.revision.restore"] }, limits: { mutationsPerHour: 100 } }), actor)
const fwRevisionPrincipal = await authenticateMcpToken(fwRevisionAccess.token), fwRevisionId = randomUUID()
const { canonicalFirewallSnapshot: canonFw } = await import("../../services/entity-snapshots.js"), { fingerprintPayload: fwRevHash } = await import("../../services/config-revisions.js")
const fwSnapshot = canonFw({ rules: [1, 2].map(() => ({ family: "ip" as const, table: "filter" as const, chain: "fixture-restore", action: "accept", disabled: true, native: { "connection-mark": "opaque" } })), addressLists: [{ family: "ip6", list: "fixture-restore", address: "2001:db8::1", disabled: true }] })
await pool.query("INSERT INTO config_revisions(id,server_id,section,source,fingerprint,payload) VALUES($1,1,'firewall','apply',$2,$3::jsonb)", [fwRevisionId, fwRevHash(fwSnapshot), JSON.stringify(fwSnapshot)])
const fwRevisionArgs = { serverId: 1, revisionId: fwRevisionId }
const fwRevisionPlan = async () => invokeMcpTool(fwRevisionPrincipal, "mm_firewall_revision_restore_plan", fwRevisionArgs) as Promise<{ planId: string }>
const fwRevisionApply = async (planId: string) => { await approvePlan(planId, actor, true); const key = randomUUID(), op = await applyPlan(fwRevisionPrincipal, planId, key); return { op, key, state: await waitFirewallMove(op.id) } }
fwRestoreFixtures = true; fwRestoreCommands = 0; fwRestoreCollections = { "/rest/ip/firewall/filter": [{ ".id": "*D", chain: "dynamic", action: "accept", disabled: "false", dynamic: "true", log: "false" }, { ".id": "*OLD", chain: "fixture-restore", action: "drop", disabled: "true", dynamic: "false", log: "false", "connection-mark": "original" }] }
try {
await assert.rejects(invokeMcpTool(fwRevisionPrincipal, "mm_firewall_revision_restore_plan", { ...fwRevisionArgs, serverId: 2 })); assert.equal(fwRestoreCommands, 0)
await pool.query("UPDATE config_revisions SET fingerprint='bad' WHERE id=$1", [fwRevisionId]); await assert.rejects(fwRevisionPlan()); assert.equal(fwRestoreCommands, 0)
await pool.query("UPDATE config_revisions SET fingerprint=$2 WHERE id=$1", [fwRevisionId, fwRevHash(fwSnapshot)])
const stale = await fwRevisionPlan(); fwRestoreCollections["/rest/ip/firewall/filter"][1]["connection-mark"] = "drift"
assert.equal((await fwRevisionApply(stale.planId)).state, "rejected"); assert.equal(fwRestoreCommands, 0); fwRestoreCollections["/rest/ip/firewall/filter"][1]["connection-mark"] = "original"
const protection = randomUUID(); await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,$3)", [protection, JSON.stringify({ kind: "ethernet", id: "*protected-dependency", serverId: 1, protection: "deny" }), actor.id])
await assert.rejects(fwRevisionPlan()); await pool.query("DELETE FROM mcp_protections WHERE id=$1", [protection]); assert.equal(fwRestoreCommands, 0)
const low = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Firewall restore budget", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1], operationIds: ["firewall.revision.restore"] }, limits: { mutationsPerHour: 2 } }), actor)
await assert.rejects(invokeMcpTool(await authenticateMcpToken(low.token), "mm_firewall_revision_restore_plan", fwRevisionArgs), error => error instanceof Error && "code" in error && error.code === "BUDGET_EXCEEDED"); assert.equal(fwRestoreCommands, 0)
const exact = await fwRevisionPlan(), applied = await fwRevisionApply(exact.planId)
assert.equal(applied.state, "applied"); assert.equal(fwRestoreCommands, 4)
assert.deepEqual(fwRestoreCollections["/rest/ip/firewall/filter"].map(row => row["connection-mark"] ?? "dynamic"), ["dynamic", "opaque", "opaque"])
assert.equal((await applyPlan(fwRevisionPrincipal, exact.planId, applied.key)).id, applied.op.id); assert.equal(fwRestoreCommands, 4)
const step = (await pool.query("SELECT result FROM mcp_operation_steps WHERE operation_id=$1", [applied.op.id])).rows[0].result
assert.equal(step.revisionRecorded, true); assert.equal(step.completedCommands, 4)
const enabledRevision = randomUUID(), enabledSnapshot = { ...fwSnapshot, rules: fwSnapshot.rules.map(row => ({ ...row, disabled: false })) }
await pool.query("INSERT INTO config_revisions(id,server_id,section,source,fingerprint,payload) VALUES($1,1,'firewall','apply',$2,$3::jsonb)", [enabledRevision, fwRevHash(enabledSnapshot), JSON.stringify(enabledSnapshot)])
const activatePlan = await invokeMcpTool(fwRevisionPrincipal, "mm_firewall_revision_restore_plan", { ...fwRevisionArgs, revisionId: enabledRevision }) as { planId: string }
const activated = await fwRevisionApply(activatePlan.planId); assert.equal(activated.state, "applied")
assert.ok(fwRestoreCollections["/rest/ip/firewall/filter"].filter(row => row.dynamic === "false").every(row => row.disabled === "false"))
const activationStep = (await pool.query("SELECT result FROM mcp_operation_steps WHERE operation_id=$1", [activated.op.id])).rows[0].result
assert.equal(activationStep.commandCount, 8); assert.equal(activationStep.completedCommands, 8); assert.equal(activationStep.acknowledgedCommands, 8)
const oldIds = fwRestoreCollections["/rest/ip/firewall/filter"].map(row => row[".id"])
fwRestoreIgnored = true; const beforeIgnored = fwRestoreCommands
assert.equal((await fwRevisionApply((await fwRevisionPlan()).planId)).state, "partial"); assert.equal(fwRestoreCommands, beforeIgnored + 1); assert.deepEqual(fwRestoreCollections["/rest/ip/firewall/filter"].map(row => row[".id"]), oldIds); fwRestoreIgnored = false
const { default: RestoreFastify } = await import("fastify"), { validatorCompiler: restoreValidator, serializerCompiler: restoreSerializer } = await import("@fastify/type-provider-zod")
const restoreHttp = RestoreFastify(); restoreHttp.setValidatorCompiler(restoreValidator); restoreHttp.setSerializerCompiler(restoreSerializer); await restoreHttp.register((await import("../../routes/firewall.js")).default, { prefix: "/api" })
try { const response = await restoreHttp.inject({ method: "POST", url: "/api/firewall/revisions/" + fwRevisionId + "/restore", payload: { serverId: "1" } }); assert.equal(response.statusCode, 200, response.body); assert.equal(response.json().ok, true); assert.equal(response.json().rules.length, 3) } finally { await restoreHttp.close() }
fwRestoreLost = true; const beforeLost = fwRestoreCommands
assert.equal((await fwRevisionApply((await fwRevisionPlan()).planId)).state, "unknown"); assert.equal(fwRestoreCommands, beforeLost + 1)
assert.ok(fwRestoreCollections["/rest/ip/firewall/filter"].some(row => row.dynamic === "false" && row.disabled === "true"))
const beforeRevoke = fwRestoreCommands; fwRestoreRevoke = fwRevisionAccess.connection.id
assert.equal((await fwRevisionApply((await fwRevisionPlan()).planId)).state, "unknown"); assert.equal(fwRestoreCommands, beforeRevoke + 1)
} finally { fwRestoreFixtures = false; fwRestoreIgnored = false; fwRestoreLost = false; fwRestoreRevoke = undefined }
console.log("✓ Firewall revision shared REST/MCP restore: strict scoped revision, full matcher/order/multiplicity, disabled staging, per-command read-back, protected/budget/stale, ignored/lost stop, revocation and no replay")
const { ensurePartitionFor: flowPartition } = await import("../../db/partitions.js")
const { getTrafficFlowSettingsRow: flowSettingsRow, invalidateTrafficFlowSettingsCache: invalidateFlowSettings } = await import("../../services/traffic-flow-settings.js")
const { getServerCatalog: flowServerCatalog, invalidateFlowCatalogCache: invalidateFlowCatalog } = await import("../../services/traffic-flow-topology.js")
const { readFlowCatalogWindow: flowWindow } = await import("../../services/traffic-flow-catalog-read.js")
const { listStoredFlowRows: flowRows, ingestParsedFlowsForServerForTests: addPendingFlow, resetFlowRingsForTests: clearPendingFlows } = await import("../../services/traffic-flow-ingest.js")
const { getFlowMonthly: flowMonthly } = await import("../../services/traffic-flow-analytics.js")
const { disableRipeEnqueueForTests: disableFlowRipe, resetRipeCacheForTests: resetFlowRipe } = await import("../../services/traffic-flow-ripe.js")
await flowSettingsRow()
const savedFlow = (await pool.query("SELECT peers_json,host_private_key,top_n FROM traffic_flow_settings WHERE id=1")).rows[0]
const flowOpIds = ["traffic.flow.talkers.read", "traffic.flow.exporters.read", "traffic.flow.clients.read", "traffic.flow.monthly.read"]
const flowActor = { ...actor, id: "netflow-reports-owner", permissions: [...actor.permissions, "mm:traffic:read"] }
const makeFlowAccess = async (ids: number[]) => createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped flow reports", mode: "observer", expiresAt: new Date(Date.now()+1800000).toISOString(), permissions: ["mm:traffic:read"], scope: { serverIds: ids, operationIds: flowOpIds, allowGlobal: false }, limits: { callsPerMinute: 120 } }), flowActor)
const flowAccess = await makeFlowAccess([1]), flowPrincipal = await authenticateMcpToken(flowAccess.token)
const bucket = new Date(Date.now()-60000), oldBucket = new Date(Date.now()-7200000), futureBucket = new Date(Date.now()+3600000)
const flowMonth = new Date().toISOString().slice(0,7), flowDay = flowMonth+"-01", flowUsers = ["nf-a","nf-b","nf-peer","nf-mixed","nf-disabled","nf-split"]
for (const time of [bucket,oldBucket,futureBucket]) await flowPartition(pool,"flow_buckets","day",time)
await flowPartition(pool,"flow_daily_dims","month",new Date(flowDay+"T00:00:00Z"))
await pool.query("INSERT INTO servers(id,name,host,enabled) VALUES(42,'disabled-flow-history','192.0.2.42',false)")
clearPendingFlows()
disableFlowRipe()
try {
await pool.query("UPDATE traffic_flow_settings SET top_n=20,host_private_key='NEVER_FLOW_HOST_KEY',peers_json=$1::jsonb WHERE id=1", [JSON.stringify([{serverId:1,publicKey:"public-one"},{serverId:2,publicKey:{bad:"NEVER_FLOW_PEER_KEY"},privateKey:"NEVER_FLOW_PEER_KEY"},{serverId:42,publicKey:"public-history"}])]); invalidateFlowSettings()
for (const id of flowUsers) await pool.query("INSERT INTO app_users(id,login,name,active) VALUES($1,$1,$2,$3)",[id,id==="nf-mixed"?"NEVER_FLOW_HIDDEN_USER":id,id!=="nf-b"])
for (const [userId,serverId,interfaceName,peer] of [["nf-a",1,"visible-iface",""],["nf-b",1,"other-iface",""],["nf-peer",1,"wg-whole","peer-public"],["nf-mixed",1,"mixed-iface",""],["nf-mixed",2,"NEVER_FLOW_HIDDEN_IFACE",""],["nf-disabled",42,"offline-iface",""],["nf-split",1,"split-iface",""],["nf-split",42,"split-history"," "]] as const) await pool.query("INSERT INTO user_interface_bindings(id,user_id,server_id,interface_name,peer_public_key) VALUES($1,$2,$3,$4,$5)",[randomUUID(),userId,serverId,interfaceName,peer])
const putFlow = async (sid: number, iface: string, bytes: string | number, src: string, at=bucket) => pool.query("INSERT INTO flow_buckets(server_id,bucket_at,src,dst,bytes,packets,in_iface) VALUES($1,$2,$3,'8.8.8.8',$4,1,$5)",[sid,at.toISOString(),src,bytes,iface])
await putFlow(1,"visible-iface",1000,"198.18.242.1"); await putFlow(1,"2",500,"198.18.242.2"); await putFlow(1,"wg-whole",700,"198.18.242.3"); await putFlow(1,"mixed-iface",900,"198.18.242.4")
await putFlow(1,"visible-iface",8000,"198.18.242.5",oldBucket); await putFlow(1,"visible-iface",9000,"198.18.242.6",futureBucket)
await putFlow(2,"NEVER_FLOW_HIDDEN_IFACE","9007199254740993","198.18.242.7"); await putFlow(42,"offline-iface",300,"198.18.242.8")
await pool.query("INSERT INTO flow_daily_dims(server_id,day,dim,key,bytes,packets) VALUES(1,$1,'country','NF_US',1000,10),(1,$1,'country','NF_DE',500,5),(1,$1,'service','NF_VISIBLE_SERVICE',500,5),(1,$1,'asn','64512',200,2),(2,$1,'country','NEVER_FLOW_HIDDEN_DIM',9007199254740993,1),(42,$1,'country','NF_GB',300,3)",[flowDay])
await pool.query("INSERT INTO flow_daily_dims(server_id,day,dim,key,bytes,packets) SELECT 2,$1,'country','NF_HIDDEN_'||n,1,1 FROM generate_series(1,10001) n",[flowDay])
addPendingFlow(2,[{src:"198.18.242.9",dst:"8.8.4.4",proto:6,srcPort:1,dstPort:443,bytes:7777,packets:1,inIface:"NEVER_FLOW_PENDING_IFACE",outIface:""}])
const { applyRingSnapshot: flowRingSnapshot } = await import("../../services/traffic-flow-engine.js")
const ringQuality=(await import("../../services/traffic-flow-ingest-quality.js")).createFlowIngestQuality().snapshot()
const visibleRing={key:"1\0__all__",inBps:[...Array(59).fill(0),1000000],outBps:Array(60).fill(0)}
flowRingSnapshot([visibleRing],ringQuality)
assert.throws(()=>flowRingSnapshot([visibleRing,{key:"2\0__all__",inBps:[NaN],outBps:[]}],ringQuality),/Invalid|oversized/)
invalidateFlowCatalog(); await flowServerCatalog()
countCatalogCalls = true; catalogCalls = 0
type ExporterPage = { exporters: { id: string; retainedRowsBytes: number; wireRateMbps: null; availability: string; collectionEnabled: boolean }[]; configurationMembershipVerified: boolean; coverageVerified: boolean; serverIds: number[] }
const exporter = await invokeMcpTool(flowPrincipal,"mm_netflow_exporters_get",{minutes:5}) as ExporterPage
assert.deepEqual(exporter.exporters.map(row=>row.id),["1"]); assert.equal(exporter.exporters[0].retainedRowsBytes,3100); assert.equal(exporter.configurationMembershipVerified,true)
const ringResult = exporter.exporters[0] as unknown as {flowRing:{available:boolean;lastSlotIngressMbps:number;wireRateVerified:boolean}}
assert.equal(ringResult.flowRing.available,true); assert.equal(ringResult.flowRing.lastSlotIngressMbps,1); assert.equal(ringResult.flowRing.wireRateVerified,false)
assert.equal(exporter.exporters[0].wireRateMbps,null); assert.equal(exporter.exporters[0].availability,"unknown"); assert.equal(exporter.coverageVerified,false)
assert.ok(!JSON.stringify(exporter).includes("NEVER_FLOW")); assert.ok(!JSON.stringify(exporter).includes("outside-scope")); assert.ok(!("lastExporterIp" in exporter))
await pool.query("UPDATE traffic_flow_settings SET peers_json=jsonb_set(peers_json,'{0,publicKey}','{}'::jsonb) WHERE id=1"); invalidateFlowSettings()
const badPeer = await invokeMcpTool(flowPrincipal,"mm_netflow_exporters_get",{minutes:5}) as {configurationMembershipVerified:boolean;incomplete:boolean;failures:unknown[];exporters:{storedPeerRecord:boolean|null}[]}
assert.equal(badPeer.configurationMembershipVerified,false); assert.equal(badPeer.incomplete,true); assert.equal(badPeer.failures.length,1); assert.equal(badPeer.exporters[0].storedPeerRecord,null)
await pool.query("UPDATE traffic_flow_settings SET peers_json=jsonb_set(peers_json,'{0,publicKey}',$1::jsonb) WHERE id=1",[JSON.stringify("public-one")]); invalidateFlowSettings()
const rawWindow = await flowWindow(5,[1]); assert.equal(rawWindow.rows.length,4); assert.ok(rawWindow.rows.every(row=>row.serverId===1&&row.bucketAt<=rawWindow.until))
await assert.rejects(flowRows(rawWindow.since,1,{maxRows:1,untilIso:rawWindow.until}),/предел/)
type TalkerPage = { items: {serverId:string;src:string;bytes:number;bps:number}[]; total:number; totalConversations:number; retainedRowsBytes:number; nextOffset:number|null; incomplete:boolean; serverIds:number[] }
const talkers = await invokeMcpTool(flowPrincipal,"mm_netflow_talkers_get",{minutes:5,limit:1}) as TalkerPage
assert.equal(talkers.retainedRowsBytes,3100); assert.equal(talkers.totalConversations,4); assert.equal(talkers.total,4); assert.equal(talkers.nextOffset,1); assert.equal(talkers.incomplete,true)
assert.equal(talkers.items[0].bytes,1000); assert.deepEqual(talkers.serverIds,[1]); assert.ok(!JSON.stringify(talkers).includes("NEVER_FLOW")); assert.ok(!("lastExporterIp" in talkers))
const secondTalker = await invokeMcpTool(flowPrincipal,"mm_netflow_talkers_get",{minutes:5,offset:1,limit:1}) as TalkerPage
assert.equal(secondTalker.items[0].bytes,900)
addPendingFlow(1,[{src:"198.18.242.10",dst:"8.8.4.4",proto:6,srcPort:1,dstPort:443,bytes:222,packets:1,inIface:"visible-iface",outIface:""}])
assert.equal((await invokeMcpTool(flowPrincipal,"mm_netflow_talkers_get",{minutes:5}) as TalkerPage).retainedRowsBytes,3322)
clearPendingFlows()
await pool.query("UPDATE traffic_flow_settings SET top_n=1 WHERE id=1"); invalidateFlowSettings()
const limitedTalkers = await invokeMcpTool(flowPrincipal,"mm_netflow_talkers_get",{minutes:5}) as TalkerPage
assert.equal(limitedTalkers.total,1); assert.equal(limitedTalkers.totalConversations,4); assert.equal(limitedTalkers.retainedRowsBytes,3100)
await pool.query("UPDATE traffic_flow_settings SET top_n=20 WHERE id=1"); invalidateFlowSettings()
type ClientPage = { clients: { id: string; ingressNamedRowsBytes: number|null; peerBindingsNotAttributed: number; ifIndexRowsNotAttributed: number; availability: string; completeSourceSet: boolean; accountEnabled: boolean }[]; total: number; nextOffset: number|null }
const clients = await invokeMcpTool(flowPrincipal,"mm_netflow_clients_get",{minutes:5}) as ClientPage
assert.deepEqual(clients.clients.map(row=>row.id),["nf-a","nf-b","nf-peer"]); assert.equal(clients.total,3)
assert.equal(clients.clients[0].ingressNamedRowsBytes,1000); assert.equal(clients.clients[0].ifIndexRowsNotAttributed,1)
assert.equal(clients.clients[1].accountEnabled,false); assert.equal(clients.clients[1].availability,"unknown")
assert.equal(clients.clients[2].ingressNamedRowsBytes,null); assert.equal(clients.clients[2].peerBindingsNotAttributed,1)
const clientPage = await invokeMcpTool(flowPrincipal,"mm_netflow_clients_get",{minutes:5,offset:1,limit:1}) as ClientPage
assert.deepEqual(clientPage.clients.map(row=>row.id),["nf-b"]); assert.equal(clientPage.total,3); assert.equal(clientPage.nextOffset,2)
type MonthPage = { bytes: number; collections: { countries: {items:{id:string;bytes:number}[];total:number;nextOffset:number|null} }; serverIds:number[] }
const monthly = await invokeMcpTool(flowPrincipal,"mm_netflow_monthly_report_get",{month:flowMonth,limit:1}) as MonthPage
assert.equal(monthly.bytes,1500); assert.equal(monthly.collections.countries.total,2); assert.equal(monthly.collections.countries.nextOffset,1); assert.equal(monthly.collections.countries.items[0].id,"NF_US")
assert.equal((await invokeMcpTool(flowPrincipal,"mm_netflow_monthly_report_get",{month:flowMonth,offset:1,limit:1}) as MonthPage).collections.countries.items[0].id,"NF_DE")
await assert.rejects(flowMonthly(flowMonth,[2],{maxKeys:10000}),/предел/)
for(const tool of ["mm_netflow_talkers_get","mm_netflow_exporters_get","mm_netflow_clients_get","mm_netflow_monthly_report_get"]) await assert.rejects(invokeMcpTool(flowPrincipal,tool,{serverId:2,...(tool.includes("monthly")?{month:flowMonth}:{minutes:5})}))
const disabled = await authenticateMcpToken((await makeFlowAccess([42])).token)
const disabledExporter = await invokeMcpTool(disabled,"mm_netflow_exporters_get",{minutes:5}) as ExporterPage
assert.equal(disabledExporter.exporters[0].retainedRowsBytes,300); assert.equal(disabledExporter.exporters[0].collectionEnabled,false); assert.equal(disabledExporter.exporters[0].availability,"unknown")
assert.equal((await invokeMcpTool(disabled,"mm_netflow_monthly_report_get",{month:flowMonth}) as MonthPage).bytes,300)
const broad = await makeFlowAccess([1,42]), broadPrincipal = await authenticateMcpToken(broad.token)
const split = await invokeMcpTool(broadPrincipal,"mm_netflow_clients_get",{minutes:5,serverLimit:1}) as ClientPage
assert.equal(split.clients.find(row=>row.id==="nf-split")?.completeSourceSet,false)
const wide = await makeFlowAccess([1,2]), widePrincipal = await authenticateMcpToken(wide.token), grantId = randomUUID()
await pool.query("INSERT INTO mcp_grants(id,connection_id,payload) VALUES($1,$2,$3::jsonb)",[grantId,wide.connection.id,JSON.stringify({id:grantId,credentialId:widePrincipal.credentialId,startsAt:new Date(Date.now()-1000).toISOString(),expiresAt:new Date(Date.now()+60000).toISOString(),scope:{allowGlobal:false,serverIds:[1],operationIds:flowOpIds}})])
assert.deepEqual((await invokeMcpTool(widePrincipal,"mm_netflow_clients_get",{minutes:5}) as ClientPage).clients.map(row=>row.id),["nf-a","nf-b","nf-peer"])
assert.equal((await invokeMcpTool(widePrincipal,"mm_netflow_monthly_report_get",{month:flowMonth}) as MonthPage).bytes,1500)
assert.equal((await invokeMcpTool(widePrincipal,"mm_netflow_talkers_get",{minutes:5}) as TalkerPage).retainedRowsBytes,3100)
assert.equal((await invokeMcpTool(disabled,"mm_netflow_talkers_get",{minutes:5}) as TalkerPage).retainedRowsBytes,300)
assert.equal((await invokeMcpTool(flowPrincipal,"mm_netflow_talkers_get",{serverOffset:10000}) as TalkerPage).total,0)
const empty = await authenticateMcpToken((await makeFlowAccess([])).token)
for(const tool of ["mm_netflow_talkers_get","mm_netflow_exporters_get","mm_netflow_clients_get","mm_netflow_monthly_report_get"]) await assert.rejects(invokeMcpTool(empty,tool,tool.includes("monthly")?{month:flowMonth}:{}),/сервер/)
assert.deepEqual((await invokeMcpTool(flowPrincipal,"mm_netflow_exporters_get",{serverOffset:10000}) as ExporterPage).exporters,[])
assert.equal((await invokeMcpTool(flowPrincipal,"mm_netflow_clients_get",{serverOffset:10000}) as ClientPage).total,0)
assert.equal((await invokeMcpTool(flowPrincipal,"mm_netflow_monthly_report_get",{month:flowMonth,serverOffset:10000}) as MonthPage).bytes,0)
await pool.query("UPDATE flow_daily_dims SET bytes=9007199254740993 WHERE server_id=1 AND key='NF_US'")
await assert.rejects(invokeMcpTool(flowPrincipal,"mm_netflow_monthly_report_get",{month:flowMonth}),/счётчик/)
await pool.query("UPDATE flow_daily_dims SET bytes=1000 WHERE server_id=1 AND key='NF_US'")
assert.equal(catalogCalls,0,"Historical reports must not dispatch RouterOS requests")
const stored = (await pool.query("SELECT result FROM mcp_requests WHERE connection_id=$1",[flowAccess.connection.id])).rows
assert.ok(!JSON.stringify(stored).includes("NEVER_FLOW"))
await pool.query("DELETE FROM flow_daily_dims WHERE server_id=2 AND (key='NEVER_FLOW_HIDDEN_DIM' OR key LIKE 'NF_HIDDEN_%')")
await pool.query("UPDATE flow_buckets SET bytes=2000 WHERE server_id=2 AND src='198.18.242.7'"); clearPendingFlows()
const { default: FlowFastify } = await import("fastify"), { validatorCompiler: flowValidator, serializerCompiler: flowSerializer } = await import("@fastify/type-provider-zod")
const flowHttp = FlowFastify(); flowHttp.setValidatorCompiler(flowValidator); flowHttp.setSerializerCompiler(flowSerializer); await flowHttp.register((await import("../../routes/traffic-flow.js")).default,{prefix:"/api"})
try {
const restTalkers = await flowHttp.inject({method:"GET",url:"/api/traffic/flow?range=5m"})
assert.equal(restTalkers.statusCode,200,restTalkers.body)
const restVisible = restTalkers.json().talkers.filter((row:{serverId:string})=>row.serverId==="1")
const mcpVisible = await invokeMcpTool(flowPrincipal,"mm_netflow_talkers_get",{minutes:5}) as TalkerPage
assert.deepEqual(mcpVisible.items.map(row=>({bytes:row.bytes,bps:row.bps})),restVisible.map((row:{bytes:number;bps:number})=>({bytes:row.bytes,bps:row.bps})))
assert.ok(restVisible.every((row:{src:string})=>row.src!=="198.18.242.6"),"Future rows must not enter REST talkers")
assert.equal((await flowHttp.inject({method:"GET",url:"/api/traffic/flows?range=5m"})).statusCode,200)
for(const path of ["/api/traffic/flow/exporters?range=5m","/api/traffic/flow/clients?range=5m","/api/traffic/flow/monthly?month="+flowMonth+"&serverId=1"]) { const response = await flowHttp.inject({method:"GET",url:path}); assert.equal(response.statusCode,200,response.body); assert.equal(typeof response.json(),"object") } } finally { await flowHttp.close() }
await pool.query("INSERT INTO flow_buckets(server_id,bucket_at,src,dst,bytes,packets,in_iface) SELECT 1,now()-interval '90 seconds'+n*interval '1 millisecond','198.18.242.11','8.8.8.8',1,1,'cap' FROM generate_series(1,50001) n")
await assert.rejects(invokeMcpTool(flowPrincipal,"mm_netflow_talkers_get",{minutes:5}), (error:{code?:string})=>error.code==="STATE_UNAVAILABLE")
await pool.query("DELETE FROM flow_buckets WHERE server_id=1 AND src='198.18.242.11'")
const talkerRace = async (change:()=>Promise<unknown>, principal=flowPrincipal, signal?:AbortSignal) => {
const blocker = await pool.connect()
let pending: Promise<{error:unknown}>|undefined
try {
await blocker.query("BEGIN"); await blocker.query("LOCK TABLE flow_buckets IN ACCESS EXCLUSIVE MODE")
pending = invokeMcpTool(principal,"mm_netflow_talkers_get",{minutes:5},signal).then(()=>({error:null}),error=>({error}))
let reached = false
for(let n=0;n<100;n++) {
reached = (await pool.query("SELECT EXISTS(SELECT 1 FROM pg_stat_activity WHERE datname=current_database() AND wait_event_type='Lock' AND query ILIKE '%FROM flow_buckets fb%') AS reached")).rows[0].reached
if(reached) break
await delay(20)
}
assert.equal(reached,true,"Talker race must block the actual scoped SQL read")
await change(); await blocker.query("COMMIT")
assert.ok((await pending).error,"Late cancellation/access/source drift must withhold all talker data")
} finally { await blocker.query("ROLLBACK"); blocker.release(); await pending }
}
const originalFlowName = (await pool.query("SELECT name FROM servers WHERE id=1")).rows[0].name
await talkerRace(()=>pool.query("UPDATE servers SET name='NEVER_FLOW_CHANGED_SOURCE' WHERE id=1"))
await pool.query("UPDATE servers SET name=$1 WHERE id=1",[originalFlowName])
await talkerRace(async()=>{await pool.query("UPDATE traffic_flow_settings SET top_n=1 WHERE id=1");invalidateFlowSettings()})
await pool.query("UPDATE traffic_flow_settings SET top_n=20 WHERE id=1");invalidateFlowSettings()
await talkerRace(()=>pool.query("UPDATE mcp_grants SET payload=jsonb_set(payload,'{scope,serverIds}','[]'::jsonb) WHERE id=$1",[grantId]),widePrincipal)
const originalFlowPermissions=(await pool.query("SELECT owner_permissions FROM mcp_connections WHERE id=$1",[flowAccess.connection.id])).rows[0].owner_permissions
await talkerRace(()=>pool.query("UPDATE mcp_connections SET owner_permissions='[]'::jsonb WHERE id=$1",[flowAccess.connection.id]))
await pool.query("UPDATE mcp_connections SET owner_permissions=$2::jsonb WHERE id=$1",[flowAccess.connection.id,JSON.stringify(originalFlowPermissions)])
const talkerCancel=new AbortController()
await talkerRace(async()=>talkerCancel.abort(),flowPrincipal,talkerCancel.signal)
await talkerRace(()=>setConnectionStatus(flowAccess.connection.id,"paused",flowActor))
assert.equal(catalogCalls,0,"Talker history and races must never poll RouterOS")
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_plans WHERE connection_id=$1",[flowAccess.connection.id])).rows[0].n,0)
assert.ok(!JSON.stringify((await pool.query("SELECT result FROM mcp_requests WHERE connection_id=$1",[flowAccess.connection.id])).rows).includes("NEVER_FLOW"))
console.log("✓ NetFlow talkers: shared REST parity, scoped SQL/pending, topN/pages, 50001-row refusal, real blocked-read source/topN/grant/owner/cancel/pause races, no global fields or network")
} finally {
countCatalogCalls = false; clearPendingFlows(); resetFlowRipe()
await pool.query("DELETE FROM app_users WHERE id=ANY($1::text[])",[flowUsers])
await pool.query("DELETE FROM flow_buckets WHERE src << '198.18.242.0/24'::inet AND server_id IN(1,2,42)")
await pool.query("DELETE FROM flow_daily_dims WHERE server_id IN(1,2,42) AND (key LIKE 'NF_%' OR key='NEVER_FLOW_HIDDEN_DIM' OR key='64512')")
await pool.query("DELETE FROM servers WHERE id=42")
await pool.query("UPDATE traffic_flow_settings SET peers_json=$1::jsonb,host_private_key=$2,top_n=$3 WHERE id=1",[JSON.stringify(savedFlow.peers_json),savedFlow.host_private_key,savedFlow.top_n]); invalidateFlowSettings(); invalidateFlowCatalog()
}
console.log("✓ NetFlow reports: scoped SQL before aggregation/parsing, hidden/mixed binding exclusion and grant narrowing, bounded pages/sources, future/pending/foreign filtering, disabled history, safe counters and real REST parity; no RouterOS dispatch")
await pool.query("INSERT INTO servers(id,name,host,port,use_ssl) VALUES(45,'gre-service-fixture','127.0.0.1',$1,false)",[port])
const greServiceOperations = ["network.gre.create","network.gre.update","network.gre.delete"]
const greServiceAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({name:"GRE service plans",mode:"approval",expiresAt:new Date(Date.now()+1800000).toISOString(),permissions:["mm:network:write"],scope:{serverIds:[45],operationIds:greServiceOperations,allowGlobal:false},limits:{mutationsPerHour:200}}),actor)
const greServicePrincipal = await authenticateMcpToken(greServiceAccess.token)
const greNativeAccess=await createMcpConnection(mcpConnectionCreateSchema.parse({name:"GRE native aliases",mode:"approval",expiresAt:new Date(Date.now()+1800000).toISOString(),permissions:["mm:network:write"],scope:{serverIds:[45],operationIds:["ros.gre.update","ros.gre.delete"],allowGlobal:false},limits:{mutationsPerHour:100}}),actor)
const greNativePrincipal=await authenticateMcpToken(greNativeAccess.token)
const greNativePlan=async(operation:string,id:string,fields?:Record<string,unknown>)=>invokeMcpTool(greNativePrincipal,"mm_gre_"+operation+"_plan",{serverId:45,id,...(fields?{fields}:{})})as Promise<{planId:string}>
const greNativeApply=async(planId:string)=>{await approvePlan(planId,actor,true);const key=randomUUID(),op=await applyPlan(greNativePrincipal,planId,key);return{key,op,state:await waitFirewallMove(op.id)}}
const greServicePlan = async(operation:string,args:Record<string,unknown>)=>invokeMcpTool(greServicePrincipal,"mm_gre_tunnel_"+operation+"_plan",{serverId:45,...args}) as Promise<{planId:string}>
const greServiceApply = async(planId:string)=>{await approvePlan(planId,actor,true);const key=randomUUID(),op=await applyPlan(greServicePrincipal,planId,key);return{key,op,state:await waitFirewallMove(op.id)}}
const greServiceSecret = randomUUID(), greServiceProtection = randomUUID()
await pool.query("INSERT INTO mcp_secrets(id,purpose,server_id,ciphertext,created_by) VALUES($1,'gre-ipsec:45:gre-business',45,$2,$3)",[greServiceSecret,await encryptSecret("NEVER_GRE_SERVICE_PSK"),actor.id])
greMutationFixtures=true;greMutationCommands=0;greMutationCollections={"/interface/gre":[],"/ip/address":[],"/ipv6/address":[]};greMutationDependencies={}
const {default:GreServiceFastify}=await import("fastify"),{validatorCompiler:greServiceValidator,serializerCompiler:greServiceSerializer}=await import("@fastify/type-provider-zod")
const greServiceHttp=GreServiceFastify();greServiceHttp.setValidatorCompiler(greServiceValidator);greServiceHttp.setSerializerCompiler(greServiceSerializer);await greServiceHttp.register((await import("../../routes/gre.js")).default,{prefix:"/api"})
try {
const createFields={name:"gre-business",remoteAddress:"192.0.2.2",localInnerIp:"198.18.45.1/30",enabled:false}
await assert.rejects(invokeMcpTool(greServicePrincipal,"mm_gre_tunnel_create_plan",{serverId:1,fields:createFields}));assert.equal(greMutationCommands,0)
await assert.rejects(greServicePlan("create",{fields:{...createFields,ipsecSecret:"raw-not-permitted"}}));assert.equal(greMutationCommands,0)
await assert.rejects(greServicePlan("create",{fields:{...createFields,name:"wrong-secret-target"},ipsecSecretRef:greServiceSecret}));assert.equal(greMutationCommands,0)
const shortBudget=await createMcpConnection(mcpConnectionCreateSchema.parse({name:"GRE one-write budget",mode:"approval",expiresAt:new Date(Date.now()+1800000).toISOString(),permissions:["mm:network:write"],scope:{serverIds:[45],operationIds:greServiceOperations,allowGlobal:false},limits:{mutationsPerHour:1}}),actor)
await assert.rejects(invokeMcpTool(await authenticateMcpToken(shortBudget.token),"mm_gre_tunnel_create_plan",{serverId:45,fields:createFields}));assert.equal(greMutationCommands,0)
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,$3)",[greServiceProtection,JSON.stringify({kind:"vlan",id:"*protected",serverId:45,protection:"deny"}),actor.id])
await assert.rejects(greServicePlan("create",{fields:createFields}));assert.equal(greMutationCommands,0)
assert.equal((await greServiceHttp.inject({method:"POST",url:"/api/gre/tunnels",payload:{serverId:"45",...createFields}})).statusCode,409);assert.equal(greMutationCommands,0)
await pool.query("DELETE FROM mcp_protections WHERE id=$1",[greServiceProtection])
const createdPlan=await greServicePlan("create",{fields:createFields,ipsecSecretRef:greServiceSecret}),created=await greServiceApply(createdPlan.planId)
assert.equal(created.state,"applied");assert.equal(greMutationCommands,2);assert.equal(greMutationCollections["/interface/gre"][0].disabled,"true");assert.equal(greMutationCollections["/interface/gre"][0]["ipsec-secret"],"NEVER_GRE_SERVICE_PSK");assert.equal(greMutationCollections["/interface/gre"][0]["allow-fast-path"],"false")
await applyPlan(greServicePrincipal,createdPlan.planId,created.key);assert.equal(greMutationCommands,2)
const greId=greMutationCollections["/interface/gre"][0][".id"]
greMutationCollections["/interface/gre"][0]["dont-fragment"]="no"
const stale=await greServicePlan("update",{rosId:greId,fields:{mtu:1410}})
greMutationCollections["/interface/gre"][0]["dont-fragment"]="yes"
assert.equal((await greServiceApply(stale.planId)).state,"rejected");assert.equal(greMutationCommands,2)
greMutationCollections["/interface/gre"][0]["dont-fragment"]="no"
greMutationCollections["/ip/address"].push({".id":"*SECOND",address:"198.18.99.1/32",interface:"gre-business",disabled:"false",dynamic:"false",invalid:"false",comment:"preserve-secondary"})
const beforeNativeAddressCheck=greMutationCommands
await assert.rejects(greNativePlan("delete",greId),/адресом/)
await assert.rejects(greNativePlan("update",greId,{name:"native-bound-rename"}),/адресом/)
assert.equal(greMutationCommands,beforeNativeAddressCheck)
const changed=await greServiceApply((await greServicePlan("update",{rosId:greId,fields:{mtu:1400,localInnerIp:"fd00:45::1/64",enabled:true}})).planId)
assert.equal(changed.state,"applied");assert.equal(greMutationCollections["/interface/gre"][0].disabled,"false");assert.equal(greMutationCollections["/interface/gre"][0]["dont-fragment"],"no");assert.equal(greMutationCollections["/interface/gre"][0]["ipsec-secret"],"NEVER_GRE_SERVICE_PSK")
assert.equal(greMutationCollections["/ip/address"].length,1);assert.equal(greMutationCollections["/ip/address"][0][".id"],"*SECOND");assert.equal(greMutationCollections["/ipv6/address"][0].address,"fd00:45::1/64");assert.equal(greMutationCollections["/ipv6/address"][0].advertise,"false")
await assert.rejects(greServicePlan("update",{rosId:greId,name:"different",fields:{mtu:1420}}))
greMutationDependencies["/ip/route"]=[{".id":"*USE",gateway:"192.0.2.2%gre-business",dynamic:"false"}]
await assert.rejects(greServicePlan("delete",{rosId:greId}),/используется/);greMutationDependencies={}
await pool.query("INSERT INTO app_users(id,login,name) VALUES('gre-business-user','gre-business-user','GRE binding fixture')")
await pool.query("INSERT INTO user_interface_bindings(id,user_id,server_id,interface_name) VALUES($1,'gre-business-user',45,'gre-business')",[randomUUID()])
await assert.rejects(greServicePlan("delete",{rosId:greId}),/привязкой/);await pool.query("DELETE FROM app_users WHERE id='gre-business-user'")
const removed=await greServiceApply((await greServicePlan("delete",{rosId:greId})).planId);assert.equal(removed.state,"applied");assert.equal(greMutationCollections["/interface/gre"].length,0);assert.equal(greMutationCollections["/ip/address"].length,0);assert.equal(greMutationCollections["/ipv6/address"].length,0)
for(const [method,payload,status] of [["POST",{serverId:"45",name:"rest-gre",remoteAddress:"192.0.2.3",localInnerIp:"fd00:46::1/64",enabled:false},201],["PATCH",{serverId:"45",name:"rest-gre",mtu:1400},200],["DELETE",{serverId:"45",name:"rest-gre"},200]] as const){const response=await greServiceHttp.inject({method,url:"/api/gre/tunnels",payload});assert.equal(response.statusCode,status,response.body);assert.equal(response.json().mutation.verified,true)}
assert.equal((await greServiceApply((await greServicePlan("create",{fields:{name:"native-gre",remoteAddress:"192.0.2.4",enabled:false,comment:"native note"}})).planId)).state,"applied")
const nativeId=greMutationCollections["/interface/gre"][0][".id"],nativeBefore=greMutationCommands
greMutationCollections["/interface/gre"][0]["dont-fragment"]="no"
await pool.query("INSERT INTO app_users(id,login,name) VALUES('gre-native-user','gre-native-user','Native GRE binding fixture')")
const nativeBindingId=randomUUID()
await pool.query("INSERT INTO user_interface_bindings(id,user_id,server_id,interface_name) VALUES($1,'gre-native-user',45,'native-gre')",[nativeBindingId])
await assert.rejects(greNativePlan("delete",nativeId),/привязкой/);await assert.rejects(greNativePlan("update",nativeId,{name:"native-renamed"}),/привязкой/)
const {executeRosStep:directGreStep}=await import("./resources.js")
await assert.rejects(directGreStep({serverId:45,resource:"gre",action:"delete",id:nativeId,fields:{}}),/привязкой/)
await assert.rejects(directGreStep({serverId:45,resource:"gre",action:"update",id:nativeId,fields:{name:"bypass-rename"}}),/привязкой/)
assert.equal(greMutationCommands,nativeBefore)
const scalarNative=await greNativeApply((await greNativePlan("update",nativeId,{mtu:1395})).planId);assert.equal(scalarNative.state,"applied")
await pool.query("DELETE FROM user_interface_bindings WHERE id=$1",[nativeBindingId])
const lateNative=await greNativePlan("delete",nativeId),beforeLateNative=greMutationCommands
await pool.query("INSERT INTO user_interface_bindings(id,user_id,server_id,interface_name) VALUES($1,'gre-native-user',45,'native-gre')",[nativeBindingId])
assert.equal((await greNativeApply(lateNative.planId)).state,"rejected");assert.equal(greMutationCommands,beforeLateNative)
await pool.query("DELETE FROM app_users WHERE id='gre-native-user'")
const dynamicNative=await greNativePlan("delete",nativeId),beforeDynamicNative=greMutationCommands
// Apply reads the sealed current state and execution's initial state first;
// introduce the learned route only in the final pre-dispatch read.
greNativeLateDynamicAt=greNativeRouteReads+3
assert.equal((await greNativeApply(dynamicNative.planId)).state,"unknown");assert.equal(greMutationCommands,beforeDynamicNative)
greNativeLateDynamicAt=0;greMutationDependencies["/ip/route"]=[]
greMutationDependencies["/ip/firewall/nat"]=[{".id":"*FWUSE",chain:"srcnat",action:"masquerade","out-interface":"native-gre",packets:"1",bytes:"100"}]
await assert.rejects(greNativePlan("delete",nativeId),/используется/);await assert.rejects(greNativePlan("update",nativeId,{name:"native-renamed"}),/используется/)
await assert.rejects(directGreStep({serverId:45,resource:"gre",action:"delete",id:nativeId,fields:{}}),/используется/)
greMutationDependencies["/ip/firewall/nat"]=[]
await assert.rejects(greNativePlan("update",nativeId,{name:"ether1"}),/уже используется/)
const nativeOpaque=await greNativePlan("update",nativeId,{mtu:1390}),beforeOpaque=greMutationCommands
greMutationCollections["/interface/gre"][0]["dont-fragment"]="yes"
assert.equal((await greNativeApply(nativeOpaque.planId)).state,"rejected");assert.equal(greMutationCommands,beforeOpaque)
greMutationCollections["/interface/gre"][0]["dont-fragment"]="no"
greMutationDependencies["/ip/firewall/filter"]=[{".id":"*COUNTER",chain:"forward",action:"accept","in-interface":"ether1",packets:"1",bytes:"100"}];greNativeCounterTick=true
const renamed=await greNativeApply((await greNativePlan("update",nativeId,{name:"native-renamed",comment:""})).planId);assert.equal(renamed.state,"applied");assert.equal(greMutationCollections["/interface/gre"][0].name,"native-renamed");assert.equal(greMutationCollections["/interface/gre"][0].comment,"");assert.equal(greMutationCollections["/interface/gre"][0]["dont-fragment"],"no")
const ignoredNative=await greNativePlan("update",nativeId,{mtu:1385}),beforeIgnoredNative=greMutationCommands;greMutationIgnored=true
assert.equal((await greNativeApply(ignoredNative.planId)).state,"partial");assert.equal(greMutationCommands,beforeIgnoredNative+1);greMutationIgnored=false
const lostNative=await greNativePlan("update",nativeId,{mtu:1380}),beforeLostNative=greMutationCommands;greMutationLost=true
const nativeLostResult=await greNativeApply(lostNative.planId);assert.equal(nativeLostResult.state,"unknown");assert.equal(greMutationCommands,beforeLostNative+1)
await applyPlan(greNativePrincipal,lostNative.planId,nativeLostResult.key);assert.equal(greMutationCommands,beforeLostNative+1)
const nativeDeleteResult = await greNativeApply((await greNativePlan("delete",nativeId)).planId)
assert.equal(nativeDeleteResult.state,"applied",JSON.stringify((await pool.query("SELECT state,error_code,result FROM mcp_operations WHERE id=$1",[nativeDeleteResult.op.id])).rows[0]));assert.equal(greMutationCollections["/interface/gre"].length,0)
greNativeCounterTick=false;greMutationDependencies={}
console.log("✓ Native GRE aliases and direct execution: sealed DB/firewall/opaque proof, user/address reference rejection, rename and omitted empty-comment read-back, late binding rejection, scalar update, counter tolerance, partial/lost and no replay")
await acceptGreRevisionRestore(actor,{get:()=>greMutationCollections,set:value=>{greMutationCollections=value},writes:()=>greMutationCommands,reads:()=>greRevisionReads,ignored:value=>{greMutationIgnored=value},lost:value=>{greMutationLost=value},afterCommand:value=>{greRevisionAfterCommand=value},dependencies:value=>{greMutationDependencies=value}})
const ignored=await greServicePlan("create",{fields:{...createFields,name:"ignored-gre"}}),beforeIgnored=greMutationCommands;greMutationIgnored=true
assert.equal((await greServiceApply(ignored.planId)).state,"partial");assert.equal(greMutationCommands,beforeIgnored+1);greMutationIgnored=false
const lost=await greServicePlan("create",{fields:{...createFields,name:"lost-gre"}}),beforeLost=greMutationCommands;greMutationLost=true
const lostResult=await greServiceApply(lost.planId);assert.equal(lostResult.state,"unknown");assert.equal(greMutationCommands,beforeLost+1);assert.equal(greMutationCollections["/interface/gre"][0].disabled,"true")
await applyPlan(greServicePrincipal,lost.planId,lostResult.key);assert.equal(greMutationCommands,beforeLost+1)
greMutationCollections={"/interface/gre":[],"/ip/address":[],"/ipv6/address":[]}
const revoked=await greServicePlan("create",{fields:{...createFields,name:"revoked-gre"}}),beforeRevoke=greMutationCommands;greMutationRevoke=greServiceAccess.connection.id
assert.equal((await greServiceApply(revoked.planId)).state,"unknown");assert.equal(greMutationCommands,beforeRevoke+1)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE connection_id=$1 AND result::text LIKE '%NEVER_GRE_SERVICE_PSK%'",[greServiceAccess.connection.id])).rows[0].n,0)
} finally {greMutationFixtures=false;greMutationIgnored=false;greMutationLost=false;greMutationRevoke=undefined;greNativeCounterTick=false;greNativeLateDynamicAt=0;await greServiceHttp.close();await pool.query("DELETE FROM app_users WHERE id IN('gre-business-user','gre-native-user')");await pool.query("DELETE FROM mcp_protections WHERE id=$1",[greServiceProtection]);await pool.query("DELETE FROM mcp_secrets WHERE id=$1",[greServiceSecret]);await pool.query("DELETE FROM servers WHERE id=45")}
console.log("✓ GRE shared REST/MCP business CRUD: scoped native identity/proof, staged disabled v4/v6, preserved secondary/opaque/PSK, secret purpose, server-wide protections, parent/user dependencies, budget, stale rejection, partial/lost/no replay and revoke between commands")
const vpnAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Scoped VPN catalogs", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1], operationIds: ["network.wireguard.state.read", "network.vxlan.state.read", "network.ipsec.state.read", "network.gre.state.read"], allowGlobal: false } }), actor)
const vpnPrincipal = await authenticateMcpToken(vpnAccess.token)
vpnFixtures = true; vpnCalls.length = 0
try {
type WgPage = { interfaces: { enabled: boolean | null; status: string; address: string | null; addressStateVerified: boolean; peers: { rosId: string; transferRx: number | null; transferTx: number | null }[]; peersPage: { total: number; nextOffset: number | null } }[]; total: number; failures: unknown[]; incomplete: boolean; keyMaterialIncluded: boolean }
const wgPage = await invokeMcpTool(vpnPrincipal, "mm_wireguard_state_get", { limit: 1, peerLimit: 1 }) as WgPage
assert.equal(vpnCalls.length, 4); assert.deepEqual(wgPage.failures, []); assert.equal(wgPage.total, 2); assert.equal(wgPage.incomplete, true)
assert.equal(wgPage.interfaces[0].peersPage.total, 3); assert.equal(wgPage.interfaces[0].peersPage.nextOffset, 1)
assert.equal(wgPage.interfaces[0].peers[0].transferRx, 0); assert.equal(wgPage.interfaces[0].peers[0].transferTx, null)
assert.equal(wgPage.interfaces[0].address, "192.0.2.1/24"); assert.equal(wgPage.interfaces[0].addressStateVerified, true)
assert.equal(wgPage.keyMaterialIncluded, false); assert.ok(!JSON.stringify(wgPage).includes(vpnPrivate)); assert.ok(!JSON.stringify(wgPage).includes(vpnPsk))
const wgNext = await invokeMcpTool(vpnPrincipal, "mm_wireguard_state_get", { limit: 1, peerOffset: 1, peerLimit: 1 }) as WgPage
assert.equal(wgNext.interfaces[0].peers[0].rosId, "*P2")
const prefixes = await invokeMcpTool(vpnPrincipal, "mm_wireguard_state_get", { limit: 1, peerLimit: 1, allowedOffset: 1, allowedLimit: 1 }) as { interfaces: { peers: { allowedIps: string[]; allowedIpsPage: { total: number; nextOffset: number } }[] }[]; incomplete: boolean }
assert.deepEqual(prefixes.interfaces[0].peers[0].allowedIps, ["198.51.100.0/24"]); assert.equal(prefixes.interfaces[0].peers[0].allowedIpsPage.total, 3); assert.equal(prefixes.interfaces[0].peers[0].allowedIpsPage.nextOffset, 2); assert.equal(prefixes.incomplete, true)
const wgUnknown = await invokeMcpTool(vpnPrincipal, "mm_wireguard_state_get", { offset: 1 }) as WgPage
assert.equal(wgUnknown.interfaces[0].enabled, null); assert.equal(wgUnknown.interfaces[0].status, "unknown")
const beforeGre = vpnCalls.length
type GrePage = { tunnels: { status: string; mtu: number | null; comment: string; localAddresses: { address: string; configurationVerified: boolean }[]; addressesPage: { total: number; nextOffset: number | null } }[]; failures: unknown[]; incomplete: boolean; configurationHistoryUpdated: boolean }
const historyBeforeGre = Number((await pool.query("SELECT count(*) AS n FROM config_revisions WHERE server_id=1 AND section='gre'")).rows[0].n)
const gre = await invokeMcpTool(vpnPrincipal, "mm_gre_state_get", { limit: 1, addressLimit: 1 }) as GrePage
assert.equal(vpnCalls.length, beforeGre + 3); assert.deepEqual(gre.failures, []); assert.equal(gre.tunnels[0].status, "up"); assert.equal(gre.tunnels[0].mtu, 1400)
assert.equal(gre.tunnels[0].addressesPage.total, 3); assert.equal(gre.tunnels[0].addressesPage.nextOffset, 1); assert.equal(gre.incomplete, true)
assert.equal(gre.tunnels[0].localAddresses[0].configurationVerified, true); assert.equal(gre.configurationHistoryUpdated, false); assert.ok(!JSON.stringify(gre).includes(vpnPsk))
assert.equal(Number((await pool.query("SELECT count(*) AS n FROM config_revisions WHERE server_id=1 AND section='gre'")).rows[0].n), historyBeforeGre)
const greNext = await invokeMcpTool(vpnPrincipal, "mm_gre_state_get", { limit: 1, addressOffset: 1, addressLimit: 1 }) as GrePage
assert.equal(greNext.tunnels[0].localAddresses[0].address, "fd00::2/64")
const greUnknown = await invokeMcpTool(vpnPrincipal, "mm_gre_state_get", { offset: 1 }) as GrePage
assert.equal(greUnknown.tunnels[0].status, "unknown"); assert.equal(greUnknown.tunnels[0].mtu, null)
const beforeVxlan = vpnCalls.length
type VxPage = { tunnels: { remoteVteps: string[]; vtepsPage: { total: number; nextOffset: number | null } }[]; failures: unknown[]; incomplete: boolean }
const vx = await invokeMcpTool(vpnPrincipal, "mm_vxlan_state_get", { vtepLimit: 2 }) as VxPage
assert.equal(vpnCalls.length, beforeVxlan + 2); assert.deepEqual(vx.failures, []); assert.equal(vx.tunnels[0].vtepsPage.total, 3); assert.equal(vx.tunnels[0].vtepsPage.nextOffset, 2); assert.equal(vx.incomplete, true)
const vxNext = await invokeMcpTool(vpnPrincipal, "mm_vxlan_state_get", { vtepOffset: 2, vtepLimit: 2 }) as VxPage
assert.deepEqual(vxNext.tunnels[0].remoteVteps, ["198.51.100.3"])
const beforeIpsec = vpnCalls.length
type IpsecPage = { clients: { disabled: boolean | null; online: boolean | null }[]; servers: { clientsOnline: number | null; clientsSessionUnknown: number; peers: { disabled: boolean | null; passive: boolean | null }[]; certs: { trusted: boolean | null; keyPairAvailable: boolean | null; expiryTimestampVerified: boolean }[]; certificatesPage: { total: number; nextOffset: number | null } }[]; failures: unknown[]; incomplete: boolean }
const ike = await invokeMcpTool(vpnPrincipal, "mm_ipsec_state_get", { detailLimit: 1 }) as IpsecPage
assert.equal(vpnCalls.length, beforeIpsec + 8); assert.deepEqual(ike.failures, [])
assert.equal(ike.clients[0].disabled, null); assert.equal(ike.clients[0].online, true); assert.equal(ike.servers[0].clientsOnline, 1)
assert.equal(ike.servers[0].peers[0].disabled, null); assert.equal(ike.servers[0].peers[0].passive, true)
assert.equal(ike.servers[0].certificatesPage.total, 2); assert.equal(ike.servers[0].certificatesPage.nextOffset, 1)
assert.equal(ike.servers[0].certs[0].trusted, false); assert.equal(ike.servers[0].certs[0].keyPairAvailable, true); assert.equal(ike.servers[0].certs[0].expiryTimestampVerified, false)
assert.ok(!JSON.stringify(ike).includes(vpnPsk))
vpnAmbiguous = true
const ambiguousIke = await invokeMcpTool(vpnPrincipal, "mm_ipsec_state_get", {}) as IpsecPage
assert.ok(ambiguousIke.clients.every(row => row.online === null)); assert.equal(ambiguousIke.servers[0].clientsOnline, null); assert.equal(ambiguousIke.servers[0].clientsSessionUnknown, 2)
vpnAmbiguous = false; vpnUnknownSession = true
assert.equal((await invokeMcpTool(vpnPrincipal, "mm_ipsec_state_get", {}) as IpsecPage).clients[0].online, null); vpnUnknownSession = false
const beforeDenied = vpnCalls.length
for (const tool of ["mm_wireguard_state_get", "mm_vxlan_state_get", "mm_ipsec_state_get", "mm_gre_state_get"]) await assert.rejects(invokeMcpTool(vpnPrincipal, tool, { serverId: 2 }))
assert.equal(vpnCalls.length, beforeDenied)
await pool.query("UPDATE servers SET enabled=false WHERE id=1")
for (const tool of ["mm_wireguard_state_get", "mm_vxlan_state_get", "mm_ipsec_state_get", "mm_gre_state_get"]) assert.equal((await invokeMcpTool(vpnPrincipal, tool, {}) as { totalServers: number }).totalServers, 0)
assert.equal(vpnCalls.length, beforeDenied); await pool.query("UPDATE servers SET enabled=true WHERE id=1")
for (const [tool, path] of [["mm_gre_state_get", "/rest/interface/gre"], ["mm_gre_state_get", "/rest/ip/address"], ["mm_gre_state_get", "/rest/ipv6/address"], ["mm_wireguard_state_get", "/rest/interface/wireguard"], ["mm_vxlan_state_get", "/rest/interface/vxlan/vteps"], ["mm_ipsec_state_get", "/rest/ip/ipsec/identity"]]) {
vpnFailurePath = path
const failed = await invokeMcpTool(vpnPrincipal, tool, {}) as { failures: unknown[]; incomplete: boolean }
assert.equal(failed.failures.length, 1); assert.equal(failed.incomplete, true)
}
vpnFailurePath = ""; vpnDuplicate = true
assert.equal((await invokeMcpTool(vpnPrincipal, "mm_wireguard_state_get", {}) as WgPage).failures.length, 1)
assert.equal((await invokeMcpTool(vpnPrincipal, "mm_gre_state_get", {}) as GrePage).failures.length, 1)
const results = (await pool.query("SELECT result FROM mcp_requests WHERE connection_id=$1", [vpnAccess.connection.id])).rows
assert.ok(!JSON.stringify(results).includes(vpnPsk)); assert.ok(!JSON.stringify(results).includes(vpnPrivate))
} finally {
vpnFixtures = false; vpnFailurePath = ""; vpnAmbiguous = false; vpnUnknownSession = false; vpnDuplicate = false
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
}
console.log("✓ VPN catalogs share REST polling/models: 3 GRE/4 WG/2 VXLAN/8 IPsec scoped GETs, nested paging, unknown flags/counters/sessions, keys and reflected credentials masked, failures/duplicates and disabled/hidden sources preserved")
await (await import("../../test/mcp-routing-sources.js")).verifyRoutingSources(actor)
let analysisPeerReads = 0
let analysisPeerInstances = [{ ".id": "*peer-ospf", name: "peer-ospf", "router-id": "192.0.2.2", disabled: "false", version: "2", vrf: "main" }]
let analysisPeerNeighbors: Record<string, string>[] = [{ ".id": "*pn", instance: "peer-ospf", interface: "peer", "router-id": "192.0.2.1", address: "192.0.2.1", state: "Full" }]
let analysisPeerAddresses = [{ ".id": "*pa", interface: "peer", address: "192.0.2.2/30", disabled: "false", invalid: "false" }]
const analysisPeer = createServer((req, res) => { analysisPeerReads++; if (ospfAnalysisFixtures) ospfAnalysisNativeRequests++; res.setHeader("content-type", "application/json"); res.end(JSON.stringify(req.url === "/rest/routing/ospf/neighbor" ? analysisPeerNeighbors : req.url === "/rest/ip/address" ? analysisPeerAddresses : analysisPeerInstances)) })
await new Promise<void>(resolve => analysisPeer.listen(0, "127.0.0.1", resolve))
const analysisAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "Observer OSPF analysis", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1, 2], operationIds: ["routing.ospf.analyze"], allowGlobal: false } }), actor)
const analysisPrincipal = await authenticateMcpToken(analysisAccess.token), observationId = randomUUID(), badObservationId = randomUUID()
ospfAnalysisFixtures = true; ospfAnalysisDispatches = 0
await pool.query("UPDATE servers SET port=$1 WHERE id=2", [(analysisPeer.address() as { port: number }).port])
await pool.query("INSERT INTO mcp_routing_observations(id,src_server_id,dst_server_id,src_interface,dst_interface,family,routing_table,ping_ms,loss_pct,dl_mbps,ul_mbps,ping_at,bandwidth_at,context_verified,source) VALUES($1,1,2,'fixture-gre','peer','ipv4','main',12,0,100,200,now(),now(),true,'fixture')", [observationId])
await attestRoutingFixture(observationId)
try {
type OspfAnalysis = { ranking: { currentCost: number; proposedCost: number; observationId: string; peerId: number }[]; serverIds: number[]; changes: number; proposalOnly: boolean; executionAvailable: boolean }
const applicationPreviewPolicy={name:"OSPF application preview",mode:"observer",expiresAt:new Date(Date.now()+1800000).toISOString(),permissions:["mm:network:read"],scope:{serverIds:[1,2],operationIds:["routing.ospf.application.preview"],allowGlobal:false}}
const applicationPreviewAccess=await createMcpConnection(mcpConnectionCreateSchema.parse(applicationPreviewPolicy),actor),applicationPreviewPrincipal=await authenticateMcpToken(applicationPreviewAccess.token)
const isolatedPreviewAccess=await createMcpConnection(mcpConnectionCreateSchema.parse({...applicationPreviewPolicy,name:"OSPF source-only preview",scope:{...applicationPreviewPolicy.scope,serverIds:[1]}}),actor),isolatedPreviewPrincipal=await authenticateMcpToken(isolatedPreviewAccess.token)
const {createOspfRoutes}=await import("../../routes/ospf.js"),{ensurePartitionFor:ensurePreviewPartition}=await import("../../db/partitions.js")
const previewHttp=FilterFastify();previewHttp.setValidatorCompiler(filterValidator);previewHttp.setSerializerCompiler(filterSerializer);await previewHttp.register(createOspfRoutes(),{prefix:"/api"})
const previewProbeId=randomUUID(),previewTrafficTimes=[0,1,2].map(delta=>new Date(Date.now()-10000+delta).toISOString()),templatesBeforePreview=structuredClone(fixtureOspf["interface-template"])
type ApplicationPreview={interfacesTotal:number;proposalOnly:boolean;executionAvailable:boolean;metricContextVerified:boolean;interfaces:{items:{currentCost:number;modeled:{pingMs:number;dlMbps:number;ulMbps:number;score:number;optimalCost:number};observed:{ping:{value:number|null;sourceId:string|null};dl:{value:number|null};ul:{value:number|null}}}[];total:number;nextOffset:number|null};changes:{total:number};allowedMetricServerIds:number[]}
try{
await pool.query("INSERT INTO uptime_speed_probes(id,src_server_id,dst_server_id,src_interface,last_ping_rtt_ms,last_ping_at,last_tx_avg_mbps,last_rx_avg_mbps,last_error) VALUES($1,1,2,'fixture-gre',0,now(),0,0,'NEVER_OSPF_PREVIEW_ERROR')",[previewProbeId])
const beforePeer=analysisPeerReads,plansBeforePreview=(await pool.query("SELECT count(*)::int AS n FROM mcp_plans")).rows[0].n
const isolated=await invokeMcpTool(isolatedPreviewPrincipal,"mm_ospf_application_preview",{serverId:1}) as ApplicationPreview
assert.equal(analysisPeerReads,beforePeer);assert.equal(isolated.interfaces.items[0].observed.ping.value,null);assert.equal(isolated.interfaces.items[0].observed.ping.sourceId,null)
assert.deepEqual(isolated.allowedMetricServerIds,[1]);assert.equal(JSON.stringify(isolated).includes(previewProbeId),false)
await assert.rejects(invokeMcpTool(isolatedPreviewPrincipal,"mm_ospf_application_preview",{serverId:1,peerServerIds:[2]}));assert.equal(analysisPeerReads,beforePeer)
const application=await invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1,limit:1}) as ApplicationPreview
assert.ok(analysisPeerReads>beforePeer);assert.equal(application.interfaces.items[0].observed.ping.value,0);assert.equal(application.interfaces.items[0].observed.dl.value,0);assert.equal(application.interfaces.items[0].observed.ul.value,0)
assert.equal(application.interfaces.items[0].modeled.pingMs,1);assert.equal(application.interfaces.items[0].modeled.dlMbps,1);assert.equal(application.metricContextVerified,false);assert.equal(application.proposalOnly,true);assert.equal(application.executionAvailable,false)
const restPreview=await previewHttp.inject({method:"POST",url:"/api/servers/1/ospf/optimize/preview",payload:{pingWeight:60}})
assert.equal(restPreview.statusCode,200,restPreview.body)
assert.deepEqual(application.interfaces.items[0].modeled,{pingMs:restPreview.json().interfaces[0].pingMs,dlMbps:restPreview.json().interfaces[0].dlMbps,ulMbps:restPreview.json().interfaces[0].ulMbps,score:restPreview.json().interfaces[0].score,optimalCost:restPreview.json().interfaces[0].optimalCost})
const {readLegacyOspfSealedSources}=await import("./ospf-legacy-source.js")
const {MikrotikClient}=await import("../../services/mikrotik.js")
const legacyServer=(await (await import("./resources.js")).routerClient(1)).server
let legacySourceGates=0
const legacyOptions={serverIds:[1,2],authorize:async()=>{legacySourceGates++},signal:AbortSignal.timeout(30000)}
const legacySealed=await readLegacyOspfSealedSources(legacyServer,60,legacyOptions)
assert.deepEqual(legacySealed.plan.interfaces,restPreview.json().interfaces)
assert.ok(legacySourceGates>10);assert.ok(legacySealed.sourceCount>5)
assert.equal((await readLegacyOspfSealedSources(legacyServer,60,legacyOptions)).proof,legacySealed.proof)
const legacyFirst=legacySealed.plan.interfaces.find(row=>row.currentCost!==row.optimalCost)!
assert.ok(legacyFirst)
const legacyNativeCost=fixtureOspf["interface-template"].find(row=>row[".id"]===legacyFirst.id)!
const legacyOriginalCost=legacyNativeCost.cost
try{
legacyNativeCost.cost=String(legacyFirst.optimalCost)
const prefix=await readLegacyOspfSealedSources(legacyServer,60,legacyOptions,{baseline:legacySealed.plan,completedCount:1})
assert.equal(prefix.proof,legacySealed.proof)
await assert.rejects(readLegacyOspfSealedSources(legacyServer,60,legacyOptions,{baseline:legacySealed.plan,completedCount:0}),/не подтверждены/)
}finally{legacyNativeCost.cost=legacyOriginalCost}
const legacyProbeMetric=(await pool.query("SELECT last_ping_rtt_ms FROM uptime_speed_probes WHERE id=$1",[previewProbeId])).rows[0].last_ping_rtt_ms
try{
await pool.query("UPDATE uptime_speed_probes SET last_ping_rtt_ms=last_ping_rtt_ms+1 WHERE id=$1",[previewProbeId])
assert.notEqual((await readLegacyOspfSealedSources(legacyServer,60,legacyOptions)).proof,legacySealed.proof)
}finally{await pool.query("UPDATE uptime_speed_probes SET last_ping_rtt_ms=$2 WHERE id=$1",[previewProbeId,legacyProbeMetric])}
const legacyIntentBefore=(await pool.query("SELECT count(*)::int AS n FROM mcp_audit WHERE action='configuration.intent'")).rows[0].n
const legacyDispatchBefore=ospfAnalysisDispatches
let legacyDispatchGate=0
try{
await assert.rejects(MikrotikClient.fromServer(legacyServer).setOspfInterfaceTemplateCost(legacyFirst.id,legacyFirst.optimalCost,legacyFirst.currentCost,undefined,async()=>{
legacyDispatchGate++
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_audit WHERE action='configuration.intent'")).rows[0].n,legacyIntentBefore+1)
await pool.query("UPDATE uptime_speed_probes SET last_ping_rtt_ms=last_ping_rtt_ms+1 WHERE id=$1",[previewProbeId])
if((await readLegacyOspfSealedSources(legacyServer,60,legacyOptions)).proof!==legacySealed.proof)throw Error("NEVER_PUBLISH_LEGACY_SOURCE_DRIFT")
}),error=>error instanceof Error&&"writeAttempted"in error&&error.writeAttempted===false&&!error.message.includes("NEVER_PUBLISH"))
assert.equal(legacyDispatchGate,1);assert.equal(ospfAnalysisDispatches,legacyDispatchBefore)
assert.equal(legacyNativeCost.cost,legacyOriginalCost)
}finally{await pool.query("UPDATE uptime_speed_probes SET last_ping_rtt_ms=$2 WHERE id=$1",[previewProbeId,legacyProbeMetric])}
console.log("✓ Legacy OSPF native dispatch gate: SQL drift after durable configuration.intent rejected before PATCH, attempted=false and no provider/source error leakage")
const {executeSealedLegacyOspf,reconcileSealedLegacyOspf,LegacyOspfExecutionError}=await import("./ospf-legacy-execution.js")
const legacyExecutionBaseline=structuredClone(fixtureOspf["interface-template"]),legacyExecutionDispatches=ospfAnalysisDispatches
try{
fixtureOspf["interface-template"].push({...legacyExecutionBaseline[0],".id":"*secondary",interfaces:"fixture-other",cost:"40"})
const executionBaseline=structuredClone(fixtureOspf["interface-template"])
const readExecution=()=>readLegacyOspfSealedSources(legacyServer,60,{...legacyOptions,signal:AbortSignal.timeout(45000)})
const executionOptions={...legacyOptions,signal:AbortSignal.timeout(45000)}
const sealed=await readExecution()
assert.equal(sealed.plan.interfaces.length,2)
assert.deepEqual(await reconcileSealedLegacyOspf(legacyServer,sealed,executionOptions),{matchesOriginalState:true,matchesDesiredState:false,confirmedPrefix:0})
const successBefore=ospfAnalysisDispatches
const receipt=await executeSealedLegacyOspf(legacyServer,sealed,executionOptions)
assert.equal(receipt.optimizedCount,2);assert.equal(ospfAnalysisDispatches,successBefore+2)
assert.deepEqual(await reconcileSealedLegacyOspf(legacyServer,sealed,executionOptions),{matchesOriginalState:false,matchesDesiredState:true,confirmedPrefix:2})
assert.equal(ospfAnalysisDispatches,successBefore+2)
fixtureOspf["interface-template"]=structuredClone(executionBaseline)
await pool.query("UPDATE uptime_speed_probes SET last_ping_rtt_ms=last_ping_rtt_ms+1 WHERE id=$1",[previewProbeId])
const staleBefore=ospfAnalysisDispatches
await assert.rejects(executeSealedLegacyOspf(legacyServer,sealed,executionOptions),error=>error instanceof LegacyOspfExecutionError&&error.state==="rejected")
assert.equal(ospfAnalysisDispatches,staleBefore)
await pool.query("UPDATE uptime_speed_probes SET last_ping_rtt_ms=$2 WHERE id=$1",[previewProbeId,legacyProbeMetric])
for(const fault of ["ignored","lost-response","changed-field"] as const){
fixtureOspf["interface-template"]=structuredClone(executionBaseline)
ospfCostWriteFault=fault
const before=ospfAnalysisDispatches
await assert.rejects(executeSealedLegacyOspf(legacyServer,sealed,{...executionOptions,signal:AbortSignal.timeout(45000)}),error=>error instanceof LegacyOspfExecutionError&&error.state==="unknown"&&!error.message.includes("NEVER_PUBLISH"))
assert.equal(ospfAnalysisDispatches,before+1,"An uncertain first write must stop the second and must not be retried")
ospfCostWriteFault="none"
const reconciled=await reconcileSealedLegacyOspf(legacyServer,sealed,{...executionOptions,signal:AbortSignal.timeout(45000)})
assert.equal(reconciled.matchesDesiredState,false)
if(fault==="ignored")assert.equal(reconciled.matchesOriginalState,true)
if(fault==="lost-response")assert.equal(reconciled.confirmedPrefix,1)
if(fault==="changed-field")assert.equal(reconciled.confirmedPrefix,null)
assert.equal(ospfAnalysisDispatches,before+1,"Reconciliation must not dispatch any mutation")
}
}finally{
fixtureOspf["interface-template"]=legacyExecutionBaseline;ospfAnalysisDispatches=legacyExecutionDispatches;ospfCostWriteFault="none"
await pool.query("UPDATE uptime_speed_probes SET last_ping_rtt_ms=$2 WHERE id=$1",[previewProbeId,legacyProbeMetric])
}
console.log("✓ Legacy OSPF sealed executor: two sequential cost PATCHes, full source checks before dispatch/after read-back, stale zero-write refusal, ignored/lost/collateral stop after one command, private errors and readonly prefix reconciliation; local SQL/HTTP only")
const legacyBeforeDenied=analysisPeerReads
await assert.rejects(readLegacyOspfSealedSources(legacyServer,60,{...legacyOptions,authorize:async()=>{throw Error("legacy access revoked")}}),/legacy access revoked/)
await assert.rejects(readLegacyOspfSealedSources(legacyServer,60,{...legacyOptions,signal:AbortSignal.abort()}))
await assert.rejects(readLegacyOspfSealedSources(legacyServer,60,{...legacyOptions,deadlineAt:Date.now()-1}))
assert.equal(analysisPeerReads,legacyBeforeDenied)
countCatalogCalls=true
const legacyBeforeStaleSource=catalogCalls
try{
await assert.rejects(readLegacyOspfSealedSources({...legacyServer,password:"stale-client-credential"},60,{...legacyOptions,signal:AbortSignal.timeout(45000)}),/не подтверждены/)
assert.equal(catalogCalls,legacyBeforeStaleSource)
}finally{countCatalogCalls=false}
console.log("✓ Legacy OSPF sealed sources: actual SQL/native REST rank parity, stable private proof, confirmed cost prefix, wrong prefix refusal and pre-source access denial; no native mutation")
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_plans")).rows[0].n,plansBeforePreview)
for(const time of previewTrafficTimes)await ensurePreviewPartition(pool,"traffic_samples","week",new Date(time))
await pool.query("UPDATE uptime_speed_probes SET last_tx_avg_mbps=NULL,last_rx_avg_mbps=NULL WHERE id=$1",[previewProbeId])
await pool.query("INSERT INTO traffic_samples(server_id,interface_name,peer_public_key,sampled_at,rx_bps,tx_bps,flags) VALUES(1,'fixture-gre','',$1,0,0,61),(1,'fixture-gre','NEVER_OSPF_PEER_KEY',$2,99000000,99000000,61)",[previewTrafficTimes[0],previewTrafficTimes[1]])
const measuredZero=await invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1}) as ApplicationPreview
assert.equal(measuredZero.interfaces.items[0].observed.dl.value,0);assert.equal(measuredZero.interfaces.items[0].observed.ul.value,0)
await pool.query("INSERT INTO traffic_samples(server_id,interface_name,sampled_at,rx_bps,tx_bps,flags) VALUES(1,'fixture-gre',$1,0,0,36)",[previewTrafficTimes[2]])
const unknownRate=await invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1}) as ApplicationPreview
assert.equal(unknownRate.interfaces.items[0].observed.dl.value,null);assert.equal(unknownRate.interfaces.items[0].observed.ul.value,null);assert.equal(unknownRate.interfaces.items[0].modeled.dlMbps,10)
await pool.query("UPDATE traffic_samples SET flags=0,rx_bps=40000000 WHERE server_id=1 AND interface_name='fixture-gre' AND sampled_at=$1",[previewTrafficTimes[2]])
assert.equal((await invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1}) as ApplicationPreview).interfaces.items[0].observed.dl.value,null)
await pool.query("UPDATE uptime_speed_probes SET enabled=false WHERE id=$1",[previewProbeId])
assert.equal((await invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1}) as ApplicationPreview).interfaces.items[0].observed.ping.value,null)
const paged=await invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1,offset:1,limit:1}) as ApplicationPreview
assert.deepEqual(paged.interfaces.items,[]);assert.equal(paged.interfaces.total,1);assert.equal(paged.interfaces.nextOffset,null)
fixtureOspf["interface-template"]=[]
const noPeerReads=analysisPeerReads,emptyPreview=await invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1}) as ApplicationPreview
assert.equal(emptyPreview.interfacesTotal,0);assert.equal(emptyPreview.changes.total,0);assert.equal(analysisPeerReads,noPeerReads)
fixtureOspf["interface-template"]=[{...templatesBeforePreview[0],cost:"unknown"}]
await assert.rejects(invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1}),/не подтверждён/)
fixtureOspf["interface-template"]=templatesBeforePreview
countCatalogCalls=true
const beforeCanceled=catalogCalls
await assert.rejects(invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1},AbortSignal.abort()))
assert.equal(catalogCalls,beforeCanceled);countCatalogCalls=false
const beforePause=analysisPeerReads
ospfPreviewPauseConnection=applicationPreviewAccess.connection.id
await assert.rejects(invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1}))
assert.equal(analysisPeerReads,beforePause)
await pool.query("UPDATE mcp_connections SET policy=jsonb_set(policy,'{status}',to_jsonb('active'::text)) WHERE id=$1",[applicationPreviewAccess.connection.id])
const disabledPeerReads=analysisPeerReads
await pool.query("UPDATE servers SET enabled=false WHERE id=1")
await assert.rejects(invokeMcpTool(applicationPreviewPrincipal,"mm_ospf_application_preview",{serverId:1}))
assert.equal(analysisPeerReads,disabledPeerReads)
assert.equal(ospfAnalysisDispatches,0)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE connection_id=ANY($1::uuid[]) AND result::text LIKE '%NEVER_OSPF%'",[[applicationPreviewAccess.connection.id,isolatedPreviewAccess.connection.id]])).rows[0].n,0)
}finally{
countCatalogCalls=false;ospfPreviewPauseConnection=undefined
await pool.query("UPDATE mcp_connections SET policy=jsonb_set(policy,'{status}',to_jsonb('active'::text)) WHERE id=$1",[applicationPreviewAccess.connection.id])
fixtureOspf["interface-template"]=templatesBeforePreview
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
await pool.query("DELETE FROM uptime_speed_probes WHERE id=$1",[previewProbeId])
await pool.query("DELETE FROM traffic_samples WHERE server_id=1 AND interface_name='fixture-gre' AND sampled_at=ANY($1::timestamptz[])",[previewTrafficTimes])
await previewHttp.close()
}
console.log("✓ OSPF application preview shares REST ranking: scoped peer/native/SQL reads, hidden probe exclusion, modeled versus observed zero/unknown, aggregate continuity flags, no WG-peer substitution, pages, empty/malformed/disabled sources and no mutation/plan/audit leakage")
countCatalogCalls=true
try{await (await import("../../test/mcp-ospf-legacy.js")).acceptLegacyOspfPlans(actor,{
get:()=>fixtureOspf["interface-template"],set:rows=>{fixtureOspf["interface-template"]=rows as typeof fixtureOspf["interface-template"]},
reads:()=>catalogCalls,writes:()=>ospfAnalysisDispatches,resetWrites:value=>{ospfAnalysisDispatches=value},fault:value=>{ospfCostWriteFault=value},
})}finally{countCatalogCalls=false}
assert.equal((await (await import("./routing-observations.js")).readRoutingObservations([1, 2]))[0].sourceVerified, false, "Disable/re-enable must invalidate previous source attestation")
await attestRoutingFixture(observationId)
const proposal = await invokeMcpTool(analysisPrincipal, "mm_ospf_optimizer_analyze", { serverId: 1 }) as OspfAnalysis
assert.deepEqual(proposal.serverIds, [1, 2]); assert.equal(proposal.changes, 1)
assert.equal(proposal.ranking[0].currentCost, 30); assert.equal(proposal.ranking[0].proposedCost, 10)
assert.equal(proposal.ranking[0].observationId, observationId); assert.equal(proposal.ranking[0].peerId, 2)
assert.equal(proposal.proposalOnly, true); assert.equal(proposal.executionAvailable, false)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_plans WHERE connection_id=$1", [analysisAccess.connection.id])).rows[0].n, 0)
assert.equal(ospfAnalysisDispatches, 0)
await assert.rejects(invokeMcpTool(analysisPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }))
const writer = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "OSPF analysis comparison", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1, 2], operationIds: ["routing.ospf.optimize"], allowGlobal: false } }), actor)
const writerPrincipal = await authenticateMcpToken(writer.token)
const prepared = await invokeMcpTool(writerPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }) as { planId: string; changes: { before: { ranking: unknown[] } } }
assert.deepEqual(prepared.changes.before.ranking, proposal.ranking)
const observationEvidence = JSON.parse(await decryptSecret((await pool.query("SELECT evidence FROM mcp_plans WHERE id=$1", [prepared.planId])).rows[0].evidence.sealed))
const { verifyRoutingObservationChecks } = await import("./routing-observations.js")
await verifyRoutingObservationChecks(observationEvidence.observationChecks)
await assert.rejects(verifyRoutingObservationChecks(observationEvidence.observationChecks.map((check: Record<string, unknown>) => ({ ...check, validUntil: new Date(Date.now() - 1).toISOString() }))))
await approvePlan(prepared.planId, actor, true)
await pool.query("UPDATE mcp_routing_observations SET created_at=now()-interval '1 minute' WHERE id=$1", [observationId])
await attestRoutingFixture(observationId)
await pool.query("INSERT INTO mcp_routing_observations(id,src_server_id,dst_server_id,src_interface,dst_interface,family,routing_table,ping_ms,loss_pct,dl_mbps,ul_mbps,ping_at,bandwidth_at,context_verified,source) VALUES($1,1,2,'fixture-gre','peer','ipv4','main',12,50,100,200,now(),now(),true,'fixture')", [badObservationId])
await attestRoutingFixture(badObservationId)
await assert.rejects(invokeMcpTool(analysisPrincipal, "mm_ospf_optimizer_analyze", { serverId: 1 }), "A newer bad result must block fallback to an older healthy observation")
await assert.rejects(verifyRoutingObservationChecks(observationEvidence.observationChecks))
const staleOperation = await applyPlan(writerPrincipal, prepared.planId, randomUUID())
let staleState = "pending"
for (let attempt = 0; attempt < 100; attempt++) {
staleState = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [staleOperation.id])).rows[0].state
if (!["pending", "running"].includes(staleState)) break
await delay(20)
}
assert.equal(staleState, "rejected"); assert.equal(ospfAnalysisDispatches, 0)
await pool.query("UPDATE mcp_routing_observations SET loss_pct=0,context_verified=false WHERE id=$1", [badObservationId])
await attestRoutingFixture(badObservationId)
await assert.rejects(invokeMcpTool(analysisPrincipal, "mm_ospf_optimizer_analyze", { serverId: 1 }))
await pool.query("DELETE FROM mcp_routing_observations WHERE id=$1", [badObservationId])
await pool.query("UPDATE mcp_routing_observations SET loss_pct=5 WHERE id=$1", [observationId])
await attestRoutingFixture(observationId)
await assert.rejects(verifyRoutingObservationChecks(observationEvidence.observationChecks))
await assert.rejects(invokeMcpTool(analysisPrincipal, "mm_ospf_optimizer_analyze", { serverId: 1 }))
const overridden = await invokeMcpTool(analysisPrincipal, "mm_ospf_optimizer_analyze", { serverId: 1, maxLossPct: 5 }) as OspfAnalysis
assert.equal(overridden.ranking.length, 1)
await pool.query("UPDATE mcp_routing_observations SET loss_pct=0,ping_at=now()-interval '10 minutes' WHERE id=$1", [observationId])
await attestRoutingFixture(observationId)
await assert.rejects(invokeMcpTool(analysisPrincipal, "mm_ospf_optimizer_analyze", { serverId: 1 }))
const limitedAnalysis = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "OSPF isolated analysis", mode: "observer", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read"], scope: { serverIds: [1], operationIds: ["routing.ospf.analyze"], allowGlobal: false } }), actor)
const readsBefore = analysisPeerReads
await assert.rejects(invokeMcpTool(await authenticateMcpToken(limitedAnalysis.token), "mm_ospf_optimizer_analyze", { serverId: 1 }))
assert.equal(analysisPeerReads, readsBefore); assert.equal(ospfAnalysisDispatches, 0)
await pool.query("UPDATE mcp_routing_observations SET loss_pct=0,ping_at=now(),bandwidth_at=now(),context_verified=true WHERE id=$1", [observationId])
await attestRoutingFixture(observationId)
const costBaseline = structuredClone(fixtureOspf["interface-template"])
const waitCost = waitRecursiveOperation
const rejectGenuinelyQueuedOldVersion = async (principal: Parameters<typeof applyPlan>[0], planId: string, oldVersion: number, description: string) => {
const originalPoolQuery = pool.query, query = originalPoolQuery.bind(pool)
let release!: () => void
const barrier = new Promise<void>(done => { release = done })
let paused: { id: string; plan_id: string; state: string } | undefined
let operation: Awaited<ReturnType<typeof applyPlan>> | undefined, terminal: string | undefined
const dispatches = ospfAnalysisDispatches
// Delegate every original query with unchanged arguments/results. Hold
// only the REAL matching running row, before executeOperationWithLease
// can loadPlan. Admission and its private capabilities stay genuine.
pool.query = ((...args: unknown[]) => {
const actual = (query as (...values: unknown[]) => unknown)(...args)
if (args[0] !== "SELECT * FROM mcp_operations WHERE id=$1 AND state='running'") return actual
return (actual as Promise<{ rows: { id: string; plan_id: string; state: string }[] }>).then(async result => {
const row = result.rows[0]
if (!paused && row?.plan_id === planId) {
assert.equal(row.state, "running"); paused = row
await barrier
}
return result
})
}) as typeof pool.query
try {
operation = await applyPlan(principal, planId, randomUUID())
const deadline = Date.now() + 10000
while (!paused) {
assert(Date.now() < deadline, "The genuine runner did not reach the matching queued-version observation")
await delay(10)
}
assert.equal(paused.id, operation.id); assert.equal(paused.plan_id, planId)
await query("UPDATE mcp_plans SET operation_version=$2 WHERE id=$1", [planId, oldVersion])
} finally {
// Always release the original returned row, restore the observer and
// join the actual admitted operation before native fixture cleanup.
release(); pool.query = originalPoolQuery
if (operation) terminal = await waitCost(operation.id)
}
assert(operation)
assert.equal(terminal, "rejected", description)
assert.equal((await query("SELECT error_code FROM mcp_operations WHERE id=$1", [operation.id])).rows[0].error_code, "PLAN_EXPIRED")
assert.equal(ospfAnalysisDispatches, dispatches)
}
let thirdOwnerRows: Record<string, string>[] = [{ ".id": "*third", name: "third", "router-id": "192.0.2.103", disabled: "false", version: "2", vrf: "main" }], thirdOwnerReads = 0
let thirdOwnerDuringRead: (() => Promise<unknown>) | undefined
let thirdOwnerIds: Record<string, string>[] = []
let thirdOwnerNeighbors: Record<string, string>[] = [], thirdOwnerAddresses: Record<string, string>[] = []
const thirdOwner = createServer(async (req, res) => {
thirdOwnerReads++
if (ospfAnalysisFixtures) ospfAnalysisNativeRequests++
if (thirdOwnerDuringRead) { const work = thirdOwnerDuringRead; thirdOwnerDuringRead = undefined; await work() }
res.setHeader("content-type", "application/json")
if (req.url === "/rest/routing/id") { res.end(JSON.stringify(thirdOwnerIds)); return }
if (req.url === "/rest/routing/ospf/neighbor") { res.end(JSON.stringify(thirdOwnerNeighbors)); return }
if (req.url === "/rest/ip/address") { res.end(JSON.stringify(thirdOwnerAddresses)); return }
if (req.url === "/rest/routing/ospf/instance/get") {
let body = ""; for await (const chunk of req) body += chunk
const key = JSON.parse(body)["value-name"]
res.end(JSON.stringify({ ret: ({ version: "2", vrf: "remote-named-vrf", "router-id": "main" } as Record<string, string>)[key] })); return
}
res.end(JSON.stringify(thirdOwnerRows))
})
await new Promise<void>(resolve => thirdOwner.listen(0, "127.0.0.1", resolve))
await pool.query("INSERT INTO servers(id,name,host,port,use_ssl,password) VALUES(103,'unselected-ospf-owner','127.0.0.1',$1,false,'NEVER_OSPF_UNUSED_SECRET')", [(thirdOwner.address() as { port: number }).port])
const graphPolicy = { limits: { callsPerMinute: 120, mutationsPerHour: 100 }, name: "OSPF complete owners", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:write"], scope: { serverIds: [1, 2, 103], operationIds: ["routing.ospf.optimize", "operations.recover"], allowGlobal: false } }
const graphAccess = await createMcpConnection(mcpConnectionCreateSchema.parse(graphPolicy), actor), graphPrincipal = await authenticateMcpToken(graphAccess.token)
const graphPrimaryInstances = structuredClone(fixtureOspf.instance)
const graphPeerInstances = structuredClone(analysisPeerInstances), graphPeerNeighbors = structuredClone(analysisPeerNeighbors), graphPeerAddresses = structuredClone(analysisPeerAddresses)
try {
const dispatchesBeforePassive = ospfAnalysisDispatches
fixtureOspf["interface-template"][0].passive = "true"
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }), (error: { code?: string }) => error.code === "MEASUREMENT_UNKNOWN", "A passive template cannot become eligible through a stale Full neighbor")
for (const passive of ["true", "false"]) {
fixtureOspf["interface-template"] = [...structuredClone(costBaseline), { ...costBaseline[0], ".id": "*passive", interfaces: "fixture-loop", passive }]
const mixedPassive = await invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }) as { planId: string }
const mixedRow = (await pool.query("SELECT evidence FROM mcp_plans WHERE id=$1", [mixedPassive.planId])).rows[0]
const mixedEvidence = JSON.parse(await decryptSecret(mixedRow.evidence.sealed)) as { before: { ranking: { interface: string }[] }; steps: { step: { id: string } }[] }
assert.deepEqual(mixedEvidence.before.ranking.map(row => row.interface), [costBaseline[0].interfaces])
assert.deepEqual(mixedEvidence.steps.map(row => row.step.id), [costBaseline[0][".id"]])
}
assert.equal(ospfAnalysisDispatches, dispatchesBeforePassive, "Passive or no-Full templates with unknown BFD cannot block or enter the selected GRE plan")
fixtureOspf["interface-template"] = [{ ...costBaseline[0], interfaces: "fixture-loop" }]
ospfAnalysisExtraNeighbors = [{ ".id": "*loop", instance: "fixture-ospf", interface: "fixture-loop", state: "Full", "router-id": "192.0.2.2", address: "192.0.2.2" }]
try {
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }), (error: { code?: string; message?: string }) => error.code === "MEASUREMENT_UNKNOWN" && Boolean(error.message?.includes("use-bfd")), "Unknown BFD remains forbidden for a Full candidate")
} finally { ospfAnalysisExtraNeighbors = [] }
fixtureOspf["interface-template"] = structuredClone(costBaseline)
for (const listsBeforePause of [0, 1]) {
const readsBeforePause: number = ospfTemplateFlagReads
ospfPauseOnTemplatesConnection = graphAccess.connection.id; ospfTemplateListsBeforePause = listsBeforePause
try {
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }))
assert.equal(ospfTemplateFlagReads, readsBeforePause + listsBeforePause * 2, "Pause committed during either template list must stop before another flag receipt")
} finally { ospfPauseOnTemplatesConnection = undefined; await setConnectionStatus(graphAccess.connection.id, "active", actor) }
}
const limitedGraph = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...graphPolicy, name: "OSPF owner budget", limits: { serversPerPlan: 2 } }), actor)
const readsBeforeBudget = [thirdOwnerReads, analysisPeerReads]
await assert.rejects(invokeMcpTool(await authenticateMcpToken(limitedGraph.token), "mm_ospf_optimizer_plan", { serverId: 1 }))
assert.deepEqual([thirdOwnerReads, analysisPeerReads], readsBeforeBudget, "All owner dependencies must fit policy before native polling")
await setConnectionStatus(limitedGraph.connection.id, "paused", actor)
for (const fault of ["none", "duplicate", "empty", "credential", "disabled", "during-read", "other-family", "family-change", "elected-change", "elected-inactive", "elected-defaults", "unrelated-vrf", "isolated-vrf", "peer-vrf", "peer-down", "peer-address", "peer-interface", "counter-only", "post-peer-down", "template-order", "post-template-order"]) {
fixtureOspf["interface-template"] = structuredClone(costBaseline)
if (fault === "template-order" || fault === "post-template-order") fixtureOspf["interface-template"].push({ ...costBaseline[0], ".id": "*passive", interfaces: "fixture-loop", passive: "true" })
if (fault === "other-family" || fault === "family-change") Object.assign(thirdOwnerRows[0], { "router-id": "192.0.2.2", version: "3", vrf: "remote-named-vrf" })
if (fault.startsWith("elected-")) {
thirdOwnerRows[0]["router-id"] = "main"
thirdOwnerIds = [{ ".id": "*ref", name: "main", "dynamic-id": "192.0.2.103", disabled: "false", inactive: "false" }]
if (fault === "elected-defaults") { delete thirdOwnerRows[0].version; delete thirdOwnerRows[0].vrf; delete thirdOwnerRows[0]["router-id"] }
}
if (fault === "unrelated-vrf") {
fixtureOspf.instance.push({ ".id": "*other", name: "other-instance", vrf: "isolated", "router-id": "192.0.2.200", version: "2", disabled: "false" })
ospfAnalysisExtraNeighbors = [{ ".id": "*other-neighbor", interface: "other-iface", instance: "other-instance", "router-id": "192.0.2.1", address: "198.51.100.1", state: "Full" }]
thirdOwnerRows[0]["router-id"] = "192.0.2.1"
}
if (fault === "isolated-vrf") {
Object.assign(thirdOwnerRows[0], { "router-id": "192.0.2.2", vrf: "isolated-third-vrf" })
thirdOwnerNeighbors = [{ ".id": "*tn", instance: "third", interface: "third", "router-id": "192.0.2.1", address: "198.51.100.1", state: "Full" }]
thirdOwnerAddresses = [{ ".id": "*ta", interface: "third", address: "198.51.100.3/24", disabled: "false", invalid: "false" }]
}
if (fault === "peer-vrf") analysisPeerInstances[0].vrf = "remote-different-vrf"
const prepared = await invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }) as { planId: string; changes: { target: { serverIds: number[] }; ospfOwnerGraph: { sourceSecretProofs: unknown; instances: { serverId: number }[] } } }
assert.deepEqual(prepared.changes.target.serverIds, [1, 2, 103])
assert.deepEqual(prepared.changes.ospfOwnerGraph.instances.map(row => row.serverId), [1, 2, 103])
assert.equal(prepared.changes.ospfOwnerGraph.sourceSecretProofs, "[redacted]")
assert.ok(!JSON.stringify(prepared).includes("NEVER_OSPF_UNUSED_SECRET"))
await approvePlan(prepared.planId, actor, true)
if (fault === "duplicate") thirdOwnerRows[0]["router-id"] = "192.0.2.2"
if (fault === "empty") thirdOwnerRows = []
if (fault === "credential") await pool.query("UPDATE servers SET password='changed-unused-owner' WHERE id=103")
if (fault === "disabled") await pool.query("UPDATE servers SET enabled=false WHERE id=103")
if (fault === "during-read") thirdOwnerDuringRead = () => pool.query("UPDATE servers SET password='changed-during-native-read' WHERE id=103")
if (fault === "family-change") thirdOwnerRows[0].version = "2"
if (fault === "elected-change") thirdOwnerIds[0]["dynamic-id"] = "192.0.2.2"
if (fault === "elected-inactive") thirdOwnerIds[0].inactive = "true"
if (fault === "peer-down") analysisPeerNeighbors[0].state = "Down"
if (fault === "peer-address") analysisPeerAddresses[0].address = "192.0.2.99/30"
if (fault === "peer-interface") analysisPeerNeighbors[0].interface = "another-interface"
if (fault === "counter-only") Object.assign(analysisPeerNeighbors[0], { adjacency: "99h", "state-changes": "999" })
if (fault === "post-peer-down") ospfAfterCostPatch = () => { analysisPeerNeighbors[0].state = "Down" }
if (fault === "template-order") fixtureOspf["interface-template"].reverse()
if (fault === "post-template-order") ospfAfterCostPatch = () => { fixtureOspf["interface-template"].reverse() }
const dispatches: number = ospfAnalysisDispatches, requestsBeforeApply = ospfAnalysisNativeRequests, key = randomUUID(), operation = await applyPlan(graphPrincipal, prepared.planId, key)
const positive = ["none", "other-family", "elected-defaults", "unrelated-vrf", "isolated-vrf", "peer-vrf", "counter-only"].includes(fault)
assert.equal(await waitCost(operation.id), positive ? "applied" : fault === "post-peer-down" ? "partial" : fault === "post-template-order" ? "unknown" : "rejected", fault)
assert.equal(ospfAnalysisDispatches, dispatches + (positive || fault === "post-peer-down" || fault === "post-template-order" ? 1 : 0), fault)
assert.equal((await applyPlan(graphPrincipal, prepared.planId, key)).id, operation.id)
if (fault === "none") {
const nativeRequests = ospfAnalysisNativeRequests - requestsBeforeApply
assert.ok(nativeRequests <= 160, `One OSPF cost PATCH caused ${nativeRequests} native requests; full graph polling must not run inside each catalog callback`)
console.log(`✓ OSPF dispatch read budget: ${nativeRequests} native requests across three owners, including one PATCH; no nested full graph polling`)
await pool.query("UPDATE mcp_plans SET operation_version=8 WHERE id=$1", [prepared.planId])
try { await assert.rejects(invokeMcpTool(graphPrincipal, "mm_operation_recovery_plan", { operationId: operation.id }), (error: { code?: string }) => error.code === "PLAN_EXPIRED") }
finally { await pool.query("UPDATE mcp_plans SET operation_version=9 WHERE id=$1", [prepared.planId]) }
const oldInverse = await invokeMcpTool(graphPrincipal, "mm_operation_recovery_plan", { operationId: operation.id }) as { planId: string }
await approvePlan(oldInverse.planId, actor, true)
await pool.query("UPDATE mcp_plans SET operation_version=1 WHERE id=$1", [oldInverse.planId])
await assert.rejects(applyPlan(graphPrincipal, oldInverse.planId, randomUUID()), (error: { code?: string }) => error.code === "PLAN_EXPIRED")
const queuedInverse = await invokeMcpTool(graphPrincipal, "mm_operation_recovery_plan", { operationId: operation.id }) as { planId: string }
await approvePlan(queuedInverse.planId, actor, true)
await rejectGenuinelyQueuedOldVersion(graphPrincipal, queuedInverse.planId, 1, "Queued old inverse revision cannot escape the runner version check")
}
if (fault === "post-peer-down" || fault === "post-template-order") {
const verified = (await pool.query("SELECT count(*)::int AS n FROM mcp_operation_steps WHERE operation_id=$1 AND state='verified'", [operation.id])).rows[0].n
assert.equal(verified, 0, "A peer or template-order change after ACK cannot leave a verified cost checkpoint")
}
if (fault === "none" || fault === "peer-vrf") {
const inverse = await invokeMcpTool(graphPrincipal, "mm_operation_recovery_plan", { operationId: operation.id }) as { planId: string }
const inverseEvidence = JSON.parse(await decryptSecret((await pool.query("SELECT evidence FROM mcp_plans WHERE id=$1", [inverse.planId])).rows[0].evidence.sealed))
assert.equal(inverseEvidence.steps[0].step.expectedCost, 10, "Inverse must compare the applied cost, not the original pre-write value")
assert.equal(inverseEvidence.steps[0].step.fields.cost, costBaseline[0].cost)
assert.deepEqual(inverseEvidence.ospfOwnerGraph.instances.map((row: { serverId: number }) => row.serverId), [1, 2, 103])
await approvePlan(inverse.planId, actor, true)
if (fault === "peer-vrf") analysisPeerNeighbors[0].state = "Down"
const beforeInverse: number = ospfAnalysisDispatches, inverseKey = randomUUID(), inverseOperation = await applyPlan(graphPrincipal, inverse.planId, inverseKey)
assert.equal(await waitCost(inverseOperation.id), fault === "none" ? "applied" : "rejected")
assert.equal(ospfAnalysisDispatches, beforeInverse + (fault === "none" ? 1 : 0))
assert.equal((await applyPlan(graphPrincipal, inverse.planId, inverseKey)).id, inverseOperation.id)
if (fault === "none") assert.deepEqual(fixtureOspf["interface-template"], costBaseline)
}
thirdOwnerRows = [{ ".id": "*third", name: "third", "router-id": "192.0.2.103", disabled: "false", version: "2", vrf: "main" }]
thirdOwnerIds = []
thirdOwnerNeighbors = []; thirdOwnerAddresses = []
analysisPeerInstances = structuredClone(graphPeerInstances); analysisPeerNeighbors = structuredClone(graphPeerNeighbors); analysisPeerAddresses = structuredClone(graphPeerAddresses)
ospfAnalysisExtraNeighbors = []; fixtureOspf.instance = structuredClone(graphPrimaryInstances)
await pool.query("UPDATE servers SET password='NEVER_OSPF_UNUSED_SECRET',enabled=true WHERE id=103")
}
const contextDispatches = ospfAnalysisDispatches
Object.assign(thirdOwnerRows[0], { "router-id": "192.0.2.2", vrf: "cloned-context" })
thirdOwnerNeighbors = [{ ".id": "*tn", instance: "third", interface: "third", "router-id": "192.0.2.1", address: "192.0.2.1", state: "Full" }]
thirdOwnerAddresses = [{ ".id": "*ta", interface: "third", address: "192.0.2.2/30", disabled: "false", invalid: "false" }]
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }), (error: { code?: string }) => error.code === "MEASUREMENT_UNKNOWN", "Two devices with identical reciprocal contexts remain ambiguous")
thirdOwnerRows[0]["router-id"] = "192.0.2.103"; thirdOwnerNeighbors = []; thirdOwnerAddresses = []
analysisPeerInstances.push({ ...analysisPeerInstances[0], ".id": "*second", name: "second-vrf", vrf: "another-peer-vrf" })
analysisPeerNeighbors.push({ ...analysisPeerNeighbors[0], ".id": "*secondn", instance: "second-vrf", interface: "another-peer-interface" })
analysisPeerAddresses.push({ ...analysisPeerAddresses[0], ".id": "*seconda", interface: "another-peer-interface" })
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }), (error: { code?: string }) => error.code === "MEASUREMENT_UNKNOWN", "Two matching VRFs on the same peer are not merged by device ID")
analysisPeerInstances = structuredClone(graphPeerInstances); analysisPeerNeighbors = structuredClone(graphPeerNeighbors); analysisPeerAddresses = structuredClone(graphPeerAddresses)
await pool.query("UPDATE mcp_routing_observations SET dst_interface='wrong-peer-interface' WHERE id=$1", [observationId])
await attestRoutingFixture(observationId)
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }), "Metric for another peer interface cannot be substituted")
await pool.query("UPDATE mcp_routing_observations SET dst_interface='peer' WHERE id=$1", [observationId]); await attestRoutingFixture(observationId)
assert.equal(ospfAnalysisDispatches, contextDispatches)
const preparationReads = thirdOwnerReads
thirdOwnerDuringRead = () => setConnectionStatus(graphAccess.connection.id, "paused", actor)
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }))
assert.equal(thirdOwnerReads, preparationReads + 1, "Pause during preparation stops before another native context read")
await setConnectionStatus(graphAccess.connection.id, "active", actor)
const cancelledReads = thirdOwnerReads, preparationCancel = new AbortController()
thirdOwnerDuringRead = async () => preparationCancel.abort()
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }, preparationCancel.signal))
assert.equal(thirdOwnerReads, cancelledReads + 1, "Cancellation stops before another native context read")
const changedReads = thirdOwnerReads
thirdOwnerDuringRead = () => pool.query("UPDATE servers SET password='changed-during-preparation' WHERE id=103")
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }))
assert.equal(thirdOwnerReads, changedReads + 1, "Source drift during preparation stops before another native context read")
await pool.query("UPDATE servers SET password='NEVER_OSPF_UNUSED_SECRET' WHERE id=103")
fixtureOspf["interface-template"] = structuredClone(costBaseline)
await pool.query("UPDATE servers SET enabled=false WHERE id=103")
const disabledReads = [thirdOwnerReads, analysisPeerReads]
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }))
assert.deepEqual([thirdOwnerReads, analysisPeerReads], disabledReads, "Monitoring disabled cannot be guessed to mean an absent Router ID owner")
await pool.query("UPDATE servers SET enabled=true WHERE id=103")
fixtureOspf["interface-template"] = structuredClone(costBaseline)
const graphLease = await pool.connect()
try {
await graphLease.query("SELECT pg_advisory_lock(hashtextextended('mm-config:103',0))")
const prepared = await invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }) as { planId: string }
await approvePlan(prepared.planId, actor, true)
const dispatches = ospfAnalysisDispatches, key = randomUUID(), operation = await applyPlan(graphPrincipal, prepared.planId, key)
assert.equal(await waitCost(operation.id), "rejected"); assert.equal(ospfAnalysisDispatches, dispatches, "Unselected owner participates in the actual multi-router lease")
} finally { await graphLease.query("SELECT pg_advisory_unlock(hashtextextended('mm-config:103',0))"); graphLease.release() }
fixtureOspf["interface-template"] = structuredClone(costBaseline)
thirdOwnerRows = Array.from({ length: 10001 }, (_, n) => ({ ".id": "*third" + n, name: "third" + n, "router-id": "192.0.2.103", disabled: "false", version: "2", vrf: "main" }))
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }))
thirdOwnerRows = [{ ".id": "*third", name: "third", "router-id": "192.0.2.103", disabled: "false", version: "2", vrf: "main", opaque: "x".repeat(1048576) }]
await assert.rejects(invokeMcpTool(graphPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }))
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE connection_id=$1 AND result::text LIKE '%NEVER_OSPF_UNUSED_SECRET%'", [graphAccess.connection.id])).rows[0].n, 0)
console.log("✓ OSPF full owner graph: unselected third device sealed and locked, late duplicate/removal/credential/disable reject before PATCH, positive cost, scoped server budget before GET, private proofs and bounded graph")
console.log("✓ OSPF VRF link context: reciprocal Full plus both address/interface bindings, different VRF names, isolated duplicate accepted, cloned contexts and wrong peer metric refused; late/post-write drift, counter tolerance, preparation pause/cancel/source fencing and no replay")
} finally {
ospfAfterCostPatch = undefined
analysisPeerInstances = graphPeerInstances; analysisPeerNeighbors = graphPeerNeighbors; analysisPeerAddresses = graphPeerAddresses
ospfAnalysisExtraNeighbors = []; fixtureOspf.instance = graphPrimaryInstances
await setConnectionStatus(graphAccess.connection.id, "paused", actor)
await pool.query("DELETE FROM servers WHERE id=103")
await new Promise<void>(resolve => thirdOwner.close(() => resolve()))
fixtureOspf["interface-template"] = structuredClone(costBaseline)
}
try {
const savedPassword = (await pool.query("SELECT password FROM servers WHERE id=1")).rows[0].password
const credentialCandidate = await invokeMcpTool(writerPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }) as { planId: string }
await approvePlan(credentialCandidate.planId, actor, true)
await pool.query("UPDATE servers SET password='NEVER_OSPF_CHANGED_CREDENTIAL' WHERE id=1")
const credentialDispatches = ospfAnalysisDispatches
try {
const op = await applyPlan(writerPrincipal, credentialCandidate.planId, randomUUID())
assert.equal(await waitCost(op.id), "rejected")
assert.equal(ospfAnalysisDispatches, credentialDispatches, "Credential drift must stop before PATCH even if native configuration is identical")
} finally { await pool.query("UPDATE servers SET password=$1 WHERE id=1", [savedPassword]) }
await attestRoutingFixture(observationId)
const oldVersionCandidate = await invokeMcpTool(writerPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }) as { planId: string }
await approvePlan(oldVersionCandidate.planId, actor, true)
await pool.query("UPDATE mcp_plans SET operation_version=6 WHERE id=$1", [oldVersionCandidate.planId])
await assert.rejects(applyPlan(writerPrincipal, oldVersionCandidate.planId, randomUUID()), (error: { code?: string }) => error.code === "PLAN_EXPIRED")
assert.equal(ospfAnalysisDispatches, credentialDispatches)
const queuedVersionCandidate = await invokeMcpTool(writerPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }) as { planId: string }
await approvePlan(queuedVersionCandidate.planId, actor, true)
await rejectGenuinelyQueuedOldVersion(writerPrincipal, queuedVersionCandidate.planId, 6, "Previously queued old revision must not escape the runner version check")
assert.equal(ospfAnalysisDispatches, credentialDispatches)
for (const fault of ["none", "ignored", "changed-field", "lost-response"]) {
fixtureOspf["interface-template"] = structuredClone(costBaseline)
Object.assign(fixtureOspf["interface-template"][0], { opaque: "NEVER_OSPF_OPAQUE" })
ospfCostWriteFault = fault
const candidate = await invokeMcpTool(writerPrincipal, "mm_ospf_optimizer_plan", { serverId: 1 }) as { planId: string }
await approvePlan(candidate.planId, actor, true)
const key = randomUUID(), beforeDispatch: number = ospfAnalysisDispatches, op = await applyPlan(writerPrincipal, candidate.planId, key)
assert.equal(await waitCost(op.id), fault === "none" ? "applied" : "unknown")
assert.equal(ospfAnalysisDispatches, beforeDispatch + 1, "Cost must use exactly one PATCH and never replay it")
assert.equal((await applyPlan(writerPrincipal, candidate.planId, key)).id, op.id)
assert.equal(ospfAnalysisDispatches, beforeDispatch + 1)
if (fault === "none") { assert.equal(fixtureOspf["interface-template"][0].cost, "10"); assert.equal((fixtureOspf["interface-template"][0] as Record<string, string>).opaque, "NEVER_OSPF_OPAQUE") }
}
} finally { fixtureOspf["interface-template"] = costBaseline; ospfCostWriteFault = "none" }
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE connection_id=$1 AND result::text LIKE '%NEVER_OSPF_OPAQUE%'", [writer.connection.id])).rows[0].n, 0)
console.log("✓ Shared OSPF cost writer over actual MCP/HTTP: sealed expected cost, opaque-field preservation, ignored/changed/lost result stop and idempotency without PATCH replay")
} finally {
ospfAnalysisFixtures = false
await pool.query("UPDATE servers SET port=$1 WHERE id=2", [port])
await pool.query("DELETE FROM mcp_routing_observations WHERE id=ANY($1::uuid[])", [[observationId, badObservationId]])
await new Promise<void>(resolve => analysisPeer.close(() => resolve()))
}
console.log("✓ Observer OSPF analysis shares the sealed planner ranking, dispatches no writes/plans, narrows peer scope and rejects stale/lossy observations by default")
ecmpFixtures = true
const ecmpBaseline = [0, 1].map(index => ({ ".id": `*ecmp${index}`, "dst-address": "192.0.2.0/24", "routing-table": "main", gateway: `192.0.2.${index + 2}`, "immediate-gw": `192.0.2.${index + 2}%fixture-gre`, distance: String((index + 1) * 10), active: index === 0 ? "true" : "false", comment: "MikrotikManager: integration", disabled: "false" }))
fixtureEcmpRoutes = structuredClone(ecmpBaseline)
const ecmpAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ name: "ECMP transition test", mode: "approval", expiresAt: new Date(Date.now() + 1800000).toISOString(), permissions: ["mm:network:read", "mm:network:write"], scope: { serverIds: [1], operationIds: ["routing.ecmp.update", "routing.rpf.update", "ros.ip_settings.update", "operations.recover"], allowGlobal: false } }), actor)
const ecmpPrincipal = await authenticateMcpToken(ecmpAccess.token)
const ecmpArgs = { serverId: 1, family: "ipv4", routeIds: ["*ecmp0", "*ecmp1"], distance: 10 }
const equalPlan = await invokeMcpTool(ecmpPrincipal, "mm_ecmp_plan", ecmpArgs) as { planId: string }
await approvePlan(equalPlan.planId, actor, true)
const equalOperation = await applyPlan(ecmpPrincipal, equalPlan.planId, randomUUID())
await awaitOperation(equalOperation.id, "applied"); assert.equal(ecmpWrites, 2)
assert.ok(fixtureEcmpRoutes.every(row => row.active === "true" && row.distance === "10"))
const unequalPlan = await invokeMcpTool(ecmpPrincipal, "mm_operation_recovery_plan", { operationId: equalOperation.id }) as { planId: string }
await approvePlan(unequalPlan.planId, actor, true)
await awaitOperation((await applyPlan(ecmpPrincipal, unequalPlan.planId, randomUUID())).id, "applied")
assert.deepEqual(fixtureEcmpRoutes, ecmpBaseline)
const staleEcmp = await invokeMcpTool(ecmpPrincipal, "mm_ecmp_plan", ecmpArgs) as { planId: string }
await approvePlan(staleEcmp.planId, actor, true)
fixtureEcmpRoutes[1]["immediate-gw"] = ""
await awaitOperation((await applyPlan(ecmpPrincipal, staleEcmp.planId, randomUUID())).id, "rejected"); assert.equal(ecmpWrites, 4)
fixtureEcmpRoutes = structuredClone(ecmpBaseline)
const brokenEcmp = await invokeMcpTool(ecmpPrincipal, "mm_ecmp_plan", ecmpArgs) as { planId: string }
await approvePlan(brokenEcmp.planId, actor, true)
loseEcmpGateway = true
const brokenOperation = await applyPlan(ecmpPrincipal, brokenEcmp.planId, randomUUID())
await awaitOperation(brokenOperation.id, "partial"); assert.equal(ecmpWrites, 6)
await applyPlan(ecmpPrincipal, brokenEcmp.planId, randomUUID()); await delay(30); assert.equal(ecmpWrites, 6)
loseEcmpGateway = false; fixtureEcmpRoutes = structuredClone(ecmpBaseline)
const tableProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'integration')", [tableProtection, JSON.stringify({ kind: "routing_table", id: "*main", serverId: 1, protection: "deny" })])
await assert.rejects(invokeMcpTool(ecmpPrincipal, "mm_ecmp_plan", ecmpArgs))
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [tableProtection])
const settingsProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'integration')", [settingsProtection, JSON.stringify({ kind: "ip_settings", id: "singleton", serverId: 1, protection: "deny" })])
await assert.rejects(invokeMcpTool(ecmpPrincipal, "mm_ecmp_plan", { ...ecmpArgs, hashPolicy: "l4" }))
await assert.rejects(invokeMcpTool(ecmpPrincipal, "mm_rpf_plan", { serverId: 1, mode: "loose", acknowledgeAsymmetry: true }))
await assert.rejects(invokeMcpTool(ecmpPrincipal, "mm_ip_settings_update_plan", { serverId: 1, fields: { "rp-filter": "loose" } }))
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [settingsProtection])
ecmpFixtures = false
console.log("✓ ECMP: resolved inactive candidate, equal-active transition, inverse to unequal distances, lost resolution before/after write and table protection")
const plan = await invokeMcpTool(principal, "mm_ip_settings_update_plan", { serverId: 1, fields: { "rp-filter": "loose" } }) as { planId: string; state: string }
assert.equal(plan.state, "awaiting-approval")
await assert.rejects(applyPlan(principal, plan.planId, "test-key"))
await approvePlan(plan.planId, actor, true)
const operation = await applyPlan(principal, plan.planId, "test-key")
assert.equal((await applyPlan(principal, plan.planId, "test-key")).id, operation.id)
let state = "pending"
for (let index = 0; index < 100; index++) {
const row = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [operation.id])).rows[0]
state = row.state
if (!["pending", "running"].includes(state)) break
await delay(30)
}
assert.equal(state, "applied"); assert.equal(writes, 1); assert.equal(settings["rp-filter"], "loose")
assert.equal((await pool.query("SELECT state FROM mcp_operation_steps WHERE operation_id=$1", [operation.id])).rows[0].state, "verified")
console.log("✓ Human approval, write-ahead intent, single idempotent write and read-back verification")
const stale = await invokeMcpTool(principal, "mm_ip_settings_update_plan", { serverId: 1, fields: { "rp-filter": "strict" } }) as { planId: string }
await approvePlan(stale.planId, actor, true)
settings["rp-filter"] = "no"
const conflict = await applyPlan(principal, stale.planId, "conflict-key")
for (let index = 0; index < 100; index++) {
state = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [conflict.id])).rows[0].state
if (!["pending", "running"].includes(state)) break
await delay(30)
}
assert.equal(state, "rejected"); assert.equal(writes, 1)
console.log("✓ Changed snapshots reject execution before contacting the write endpoint")
const expiring = await invokeMcpTool(principal, "mm_ip_settings_update_plan", { serverId: 1, fields: { "rp-filter": "loose" } }) as { planId: string }
const sealedEvidence = (await pool.query("SELECT evidence FROM mcp_plans WHERE id=$1", [expiring.planId])).rows[0].evidence
const expiringEvidence = JSON.parse(await decryptSecret(sealedEvidence.sealed))
expiringEvidence.validUntil = new Date(Date.now() - 1000).toISOString()
await pool.query("UPDATE mcp_plans SET evidence=$2::jsonb WHERE id=$1", [expiring.planId, JSON.stringify({ sealed: await encryptSecret(JSON.stringify(expiringEvidence)) })])
await approvePlan(expiring.planId, actor, true)
const mutationBudgetBeforeExpiry = (await pool.query("SELECT kind,bucket,used FROM mcp_budget_buckets WHERE connection_id=$1 AND kind='mutations' ORDER BY bucket", [principal.connectionId])).rows
await assert.rejects(applyPlan(principal, expiring.planId, "expired-measurement"), (error: { code?: string }) => error.code === "MEASUREMENT_UNKNOWN")
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_operations WHERE plan_id=$1", [expiring.planId])).rows[0].n, 0)
assert.deepEqual((await pool.query("SELECT kind,bucket,used FROM mcp_budget_buckets WHERE connection_id=$1 AND kind='mutations' ORDER BY bucket", [principal.connectionId])).rows, mutationBudgetBeforeExpiry)
assert.equal(writes, 1)
console.log("✓ Expired measurement evidence refuses admission with its own reason before operation, mutation debit or native write")
const { routerClient } = await import("./resources.js")
const nativeClient = (await routerClient(1)).client, protectionId = randomUUID(), writesBeforeProtection = writes
const { updateServer } = await import("../servers/service/servers-service.js")
const nameBeforeGuard = (await pool.query("SELECT name FROM servers WHERE id=1")).rows[0].name
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,'integration')", [protectionId, JSON.stringify({ kind: "server", id: "1", serverId: 1, protection: "deny" })])
try {
await assert.rejects(nativeClient.patch("/ip/settings", { "rp-filter": "strict" }), /защитой/)
await assert.rejects(updateServer(1, { name: "must-not-change" }))
assert.equal((await pool.query("SELECT name FROM servers WHERE id=1")).rows[0].name, nameBeforeGuard)
assert.equal(writes, writesBeforeProtection)
} finally { await pool.query("DELETE FROM mcp_protections WHERE id=$1", [protectionId]) }
const auditCount = (await pool.query("SELECT count(*)::int AS n FROM mcp_audit WHERE action='configuration.intent'")).rows[0].n
assert.ok(auditCount > 0)
const originalQuery = pool.query.bind(pool)
// Storage outage must be observed before any native network request is made.
pool.query = ((...args: unknown[]) => {
if (typeof args[0] === "string" && args[0].startsWith("INSERT INTO mcp_audit")) return Promise.reject(new Error("test audit outage"))
return (originalQuery as (...args: unknown[]) => unknown)(...args)
}) as typeof pool.query
try { await assert.rejects(nativeClient.patch("/ip/settings", { "rp-filter": "strict" }), /audit outage/); await assert.rejects(updateServer(1, { name: "must-not-change" }), /audit outage/); assert.equal((await pool.query("SELECT name FROM servers WHERE id=1")).rows[0].name, nameBeforeGuard); assert.equal(writes, writesBeforeProtection) }
finally { pool.query = originalQuery as typeof pool.query }
console.log("✓ Legacy native writes cannot bypass server protection or unavailable write-ahead audit")
const { withConfigMutationLock } = await import("../../services/config-mutation-lock.js")
let wake!: () => void, late!: Promise<void>, lateWrites = 0
const wait = new Promise<void>(resolve => { wake = resolve })
await withConfigMutationLock([1], async () => {
late = wait.then(() => withConfigMutationLock([1], async () => { lateWrites++ }))
})
const competingLease = await pool.connect()
try {
await competingLease.query("SELECT pg_advisory_lock(hashtextextended('mm-config:1',0))")
wake(); await assert.rejects(late, /другой операцией/); assert.equal(lateWrites, 0)
} finally { await competingLease.query("SELECT pg_advisory_unlock(hashtextextended('mm-config:1',0))"); competingLease.release() }
console.log("✓ Detached children cannot reuse a released configuration lease")
const rotated = await rotateConnectionToken(issued.connection.id, actor)
await assert.rejects(authenticateMcpToken(issued.token))
await authenticateMcpToken(rotated.token)
const { buildApp } = await import("../../index.js")
const reserve = createServer()
await new Promise<void>(resolve => reserve.listen(0, "127.0.0.1", resolve))
const appPort = (reserve.address() as { port: number }).port
await new Promise<void>(resolve => reserve.close(() => resolve()))
const endpoint = `http://localhost:${appPort}/mcp`
process.env.MCP_PUBLIC_URL = endpoint
app = await buildApp({ startScheduler: false })
await app.listen({ port: appPort, host: "127.0.0.1" })
await (await import("../../test/mcp-backup-download.js")).verifyMcpBackupDownload(actor,app)
await (await import("../../test/mcp-database-backup.js")).verifyMcpDatabaseBackup(actor,app)
const fixtureScheduler = await import("../../services/scheduler-running.js")
const fixtureSchedulerWasPaused = fixtureScheduler.isSchedulerJobsPaused()
await fixtureScheduler.pauseSchedulerJobsAndWait()
try {
await (await import("./control-path-context-acceptance.js")).verifyMcpControlPathContext(actor)
await (await import("./routing-community-scoped-acceptance.js")).acceptScopedRouteCommunitySwitch(actor)
await (await import("../../test/mcp-terminal-diagnostics.js")).verifyMcpTerminalDiagnostics(actor, app)
await (await import("../../test/mcp-events-batch.js")).verifyMcpEventsBatch(actor, app)
await (await import("./wireguard-interface-update-acceptance.js")).acceptWireguardInterfaceUpdate(actor)
await (await import("./wireguard-import-acceptance.js")).acceptWireguardImport(actor)
await (await import("./wireguard-export-acceptance.js")).acceptWireguardExportMcp(actor, app)
await (await import("./protection-scope-acceptance.js")).acceptProtectionRegistrationScope(actor)
console.log("Routing controller CAS SQL:", await (await import("./routing-controller-cas-acceptance.js")).acceptRoutingControllerCas())
await (await import("../../test/mcp-server-connection.js")).verifyMcpServerConnection(actor)
await (await import("./ipsec-peer-delete-acceptance.js")).acceptIpsecPeerDeletion(actor)
await (await import("./ipsec-user-delete-acceptance.js")).acceptIpsecUserDeletion(actor)
await (await import("./ipsec-certificate-delete-acceptance.js")).acceptIpsecCertificateDeletion(actor)
await (await import("./ipsec-peer-update-acceptance.js")).acceptIpsecPeerUpdate(actor)
await (await import("./management-transport-acceptance.js")).acceptManagementTransport(actor)
await (await import("../../test/mcp-flow-purge.js")).verifyMcpFlowPurge(actor)
await (await import("./routing-community-context-compatibility-acceptance.js")).acceptRouteCommunityContextCompatibilityMcp(actor)
} finally { if (!fixtureSchedulerWasPaused) fixtureScheduler.resumeSchedulerJobs() }
const client = new Client({ name: "integration", version: "1.0.0" })
try {
await client.connect(new StreamableHTTPClientTransport(new URL(endpoint), { requestInit: { headers: { Authorization: `Bearer ${rotated.token}` } } }))
const listed = await client.listTools()
assert.ok(listed.tools.some(tool => tool.name === "mm_ip_settings_list"))
assert.ok(!listed.tools.some(tool => tool.name === "mm_servers_delete_plan"))
const result = await client.callTool({ name: "mm_ip_settings_list", arguments: { serverId: 1 } })
assert.ok(!result.isError)
console.log("✓ Official SDK HTTP initialize, filtered tools/list and tools/call")
} finally { await client.close() }
{
const access = await createMcpConnection(mcpConnectionCreateSchema.parse({
...input, name: "Logs follow maintenance", permissions: ["mm:servers:read"],
scope: { serverIds: [1], operationIds: ["logs.follow"], allowGlobal: false },
}), actor)
const follower = new Client({ name: "logs-follow-maintenance", version: "1.0.0" })
const { sharedDatabaseGate } = await import("../../services/shared-database-gate.js")
const original = pool.query
let arrived!: () => void, release!: () => void
const reading = new Promise<void>(resolve => { arrived = resolve })
const held = new Promise<void>(resolve => { release = resolve })
try {
await follower.connect(new StreamableHTTPClientTransport(new URL(endpoint), { requestInit: { headers: { Authorization: `Bearer ${access.token}` } } }))
pool.query = (async (...args: Parameters<typeof original>) => {
const text = typeof args[0] === "string" ? args[0] : args[0]?.text
const result = await Reflect.apply(original, pool, args)
if (typeof text === "string" && text.startsWith("SELECT GREATEST(COALESCE(max(id),0)")) {
arrived()
await held
}
return result
}) as typeof original
const following = follower.callTool({ name: "mm_logs_follow", arguments: { serverId: 1, waitSeconds: 30 } })
try {
const observation = new AbortController()
try {
await Promise.race([reading, following.then(() => { throw new Error("Follow finished before its stream query") }),
delay(5000, undefined, { signal: observation.signal }).then(() => { throw new Error("Follow stream query was not observed") })])
} finally { observation.abort() }
let exclusiveEntered = false
const maintenance = sharedDatabaseGate.exclusive(async () => { exclusiveEntered = true }, 5000)
try {
await delay(25)
assert.equal(exclusiveEntered, false, "maintenance must wait for the pending database read")
} finally {
release()
await maintenance
}
const result = await following
assert.equal(result.isError, true)
assert.match(JSON.stringify(result), /RESET_REQUIRED/)
assert.doesNotMatch(JSON.stringify(result), /"cursor"/)
assert.equal((await pool.query("SELECT count(*)::int AS count FROM mcp_read_leases WHERE connection_id=$1", [access.connection.id])).rows[0].count, 0)
} finally { release(); await following.catch(() => undefined) }
} finally { pool.query = original; await follower.close() }
}
const stdio = new Client({ name: "stdio-integration", version: "1.0.0" })
try {
await stdio.connect(new StdioClientTransport({ command: process.execPath, args: ["--import", "tsx", fileURLToPath(new URL("../../scripts/mcp-stdio.ts", import.meta.url))], env: { MCP_URL: endpoint, MCP_TOKEN: rotated.token }, stderr: "pipe" }))
assert.ok((await stdio.listTools()).tools.some(tool => tool.name === "mm_ip_settings_list"))
assert.ok(!(await stdio.callTool({ name: "mm_ip_settings_list", arguments: { serverId: 1 } })).isError)
console.log("✓ Official SDK stdio bridge initializes and calls the same authorized HTTP tools")
} finally { await stdio.close() }
const clientId = randomUUID(), redirectUri = "http://localhost:45678/callback", verifier = "v".repeat(64)
await pool.query("INSERT INTO mcp_oauth_clients(id,name,redirect_uris) VALUES($1,'integration',$2::jsonb)", [clientId, JSON.stringify([redirectUri])])
const parameters = { response_type: "code", client_id: clientId, redirect_uri: redirectUri, resource: endpoint, scope: "mcp", state: "test-state", code_challenge_method: "S256", code_challenge: createHash("sha256").update(verifier).digest("base64url") }
const authorization = await app.inject({ url: "/oauth/authorize?" + new URLSearchParams(parameters) })
assert.equal(authorization.statusCode, 302)
const requestId = new URL(authorization.headers.location!).searchParams.get("oauthRequest")!
const { SignJWT } = await import("jose"), { env } = await import("../../config.js")
const jwt = await new SignJWT({ sub: actor.id, apps: ["mm"], permissions: actor.permissions }).setProtectedHeader({ alg: "HS256" }).setIssuer(env.authIssuer).setExpirationTime(Math.floor(fixtureAuthExpiresAt / 1000)).sign(new TextEncoder().encode(env.jwtSecret))
await (await import("../../test/mcp-host-files.js")).verifyMcpHostFiles(actor,app)
const readinessAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Actual readiness handshake", scope: { ...input.scope, operationIds: ["servers.list"] } }), actor)
const readinessHeaders = { authorization: "Bearer " + jwt }
const ready = await app.inject({ method: "POST", url: `/api/mcp/connections/${readinessAccess.connection.id}/check`, headers: readinessHeaders, payload: {} })
assert.equal(ready.statusCode, 200, ready.body)
assert.equal(ready.json().ok, true, ready.body); assert.equal(ready.json().checks.protocolHandshake, true)
assert.equal(ready.json().protocolProbe.status, "passed"); assert.equal(ready.json().protocolProbe.clientCredentialsVerified, false)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_credentials WHERE connection_id=$1 AND client_id='mcp-readiness-probe'", [readinessAccess.connection.id])).rows[0].n, 0)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_grants WHERE connection_id=$1", [readinessAccess.connection.id])).rows[0].n, 0)
const duplicateReady = await app.inject({ method: "POST", url: `/api/mcp/connections/${readinessAccess.connection.id}/check`, headers: readinessHeaders, payload: {} })
assert.equal(duplicateReady.statusCode, 429)
await setConnectionStatus(readinessAccess.connection.id, "paused", actor)
const pausedReady = await app.inject({ method: "POST", url: `/api/mcp/connections/${readinessAccess.connection.id}/check`, headers: readinessHeaders, payload: {} })
assert.equal(pausedReady.statusCode, 200); assert.equal(pausedReady.json().protocolProbe.status, "skipped")
const emptyGrantAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Readiness has no operation authority" }), actor)
const { withMcpProbeCredential } = await import("./readiness.js")
let endedProbeToken = ""
await assert.rejects(withMcpProbeCredential(emptyGrantAccess.connection.id, actor, async token => {
endedProbeToken = token
const probePrincipal = await authenticateMcpToken(token)
const { effectiveMcpConnection } = await import("./store.js")
assert.deepEqual((await effectiveMcpConnection(probePrincipal)).policy.scope.operationIds, [])
await assert.rejects(invokeMcpTool(probePrincipal, "mm_ip_settings_list", { serverId: 1 }))
throw new Error("Simulated interrupted handshake")
}))
await assert.rejects(authenticateMcpToken(endedProbeToken))
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_grants WHERE connection_id=$1", [emptyGrantAccess.connection.id])).rows[0].n, 0)
const readinessAudit = (await pool.query("SELECT payload FROM mcp_audit WHERE connection_id=$1", [emptyGrantAccess.connection.id])).rows
assert.ok(!JSON.stringify(readinessAudit).includes(endedProbeToken))
console.log("✓ Actual readiness initialize/tools-list over public HTTP: temporary empty grant, no tool authority, cleanup on success/error, cooldown and paused precheck skip")
const deviceConnection = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Web interfaces", scope: { ...input.scope, operationIds: ["ros.bridge.list", "ros.bridge.create"] } }), actor)
const deviceHeaders = { authorization: "Bearer " + jwt }
const deviceCatalog = await app.inject({ url: "/api/mcp/devices/catalog?connectionId=" + deviceConnection.connection.id, headers: deviceHeaders })
assert.equal(deviceCatalog.statusCode, 200, deviceCatalog.body)
assert.deepEqual(deviceCatalog.json().servers.map((server: { id: number }) => server.id), [1])
assert.equal(deviceCatalog.json().resources.find((resource: { id: string }) => resource.id === "bridge").create, true)
assert.equal((await app.inject({ url: `/api/mcp/devices/2/bridge?connectionId=${deviceConnection.connection.id}`, headers: deviceHeaders })).statusCode, 403)
const devicePlan = await app.inject({ method: "POST", url: "/api/mcp/devices/1/bridge/plan", headers: deviceHeaders, payload: { connectionId: deviceConnection.connection.id, action: "create", fields: { name: "own-web-test", disabled: true } } })
assert.equal(devicePlan.statusCode, 200, devicePlan.body); assert.equal(devicePlan.json().state, "awaiting-approval")
const invalidDevice = await app.inject({ method: "POST", url: "/api/mcp/devices/1/bridge/plan", headers: deviceHeaders, payload: { connectionId: deviceConnection.connection.id, action: "create", fields: { name: "own-web-test", script: "forbidden" } } })
assert.equal(invalidDevice.statusCode, 400, invalidDevice.body)
console.log("✓ Web interface catalog enforces server scope; typed creation requires approval and rejects arbitrary fields")
const consent = await app.inject({ method: "POST", url: "/api/mcp/oauth/consent", headers: { authorization: "Bearer " + jwt }, payload: { requestId, connectionId: issued.connection.id, approve: true } })
assert.equal(consent.statusCode, 200, consent.body)
const redirect = new URL(consent.json().redirectUrl)
assert.equal(redirect.searchParams.get("state"), "test-state")
const codePayload = { grant_type: "authorization_code", client_id: clientId, redirect_uri: redirectUri, resource: endpoint, code: redirect.searchParams.get("code")!, code_verifier: verifier }
const tokenRequest = (payload: Record<string, string>) => app!.inject({ method: "POST", url: "/oauth/token", headers: { "content-type": "application/x-www-form-urlencoded" }, payload: new URLSearchParams(payload).toString() })
assert.equal((await tokenRequest({ ...codePayload, code_verifier: "x".repeat(64) })).statusCode, 400)
assert.equal((await tokenRequest({ ...codePayload, resource: "https://wrong.invalid/mcp" })).statusCode, 400)
const exchanged = await tokenRequest(codePayload)
assert.equal(exchanged.statusCode, 200, exchanged.body)
await authenticateMcpToken(exchanged.json().access_token)
assert.equal((await tokenRequest(codePayload)).statusCode, 400)
const refreshPayload = { grant_type: "refresh_token", client_id: clientId, resource: endpoint, refresh_token: exchanged.json().refresh_token }
const refreshed = await tokenRequest(refreshPayload)
assert.equal(refreshed.statusCode, 200)
assert.equal((await tokenRequest(refreshPayload)).statusCode, 400)
await assert.rejects(authenticateMcpToken(refreshed.json().access_token))
console.log("✓ OAuth consent, PKCE, resource binding, one-use code, refresh rotation and reuse-family revocation")
const { detectMcpDrift } = await import("./workers.js")
await detectMcpDrift()
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_drift WHERE operation_id=$1", [operation.id])).rows[0].n, 1)
await detectMcpDrift()
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_drift WHERE operation_id=$1", [operation.id])).rows[0].n, 1)
console.log("✓ Drift detection records a single open incident without replaying writes")
const currentPrincipal = await authenticateMcpToken(rotated.token)
await assert.rejects(invokeMcpTool(currentPrincipal, "mm_operation_recovery_plan", { operationId: operation.id }), error => error instanceof Error && "code" in error && error.code === "STATE_CONFLICT")
const beforeRecovery = settings["rp-filter"]
const forward = await invokeMcpTool(currentPrincipal, "mm_ip_settings_update_plan", { serverId: 1, fields: { "rp-filter": "loose" } }) as { planId: string }
await approvePlan(forward.planId, actor, true)
const forwardOperation = await applyPlan(currentPrincipal, forward.planId, "recovery-forward")
const waitOperation = async (id: string) => {
// This observes asynchronous execution; it does not set an operation TTL.
// Genuine settings/drain execution can exceed the former 100 x 30ms loop.
const observationDeadline = performance.now() + 30000
while (performance.now() < observationDeadline) {
const value = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [id])).rows[0].state
if (!["pending", "running"].includes(value)) return value
await delay(30)
}
return "timeout"
}
assert.equal(await waitOperation(forwardOperation.id), "applied")
await pool.query("INSERT INTO servers(id,name,host,port,use_ssl,password) VALUES(107,'native-reconciliation','127.0.0.1',$1,false,'fixture')", [port])
const reconcileAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Native reconciliation fences", scope: { serverIds: [107], operationIds: ["ros.ip_settings.update", "operations.reconcile"], allowGlobal: false } }), actor)
const reconcilePrincipal = await authenticateMcpToken(reconcileAccess.token)
try {
const reconcilePlan = await invokeMcpTool(reconcilePrincipal, "mm_ip_settings_update_plan", { serverId: 107, fields: { "rp-filter": "loose" } }) as { planId: string }
await approvePlan(reconcilePlan.planId, actor, true)
const reconcileOperation = await applyPlan(reconcilePrincipal, reconcilePlan.planId, randomUUID())
assert.equal(await waitOperation(reconcileOperation.id), "applied")
const reconcileWrites = writes
const nativeReconcile = await invokeMcpTool(reconcilePrincipal, "mm_operation_reconcile", { operationId: reconcileOperation.id }) as { state: string; automaticRetry: boolean; results: { matchesVerifiedCheckpoint: boolean; comparisonScope: string; sourceUnchangedDuringRead: boolean; originalSourceIdentityVerified: boolean }[] }
assert.equal(nativeReconcile.state, "applied"); assert.equal(nativeReconcile.automaticRetry, false)
assert.equal(nativeReconcile.results[0].matchesVerifiedCheckpoint, true)
assert.equal(nativeReconcile.results[0].comparisonScope, "visible-resource-configuration")
assert.equal(nativeReconcile.results[0].sourceUnchangedDuringRead, true)
assert.equal(nativeReconcile.results[0].originalSourceIdentityVerified, false)
const reconcileAbort = new AbortController(), beforeReconcileCancel = reconcileSettingsReads
reconcileReadHook = async () => reconcileAbort.abort()
await assert.rejects(invokeMcpTool(reconcilePrincipal, "mm_operation_reconcile", { operationId: reconcileOperation.id }, reconcileAbort.signal), (error: { code?: string }) => error.code === "READ_CANCELLED")
assert.equal(reconcileSettingsReads, beforeReconcileCancel + 1)
reconcileReadHook = () => setConnectionStatus(reconcileAccess.connection.id, "paused", actor)
await assert.rejects(invokeMcpTool(reconcilePrincipal, "mm_operation_reconcile", { operationId: reconcileOperation.id }))
await setConnectionStatus(reconcileAccess.connection.id, "active", actor)
reconcileReadHook = async () => {
await pool.query("UPDATE servers SET verify_ssl=NOT verify_ssl WHERE id=107")
await pool.query("UPDATE servers SET verify_ssl=NOT verify_ssl WHERE id=107")
}
await assert.rejects(invokeMcpTool(reconcilePrincipal, "mm_operation_reconcile", { operationId: reconcileOperation.id }), (error: { code?: string }) => error.code === "STATE_CONFLICT")
assert.equal(writes, reconcileWrites)
assert.equal((await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [reconcileOperation.id])).rows[0].state, "applied")
console.log("✓ Native reconciliation fences cancellation, paused access and endpoint ABA during HTTP without replay")
} finally {
reconcileReadHook = undefined
await setConnectionStatus(reconcileAccess.connection.id, "paused", actor)
await pool.query("DELETE FROM servers WHERE id=107")
}
const recovery = await invokeMcpTool(currentPrincipal, "mm_operation_recovery_plan", { operationId: forwardOperation.id }) as { planId: string; state: string }
assert.equal(recovery.state, "awaiting-approval")
await approvePlan(recovery.planId, actor, true)
const restored = await applyPlan(currentPrincipal, recovery.planId, "recovery-once")
assert.equal(await waitOperation(restored.id), "applied"); assert.equal(settings["rp-filter"], beforeRecovery)
assert.equal((await applyPlan(currentPrincipal, recovery.planId, "recovery-once")).id, restored.id)
console.log("✓ Encrypted checkpoints support approved inverse plans, reject external drift and preserve idempotency")
const usersAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Users writer", permissions: ["mm:users:write"], scope: { serverIds: [1], operationIds: ["users.create", "users.update", "users.permissions.update"], allowGlobal: true } }), actor)
const usersPrincipal = await authenticateMcpToken(usersAccess.token)
const userData = { name: " MCP catalog fixture ", login: "mcp-" + randomUUID(), email: "[email protected]" }
await assert.rejects(invokeMcpTool(usersPrincipal, "mm_users_create_plan", { user: { ...userData, role: "admin" } }))
const userPlan = await invokeMcpTool(usersPrincipal, "mm_users_create_plan", { user: userData }) as { planId: string }
await approvePlan(userPlan.planId, actor, true)
assert.equal(await waitOperation((await applyPlan(usersPrincipal, userPlan.planId, "create-catalog-user")).id), "applied")
const catalogUser = (await pool.query("SELECT id,role FROM app_users WHERE login=$1", [userData.login])).rows[0]
assert.equal(catalogUser.role, "viewer")
await assert.rejects(invokeMcpTool(usersPrincipal, "mm_users_permissions_update_plan", { id: catalogUser.id, permissions: { role: "admin" } }))
const rolesAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Catalog roles", permissions: ["mm:settings:admin"], scope: { serverIds: [1], operationIds: ["users.permissions.update"], allowGlobal: true } }), actor)
const rolesPrincipal = await authenticateMcpToken(rolesAccess.token)
await assert.rejects(invokeMcpTool(rolesPrincipal, "mm_users_permissions_update_plan", { id: catalogUser.id, permissions: { servers: [{ serverId: "2", level: "read" }] } }))
const rolesPlan = await invokeMcpTool(rolesPrincipal, "mm_users_permissions_update_plan", { id: catalogUser.id, permissions: { role: "operator", servers: [{ serverId: "1", level: "read" }] } }) as { planId: string }
await approvePlan(rolesPlan.planId, actor, true)
assert.equal(await waitOperation((await applyPlan(rolesPrincipal, rolesPlan.planId, "catalog-role-only")).id), "applied")
assert.equal((await pool.query("SELECT role FROM app_users WHERE id=$1", [catalogUser.id])).rows[0].role, "operator")
const nameOnly = await invokeMcpTool(usersPrincipal, "mm_users_update_plan", { id: catalogUser.id, user: { name: "Renamed only" } }) as { planId: string }
await approvePlan(nameOnly.planId, actor, true)
assert.equal(await waitOperation((await applyPlan(usersPrincipal, nameOnly.planId, "name-without-privileges")).id), "applied")
const preservedUser = (await pool.query("SELECT role,servers_json FROM app_users WHERE id=$1", [catalogUser.id])).rows[0]
assert.equal(preservedUser.role, "operator")
assert.deepEqual(typeof preservedUser.servers_json === "string" ? JSON.parse(preservedUser.servers_json) : preservedUser.servers_json, [{ serverId: "1", level: "read" }])
for (const type of ["bridge", "vlan", "vxlan", "ipsec"]) await pool.query("INSERT INTO user_interface_bindings(id,user_id,server_id,interface_name,interface_type) VALUES($1,$2,1,$3,$4)", [randomUUID(), catalogUser.id, "fixture-" + type, type])
assert.equal((await pool.query("SELECT count(*)::int AS n FROM user_interface_bindings WHERE user_id=$1", [catalogUser.id])).rows[0].n, 4)
console.log("✓ Catalog roles require a separate admin action; scoped permissions, normalized read-back and real interface types work")
await verifyMcpGrantExpiryBounds(app, actor, deviceHeaders)
const grantOperations = ["users.list", "users.get", "servers.list", "ros.ip_settings.update", "changes.read", "changes.cancel", "operations.read"]
const grantAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Temporary scope acceptance", permissions: ["mm:users:read", "mm:network:write", "mm:servers:read"], scope: { allowGlobal: true, serverIds: [1, 2], operationIds: [...grantOperations, "interfaces.update"] } }), actor)
const baseGrantPrincipal = await authenticateMcpToken(grantAccess.token)
const outsidePlan = await invokeMcpTool(baseGrantPrincipal, "mm_ip_settings_update_plan", { serverId: 2, fields: { "rp-filter": settings["rp-filter"] } }) as { planId: string }
await approvePlan(outsidePlan.planId, actor, true)
const outsideOperation = await applyPlan(baseGrantPrincipal, outsidePlan.planId, "outside-temporary-grant")
assert.equal(await waitOperation(outsideOperation.id), "applied")
const cancelOutside = await invokeMcpTool(baseGrantPrincipal, "mm_ip_settings_update_plan", { serverId: 2, fields: { "rp-filter": settings["rp-filter"] } }) as { planId: string }
const issuedGrant = await app.inject({ method: "POST", url: `/api/mcp/connections/${grantAccess.connection.id}/grants`, headers: deviceHeaders, payload: { id: randomUUID(), startsAt: new Date(Date.now() - 1000).toISOString(), expiresAt: new Date(Date.now() + 600000).toISOString(), scope: { allowGlobal: true, serverIds: [1], operationIds: grantOperations } } })
assert.equal(issuedGrant.statusCode, 200, issuedGrant.body)
const grantPrincipal = await authenticateMcpToken(issuedGrant.json().token)
const hiddenBinding = randomUUID()
await pool.query("INSERT INTO user_interface_bindings(id,user_id,server_id,interface_name,interface_type) VALUES($1,$2,2,'hidden-binding','ether')", [hiddenBinding, catalogUser.id])
const grantUser = await invokeMcpTool(grantPrincipal, "mm_users_get", { id: catalogUser.id }) as { user: { incomplete: boolean; bindings: { serverId: number }[] } }
assert.equal(grantUser.user.incomplete, true)
assert.ok(grantUser.user.bindings.every(binding => binding.serverId === 1))
const grantList = await invokeMcpTool(grantPrincipal, "mm_users_list", {}) as { items: { bindings: { serverId: number }[] }[] }
assert.ok(grantList.items.every(user => user.bindings.every(binding => binding.serverId === 1)))
assert.deepEqual((await invokeMcpTool(grantPrincipal, "mm_servers_list", {}) as { items: { id: number }[] }).items.map(item => item.id), [1])
for (const [tool, body] of [["mm_change_get", { planId: outsidePlan.planId }], ["mm_change_cancel", { planId: cancelOutside.planId }], ["mm_operation_get", { operationId: outsideOperation.id }]] as const) await assert.rejects(invokeMcpTool(grantPrincipal, tool, body))
assert.equal((await pool.query("SELECT state FROM mcp_plans WHERE id=$1", [cancelOutside.planId])).rows[0].state, "awaiting-approval")
const insidePlan = await invokeMcpTool(grantPrincipal, "mm_ip_settings_update_plan", { serverId: 1, fields: { "rp-filter": settings["rp-filter"] } }) as { planId: string }
assert.equal((await invokeMcpTool(grantPrincipal, "mm_change_get", { planId: insidePlan.planId }) as { id: string }).id, insidePlan.planId)
const grantClient = new Client({ name: "temporary-grant", version: "1.0.0" })
try {
await grantClient.connect(new StreamableHTTPClientTransport(new URL(endpoint), { requestInit: { headers: { Authorization: "Bearer " + issuedGrant.json().token } } }))
const tools = (await grantClient.listTools()).tools.map(tool => tool.name)
assert.ok(tools.includes("mm_users_get")); assert.ok(!tools.includes("mm_interfaces_update_plan"))
} finally { await grantClient.close() }
await pool.query("DELETE FROM user_interface_bindings WHERE id=$1", [hiddenBinding])
console.log("✓ Temporary grants narrow catalogs and SDK discovery; hidden user bindings and out-of-scope plan/operation details or cancellation are denied")
const healthAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Post-write health", scope: { ...input.scope, operationIds: ["ros.ip_settings.update"] } }), actor)
const healthPrincipal = await authenticateMcpToken(healthAccess.token)
const healthPlan = async (resource: string, id: string, field: string, identity?: Record<string, string>) => {
const plan = await invokeMcpTool(healthPrincipal, "mm_ip_settings_update_plan", { serverId: 1, fields: { "rp-filter": settings["rp-filter"] } }) as { planId: string }
const evidence = JSON.parse(await decryptSecret((await pool.query("SELECT evidence FROM mcp_plans WHERE id=$1", [plan.planId])).rows[0].evidence.sealed))
evidence.healthChecks = [{ serverId: 1, resource, id, field, identity }]
await pool.query("UPDATE mcp_plans SET evidence=$2::jsonb WHERE id=$1", [plan.planId, JSON.stringify({ sealed: await encryptSecret(JSON.stringify(evidence)) })])
await approvePlan(plan.planId, actor, true)
return plan
}
try {
for (const [resource, id, field] of [["ospf_neighbor", "*neighbor", "state"], ["ipv4_route", "*healthroute", "active"], ["bfd_session", "*bfd", "bfd-up"]]) {
healthState = true; failHealthAfterWrite = true
const plan = await healthPlan(resource, id, field), before: number = writes
const operation = await applyPlan(healthPrincipal, plan.planId, randomUUID())
assert.equal(await waitOperation(operation.id), "partial"); assert.equal(writes, before + 1)
assert.equal((await pool.query("SELECT error_code FROM mcp_operations WHERE id=$1", [operation.id])).rows[0].error_code, "VERIFICATION_FAILED")
await applyPlan(healthPrincipal, plan.planId, "another-key"); await delay(30); assert.equal(writes, before + 1)
}
failHealthAfterWrite = false; healthState = false
const preflight = await healthPlan("ospf_neighbor", "*neighbor", "state"), before = writes
assert.equal(await waitOperation((await applyPlan(healthPrincipal, preflight.planId, randomUUID())).id), "rejected"); assert.equal(writes, before)
healthState = true
const reusedBfd = await healthPlan("bfd_session", "*bfd", "bfd-up", { "remote-address": healthBfdRemote })
healthBfdRemote = "192.0.2.99%foreign"
assert.equal(await waitOperation((await applyPlan(healthPrincipal, reusedBfd.planId, randomUUID())).id), "rejected"); assert.equal(writes, before)
healthBfdRemote = "192.0.2.2%fixture-ospf"
healthState = true; loseHealthResponse = true
const unavailable = await healthPlan("ospf_neighbor", "*neighbor", "state")
assert.equal(await waitOperation((await applyPlan(healthPrincipal, unavailable.planId, randomUUID())).id), "unknown"); assert.equal(writes, before + 1)
console.log("✓ Post-write routing health: lost Full/active is partial, unavailable evidence is unknown, failed preflight writes nothing, no replay")
} finally { healthState = true; failHealthAfterWrite = false; healthUnavailable = false; loseHealthResponse = false; healthBfdRemote = "192.0.2.2%fixture-ospf" }
const limited = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Budget", limits: { callsPerMinute: 2, concurrentReads: 100 } }), actor)
const limitedPrincipal = await authenticateMcpToken(limited.token)
const concurrent = await Promise.allSettled(Array.from({ length: 12 }, () => invokeMcpTool(limitedPrincipal, "mm_ip_settings_list", { serverId: 1 })))
assert.equal(concurrent.filter(value => value.status === "fulfilled").length, 2)
console.log("✓ Concurrent calls cannot overspend the atomic call budget")
const { reserveProtocolEnvelope, recordUnauthorizedProtocol } = await import("./protocol-limits.js")
const envelopes = await Promise.all(Array.from({ length: 16 }, () => reserveProtocolEnvelope(limitedPrincipal)))
assert.equal(envelopes.filter(value => value.allowed).length, 10)
const rejectedBefore = (await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE tool='protocol:unauthorized'")).rows[0].n
for (let attempt = 0; attempt < 8; attempt++) await recordUnauthorizedProtocol("192.0.2.99", "UNAUTHORIZED")
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_requests WHERE tool='protocol:unauthorized'")).rows[0].n, rejectedBefore + 1)
assert.equal((await pool.query("SELECT max(attempts)::int AS n FROM mcp_unauthorized_buckets WHERE reason='UNAUTHORIZED'")).rows[0].n, 8)
console.log("✓ Protocol metadata is atomically bounded; unauthorized repeats preserve counters without storing tokens")
const aliasConnection = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Interface alias acceptance", scope: { ...input.scope, operationIds: ["interfaces.update", "firewall.update"] } }), actor)
const aliasPrincipal = await authenticateMcpToken(aliasConnection.token)
await assert.rejects(invokeMcpTool(aliasPrincipal, "mm_interfaces_update_plan", { serverId: 1, resource: "ip_settings", id: "*fixture", fields: { comment: "out-of-allowlist" } }))
await assert.rejects(invokeMcpTool(aliasPrincipal, "mm_interfaces_update_plan", { serverId: 1, resource: "bridge", id: "*fixture", fields: { script: "not-allowed" } }))
const aliasPlan = await invokeMcpTool(aliasPrincipal, "mm_interfaces_update_plan", { serverId: 1, resource: "bridge", id: "*fixture", fields: { comment: "reviewed-alias" } }) as { planId: string }
await approvePlan(aliasPlan.planId, actor, true)
assert.equal(await waitOperation((await applyPlan(aliasPrincipal, aliasPlan.planId, "interface-alias")).id), "applied")
assert.equal(bridge.comment, "reviewed-alias")
console.log("✓ Named interface/firewall tools reuse typed native plans; resources and fields cannot escape their allowlists")
const telemetryActor = { ...actor, permissions: [...actor.permissions, "mm:uptime:admin", "mm:traffic:admin"] }
const telemetryOps = ["traffic.settings.update", "uptime.settings.update", "netflow.settings.update", "uptime.ping.probes.read", "uptime.ping.probes.replace", "uptime.speed.probes.read", "uptime.speed.probes.replace", "servers.api-ping.settings.update", "internet-path.settings.update"]
// NetFlow reserves four writes, seven successful updates reserve one each,
// and the stale Internet path plan reserves one before execution rejects it.
// Keep the production default budget unchanged; this fixture needs 12.
const telemetry = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Telemetry acceptance", limits: { ...input.limits, mutationsPerHour: 12 }, permissions: ["mm:uptime:write", "mm:traffic:write", "mm:servers:write", "mm:network:write"], scope: { allowGlobal: true, serverIds: [1, 2], operationIds: telemetryOps } }), telemetryActor)
const telemetryPrincipal = await authenticateMcpToken(telemetry.token)
const applyTelemetry = async (tool: string, value: Record<string, unknown>, afterPrepare?: () => Promise<unknown>) => {
const plan = await invokeMcpTool(telemetryPrincipal, tool, value) as { planId: string }
await afterPrepare?.()
await approvePlan(plan.planId, telemetryActor, true)
const operation = await applyPlan(telemetryPrincipal, plan.planId, randomUUID())
assert.equal(await waitOperation(operation.id), "applied", JSON.stringify((await pool.query("SELECT error_code,result FROM mcp_operations WHERE id=$1", [operation.id])).rows[0]))
return operation
}
await applyTelemetry("mm_traffic_settings_update_plan", { settings: { enabled: false, intervalSec: 37 } }, async () => {
await pool.query("UPDATE traffic_settings SET last_collected_at=now(),last_duration_ms=123,last_error='synthetic collector status',updated_at=now() WHERE id=1")
})
assert.deepEqual((await pool.query("SELECT enabled,interval_sec FROM traffic_settings WHERE id=1")).rows[0], { enabled: false, interval_sec: 37 })
await applyTelemetry("mm_uptime_settings_update_plan", { settings: { resourcesEnabled: false, pingEnabled: false, speedEnabled: false, intervalSec: 317 } }, async () => {
await pool.query("UPDATE uptime_settings SET last_collected_at=now(),last_duration_ms=123,last_error='synthetic collector status',updated_at=now() WHERE id=1")
})
assert.deepEqual((await pool.query("SELECT resources_enabled,ping_enabled,speed_enabled,interval_sec FROM uptime_settings WHERE id=1")).rows[0], { resources_enabled: false, ping_enabled: false, speed_enabled: false, interval_sec: 317 })
await applyTelemetry("mm_netflow_settings_update_plan", { settings: { enabled: false, topN: 23, mapServiceMinSharePct: 7 } })
await applyTelemetry("mm_servers_api_ping_settings_update_plan", { settings: { enabled: false, intervalSec: 131 } }, async () => {
await pool.query("UPDATE servers_api_ping_settings SET last_collected_at=now(),last_duration_ms=123,last_error='synthetic collector status',updated_at=now() WHERE id=1")
})
assert.deepEqual((await pool.query("SELECT enabled,interval_sec FROM servers_api_ping_settings WHERE id=1")).rows[0], { enabled: false, interval_sec: 131 })
console.log("✓ Traffic, uptime and API Ping settings tolerate actual collector metadata changes between prepare/apply and persist requested configuration with ordinary scheduler activity")
const stalePathPlan = await invokeMcpTool(telemetryPrincipal, "mm_internet_path_settings_update_plan", { settings: { enabled: false, intervalSec: 368 } }) as { planId: string }
await approvePlan(stalePathPlan.planId, telemetryActor, true)
await pool.query("UPDATE internet_path_settings SET interval_sec=interval_sec+1 WHERE id=1")
const changedPathConfig = (await pool.query("SELECT enabled,interval_sec,retention_days FROM internet_path_settings WHERE id=1")).rows[0]
const stalePathOperation = await applyPlan(telemetryPrincipal, stalePathPlan.planId, randomUUID())
assert.equal(await waitOperation(stalePathOperation.id), "rejected")
assert.equal((await pool.query("SELECT error_code FROM mcp_operations WHERE id=$1", [stalePathOperation.id])).rows[0].error_code, "STATE_CONFLICT")
assert.deepEqual((await pool.query("SELECT enabled,interval_sec,retention_days FROM internet_path_settings WHERE id=1")).rows[0], changedPathConfig)
await applyTelemetry("mm_internet_path_settings_update_plan", { settings: { enabled: false, intervalSec: 367, retentionDays: 9 } }, async () => {
await pool.query("UPDATE internet_path_settings SET last_collected_at=now(),last_duration_ms=123,last_error='synthetic collector status',updated_at=now() WHERE id=1")
})
console.log("✓ Internet path plans tolerate collector status updates and reject changed configuration without writes")
const pingProbe = { id: "mcp-ping-fixture", srcServerId: 1, srcInterface: "ether1", name: "MCP disabled Ping", target: "192.0.2.1", enabled: false, intervalSec: 1 }
await applyTelemetry("mm_ping_probes_replace_plan", { probes: [pingProbe] })
assert.equal((await pool.query("SELECT interval_sec FROM uptime_probes WHERE id=$1", [pingProbe.id])).rows[0].interval_sec, 5)
await assert.rejects(invokeMcpTool(telemetryPrincipal, "mm_ping_probes_replace_plan", { probes: [{ ...pingProbe, srcServerId: 999999 }] }))
const probeProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,reason,created_by) VALUES($1,$2::jsonb,'fixture',$3)", [probeProtection, JSON.stringify({ kind: "ping-probe", id: pingProbe.id, protection: "deny" }), actor.id])
const { replaceProbes } = await import("../../services/uptime-collector.js")
await assert.rejects(replaceProbes([]))
await assert.rejects(invokeMcpTool(telemetryPrincipal, "mm_ping_probes_replace_plan", { probes: [] }))
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [probeProtection])
const speedProbe = { id: "mcp-speed-fixture", srcServerId: 1, dstServerId: 2, srcInterface: "ether1", dstInterface: "ether1", protocol: "tcp", direction: "both", durationSec: 7, enabled: false }
await applyTelemetry("mm_speed_probes_replace_plan", { probes: [speedProbe] })
await pool.query("UPDATE uptime_speed_probes SET last_tx_avg_mbps=100,last_rx_avg_mbps=200,last_run_at=now(),last_status='done' WHERE id=$1", [speedProbe.id])
await applyTelemetry("mm_speed_probes_replace_plan", { probes: [{ ...speedProbe, durationSec: 8 }] })
const reset = (await pool.query("SELECT last_tx_avg_mbps,last_rx_avg_mbps,last_run_at FROM uptime_speed_probes WHERE id=$1", [speedProbe.id])).rows[0]
assert.deepEqual(reset, { last_tx_avg_mbps: null, last_rx_avg_mbps: null, last_run_at: null })
await assert.rejects(invokeMcpTool(telemetryPrincipal, "mm_speed_probes_replace_plan", { probes: [{ ...speedProbe, durationSec: 31 }] }))
const limitedTelemetry = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Limited telemetry", permissions: ["mm:uptime:read"], scope: { allowGlobal: true, serverIds: [1], operationIds: ["uptime.ping.probes.read"] } }), telemetryActor)
await assert.rejects(invokeMcpTool(await authenticateMcpToken(limitedTelemetry.token), "mm_ping_probes_get", {}))
console.log("✓ Telemetry settings have actual read-back; probe catalogs enforce full scope, protected deletions, bounded bandwidth duration and measurement reset")
const probeAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Probe service adapters", permissions: ["mm:uptime:read", "mm:uptime:write"], scope: { allowGlobal: false, serverIds: [1, 2], operationIds: ["uptime.speed.runs.read", "uptime.speed.interfaces.read", "uptime.ping.interfaces.read", "uptime.ping.visibility.update"] } }), telemetryActor)
const probePrincipal = await authenticateMcpToken(probeAccess.token)
const probeLimited = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Limited probe readers", mode: "observer", permissions: ["mm:uptime:read"], scope: { allowGlobal: false, serverIds: [1], operationIds: ["uptime.speed.runs.read", "uptime.speed.interfaces.read", "uptime.ping.interfaces.read"] } }), telemetryActor)
const probeLimitedPrincipal = await authenticateMcpToken(probeLimited.token)
await pool.query("INSERT INTO servers(id,name,host,enabled) VALUES(3,'Foreign history fixture','192.0.2.253',false)")
await pool.query("INSERT INTO uptime_speed_test_runs(id,src_server_id,dst_server_id,rx_avg_mbps,ping_loss_pct,created_at) VALUES('speed-visible-z',1,2,0,0,'2026-10-10'),('speed-visible-a',2,1,0,0,'2026-10-10')")
await pool.query("INSERT INTO uptime_speed_test_runs(id,src_server_id,dst_server_id,tx_avg_mbps,created_at) VALUES('speed-foreign-src',3,1,-1,'2026-10-17'),('speed-foreign-dst',1,3,-1,'2026-10-17')")
await pool.query("INSERT INTO uptime_probes(id,src_server_id,name,target,enabled) VALUES('visibility-own',1,'Visibility fixture','192.0.2.1',false),('visibility-foreign',3,'Foreign visibility fixture','192.0.2.3',false)")
probeInterfaceFixtures = true; probeNativeCalls = 0
try {
type Runs = { runs: { id: string; txAvgMbps: number | null; rxAvgMbps: number | null; afterBtPing: { lossPct: number | null } }[]; nextOffset: number | null }
const history = await invokeMcpTool(probePrincipal, "mm_speed_test_runs_get", { limit: 1 }) as Runs
assert.equal(history.runs[0].id, "speed-visible-z"); assert.equal(history.runs[0].txAvgMbps, null); assert.equal(history.runs[0].rxAvgMbps, 0); assert.equal(history.runs[0].afterBtPing.lossPct, 0)
assert.equal(history.nextOffset, 1)
const nextHistory = await invokeMcpTool(probePrincipal, "mm_speed_test_runs_get", { limit: 1, offset: 1 }) as Runs
assert.equal(nextHistory.runs[0].id, "speed-visible-a")
assert.deepEqual((await invokeMcpTool(probeLimitedPrincipal, "mm_speed_test_runs_get", {}) as Runs).runs, [])
const pingIfaces = await invokeMcpTool(probeLimitedPrincipal, "mm_ping_source_interfaces_get", { serverId: 1, limit: 1 }) as { interfaces: { name: string }[]; unknownInterfaces: { name: string }[]; total: number; incomplete: boolean; nextOffset: number }
assert.equal(pingIfaces.interfaces[0].name, "ether1"); assert.equal(pingIfaces.total, 2); assert.equal(pingIfaces.nextOffset, 1)
assert.equal(pingIfaces.unknownInterfaces[0].name, "unknown-probe"); assert.equal(pingIfaces.incomplete, true)
const speedIfaces = await invokeMcpTool(probeLimitedPrincipal, "mm_speed_test_interfaces_get", { serverId: 1 }) as { interfaces: { addresses: string[]; addressStateVerified: boolean }[] }
assert.deepEqual(speedIfaces.interfaces[0].addresses, ["192.0.2.10"]); assert.equal(speedIfaces.interfaces[0].addressStateVerified, true)
assert.ok(!JSON.stringify(speedIfaces).includes("never-return-probe-key"))
const nativeBefore = probeNativeCalls
await assert.rejects(invokeMcpTool(probeLimitedPrincipal, "mm_speed_test_interfaces_get", { serverId: 2 })); assert.equal(probeNativeCalls, nativeBefore)
await pool.query("UPDATE servers SET enabled=false WHERE id=1")
await assert.rejects(invokeMcpTool(probeLimitedPrincipal, "mm_ping_source_interfaces_get", { serverId: 1 })); assert.equal(probeNativeCalls, nativeBefore)
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
probeReadFailure = true
await assert.rejects(invokeMcpTool(probeLimitedPrincipal, "mm_speed_test_interfaces_get", { serverId: 1 }))
probeReadFailure = false
const visibilityArgs = { serverId: 1, probeId: "visibility-own", showOnDashboard: false }
await assert.rejects(invokeMcpTool(probePrincipal, "mm_ping_probe_visibility_plan", { ...visibilityArgs, probeId: "visibility-foreign" }))
const protectedVisibility = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,created_by) VALUES($1,$2::jsonb,$3)", [protectedVisibility, JSON.stringify({ kind: "ping-probe", id: "visibility-own", protection: "deny" }), actor.id])
try {
await assert.rejects(invokeMcpTool(probePrincipal, "mm_ping_probe_visibility_plan", visibilityArgs))
await assert.rejects((await import("../../services/uptime-collector.js")).updateProbeShowOnDashboard("visibility-own", false))
} finally { await pool.query("DELETE FROM mcp_protections WHERE id=$1", [protectedVisibility]) }
const staleVisibility = await invokeMcpTool(probePrincipal, "mm_ping_probe_visibility_plan", visibilityArgs) as { planId: string }
await approvePlan(staleVisibility.planId, telemetryActor, true)
await pool.query("UPDATE uptime_probes SET target='192.0.2.2' WHERE id='visibility-own'")
assert.equal(await waitOperation((await applyPlan(probePrincipal, staleVisibility.planId, randomUUID())).id), "rejected")
const visibility = await invokeMcpTool(probePrincipal, "mm_ping_probe_visibility_plan", visibilityArgs) as { planId: string }
await approvePlan(visibility.planId, telemetryActor, true)
const beforeVisibilityCalls = probeNativeCalls
assert.equal(await waitOperation((await applyPlan(probePrincipal, visibility.planId, randomUUID())).id), "applied"); assert.equal(probeNativeCalls, beforeVisibilityCalls)
assert.deepEqual((await pool.query("SELECT show_on_dashboard,enabled,target FROM uptime_probes WHERE id='visibility-own'")).rows[0], { show_on_dashboard: false, enabled: false, target: "192.0.2.2" })
} finally {
probeInterfaceFixtures = false; probeReadFailure = false
await pool.query("DELETE FROM uptime_speed_test_runs WHERE id LIKE 'speed-visible-%' OR id LIKE 'speed-foreign-%'")
await pool.query("DELETE FROM uptime_probes WHERE id IN ('visibility-own','visibility-foreign')")
await pool.query("DELETE FROM servers WHERE id=3")
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
}
console.log("✓ Probe adapters: both history endpoints scoped in SQL before paging/parser, interface effective flags/unknowns/errors, protected/stale visibility plans with read-back and no network dispatch")
const liveAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Bounded live traffic", mode: "observer", permissions: ["mm:traffic:read"], scope: { allowGlobal: false, serverIds: [1], operationIds: ["traffic.live.read"] } }), telemetryActor)
const livePrincipal = await authenticateMcpToken(liveAccess.token)
liveFixtures = true; liveNativeCalls = 0
try {
const sample = await invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 1 }) as { samples: { rxMbps: number; txMbps: number }[]; forwardingVerified: boolean }
assert.equal(sample.samples[0].rxMbps, 2); assert.equal(sample.samples[0].txMbps, 0); assert.equal(sample.forwardingVerified, false)
assert.equal(liveNativeCalls, 2); assert.ok(!JSON.stringify(sample).includes("never-return-live-key"))
const separate = await invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 1, interface: "ether1", samples: 2 }) as { samples: unknown[] }
assert.equal(separate.samples.length, 2); assert.equal(liveNativeCalls, 4)
const beforeDenied = liveNativeCalls
await assert.rejects(invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 2 }))
await assert.rejects(invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 1, interface: "ether1,ether2" }))
await assert.rejects(invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 1, samples: 4 }))
const aborted = new AbortController(); aborted.abort()
await assert.rejects(invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 1 }, aborted.signal))
await pool.query("UPDATE servers SET enabled=false WHERE id=1")
await assert.rejects(invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 1 })); assert.equal(liveNativeCalls, beforeDenied)
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
liveIncomplete = true
await assert.rejects(invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 1 }))
liveIncomplete = false; liveChangeSource = true
await assert.rejects(invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 1, samples: 3 }))
liveChangeSource = false; liveRevokeConnection = liveAccess.connection.id
const beforeRevoke = liveNativeCalls
await assert.rejects(invokeMcpTool(livePrincipal, "mm_traffic_live_get", { serverId: 1, samples: 3 }))
assert.equal(liveNativeCalls, beforeRevoke + 2, "Revocation must stop before another native monitor request")
} finally {
liveFixtures = false; liveIncomplete = false; liveChangeSource = false; liveRevokeConnection = undefined
await pool.query("UPDATE servers SET enabled=true WHERE id=1")
}
console.log("✓ Bounded live traffic: complete sums, single interface, exact zero, no secret payload, scope/disabled/cancellation, bounds, no partial sum and revocation/source drift before next dispatch")
const geoipAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "GeoIP acceptance", permissions: ["mm:traffic:read", "mm:traffic:write"], scope: { allowGlobal: true, serverIds: [1, 2], operationIds: ["geoip.read", "geoip.settings.update"] } }), telemetryActor)
const geoipPrincipal = await authenticateMcpToken(geoipAccess.token)
const { getGeoipSettings, updateGeoipSettings, touchGeoipRunMeta } = await import("../../services/geoip-settings.js")
const geoipStatus = await invokeMcpTool(geoipPrincipal, "mm_geoip_get", {}) as { running: boolean; settings: { enabled: boolean } }
assert.equal(geoipStatus.running, false)
await assert.rejects(invokeMcpTool(geoipPrincipal, "mm_geoip_settings_update_plan", { settings: {} }))
await assert.rejects(invokeMcpTool(geoipPrincipal, "mm_geoip_settings_update_plan", { settings: { updateIntervalSec: 60 } }))
await assert.rejects(invokeMcpTool(geoipPrincipal, "mm_geoip_settings_update_plan", { settings: { mirrorUrl: "https://example.invalid" } }))
const geoipPlan = await invokeMcpTool(geoipPrincipal, "mm_geoip_settings_update_plan", { settings: { enabled: false, updateIntervalSec: 86400 } }) as { planId: string }
await approvePlan(geoipPlan.planId, telemetryActor, true)
// Collector metadata must not invalidate a reviewed configuration change.
await touchGeoipRunMeta({ lastCheckAt: new Date().toISOString(), lastError: "fixture update observation" })
assert.equal(await waitOperation((await applyPlan(geoipPrincipal, geoipPlan.planId, randomUUID())).id), "applied")
assert.equal((await getGeoipSettings()).enabled, false)
assert.equal((await getGeoipSettings()).updateIntervalSec, 86400)
assert.equal((await getGeoipSettings()).lastError, "fixture update observation")
const staleGeoip = await invokeMcpTool(geoipPrincipal, "mm_geoip_settings_update_plan", { settings: { updateIntervalSec: 172800 } }) as { planId: string }
await approvePlan(staleGeoip.planId, telemetryActor, true)
await updateGeoipSettings({ updateIntervalSec: 259200 })
assert.equal(await waitOperation((await applyPlan(geoipPrincipal, staleGeoip.planId, randomUUID())).id), "rejected")
assert.equal((await getGeoipSettings()).updateIntervalSec, 259200)
const geoipProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,reason,created_by) VALUES($1,$2::jsonb,'fixture',$3)", [geoipProtection, JSON.stringify({ kind: "geoip-settings", id: "1", protection: "deny" }), actor.id])
try {
await assert.rejects(updateGeoipSettings({ enabled: true }))
await assert.rejects(invokeMcpTool(geoipPrincipal, "mm_geoip_settings_update_plan", { settings: { enabled: true } }))
assert.equal((await getGeoipSettings()).enabled, false)
} finally { await pool.query("DELETE FROM mcp_protections WHERE id=$1", [geoipProtection]) }
const partialGeoipAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "GeoIP partial scope", permissions: ["mm:traffic:read", "mm:traffic:write"], scope: { allowGlobal: true, serverIds: [1], operationIds: ["geoip.read", "geoip.settings.update"] } }), telemetryActor)
const partialGeoipPrincipal = await authenticateMcpToken(partialGeoipAccess.token)
await assert.rejects(invokeMcpTool(partialGeoipPrincipal, "mm_geoip_get", {}))
await assert.rejects(invokeMcpTool(partialGeoipPrincipal, "mm_geoip_settings_update_plan", { settings: { enabled: true } }))
await pool.query("CREATE FUNCTION mcp_test_ignore_geoip() RETURNS trigger LANGUAGE plpgsql AS 'BEGIN RETURN OLD; END'")
await pool.query("CREATE TRIGGER mcp_test_ignore_geoip BEFORE UPDATE ON geoip_settings FOR EACH ROW EXECUTE FUNCTION mcp_test_ignore_geoip()")
try {
const ignored = await invokeMcpTool(geoipPrincipal, "mm_geoip_settings_update_plan", { settings: { updateIntervalSec: 345600 } }) as { planId: string }
await approvePlan(ignored.planId, telemetryActor, true)
assert.equal(await waitOperation((await applyPlan(geoipPrincipal, ignored.planId, randomUUID())).id), "partial")
assert.equal((await getGeoipSettings()).updateIntervalSec, 259200)
} finally {
await pool.query("DROP TRIGGER mcp_test_ignore_geoip ON geoip_settings")
await pool.query("DROP FUNCTION mcp_test_ignore_geoip()")
}
const geoipCollector = await import("../../services/geoip-update-collector.js")
const savedGeoipDirectory = process.env.GEOIP_DIR
process.env.GEOIP_DIR = (await import("node:path")).join(process.env.MCP_STATE_DIR!, "geoip-fixture")
let mirrorRequests = 0
geoipCollector.setGeoipFetchForTests(async () => { mirrorRequests++; return new Response(null, { status: 503 }) })
try {
const enableGeoip = await invokeMcpTool(geoipPrincipal, "mm_geoip_settings_update_plan", { settings: { enabled: true } }) as { planId: string; changes: { warnings: string[] } }
assert.ok(enableGeoip.changes.warnings.some(warning => warning.includes("сразу")))
await approvePlan(enableGeoip.planId, telemetryActor, true)
assert.equal(await waitOperation((await applyPlan(geoipPrincipal, enableGeoip.planId, randomUUID())).id), "applied")
for (let attempt = 0; attempt < 100 && (mirrorRequests < 2 || geoipCollector.getGeoipUpdateState().running); attempt++) await delay(20)
assert.equal(mirrorRequests, 2); assert.equal(geoipCollector.getGeoipUpdateState().running, false)
const failedMirrorStatus = await invokeMcpTool(geoipPrincipal, "mm_geoip_get", {}) as { settings: { enabled: boolean; lastError: string } }
assert.equal(failedMirrorStatus.settings.enabled, true)
assert.match(failedMirrorStatus.settings.lastError, /HTTP 503/)
assert.equal(mirrorRequests, 2, "Status reads must not restart the failed download")
} finally {
await updateGeoipSettings({ enabled: false })
await (await import("../../services/scheduler.js")).refreshScheduler()
geoipCollector.resetGeoipUpdateForTests()
if (savedGeoipDirectory === undefined) delete process.env.GEOIP_DIR
else process.env.GEOIP_DIR = savedGeoipDirectory
}
console.log("✓ GeoIP uses shared guarded settings: strict input, stable metadata, stale-plan rejection, full scope, protected REST service and failed persistence read-back")
const evoAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "EvoBGP settings acceptance", limits: { mutationsPerHour: 50 }, permissions: ["mm:settings:admin"], scope: { allowGlobal: true, serverIds: [1, 2], operationIds: ["evobgp.settings.read", "evobgp.settings.update", "evobgp.catalog.read"] } }), actor)
const evoPrincipal = await authenticateMcpToken(evoAccess.token)
const limitedEvo = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "EvoBGP partial scope", permissions: ["mm:settings:admin"], scope: { allowGlobal: true, serverIds: [1], operationIds: ["evobgp.settings.read", "evobgp.settings.update", "evobgp.catalog.read"] } }), actor)
const limitedEvoPrincipal = await authenticateMcpToken(limitedEvo.token)
await assert.rejects(invokeMcpTool(limitedEvoPrincipal, "mm_evobgp_settings_get", {}))
await assert.rejects(invokeMcpTool(limitedEvoPrincipal, "mm_evobgp_settings_update_plan", { settings: { enabled: true } }))
const { readEvoBgpSettings, writeEvoBgpSettings } = await import("../../services/evobgp-settings.js")
await pool.query("DELETE FROM evobgp_settings")
assert.deepEqual(await invokeMcpTool(evoPrincipal, "mm_evobgp_settings_get", {}), { baseUrl: "", enabled: false, secretConfigured: false })
assert.equal((await pool.query("SELECT count(*)::int AS n FROM evobgp_settings")).rows[0].n, 0)
const evoRoot = "https://evo.example.invalid", evoKey = "fixture-evo-private-key"
const issueEvoSecret = async (purpose = `evobgp-api:${evoRoot}`, owner = actor.id, serverId: number | null = null) => {
const id = randomUUID()
await pool.query("INSERT INTO mcp_secrets(id,purpose,server_id,ciphertext,created_by) VALUES($1,$2,$3,$4,$5)", [id, purpose, serverId, await encryptSecret("Bearer " + evoKey), owner])
return id
}
for (const ref of [await issueEvoSecret("evobgp-api:https://wrong.example.invalid"), await issueEvoSecret(undefined, "other-owner"), await issueEvoSecret(undefined, actor.id, 1)]) {
await assert.rejects(invokeMcpTool(evoPrincipal, "mm_evobgp_settings_update_plan", { settings: { baseUrl: evoRoot }, apiKeyRef: ref }))
}
await assert.rejects(invokeMcpTool(evoPrincipal, "mm_evobgp_settings_update_plan", { settings: { apiKey: "raw-input-rejected" } }))
await assert.rejects(invokeMcpTool(evoPrincipal, "mm_evobgp_settings_update_plan", { settings: {} }))
const evoKeyRef = await issueEvoSecret()
const applyEvo = async (args: Record<string, unknown>, state = "applied") => {
const plan = await invokeMcpTool(evoPrincipal, "mm_evobgp_settings_update_plan", args) as { planId: string; changes: unknown }
assert.ok(!JSON.stringify(plan).includes(evoKey))
await approvePlan(plan.planId, actor, true)
const operation = await applyPlan(evoPrincipal, plan.planId, randomUUID())
assert.equal(await waitOperation(operation.id), state)
return operation
}
await applyEvo({ settings: { baseUrl: "EVO.example.invalid/", enabled: false }, apiKeyRef: evoKeyRef })
assert.deepEqual(await readEvoBgpSettings(), { baseUrl: evoRoot, enabled: false, apiKey: evoKey })
assert.deepEqual(await invokeMcpTool(evoPrincipal, "mm_evobgp_settings_get", {}), { baseUrl: evoRoot, enabled: false, secretConfigured: true })
await assert.rejects(invokeMcpTool(evoPrincipal, "mm_evobgp_settings_update_plan", { settings: { baseUrl: "https://different.example.invalid" } }))
const staleEvo = await invokeMcpTool(evoPrincipal, "mm_evobgp_settings_update_plan", { settings: { enabled: true } }) as { planId: string }
await approvePlan(staleEvo.planId, actor, true)
await writeEvoBgpSettings({ apiKey: "fixture-replaced-private-key" })
assert.equal(await waitOperation((await applyPlan(evoPrincipal, staleEvo.planId, randomUUID())).id), "rejected")
assert.equal((await readEvoBgpSettings()).enabled, false)
const evoProtection = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,reason,created_by) VALUES($1,$2::jsonb,'fixture',$3)", [evoProtection, JSON.stringify({ kind: "evobgp-settings", id: "1", protection: "deny" }), actor.id])
try {
await assert.rejects(writeEvoBgpSettings({ enabled: true }))
await assert.rejects(invokeMcpTool(evoPrincipal, "mm_evobgp_settings_update_plan", { settings: { enabled: true } }))
} finally { await pool.query("DELETE FROM mcp_protections WHERE id=$1", [evoProtection]) }
await pool.query("CREATE FUNCTION mcp_test_ignore_evo() RETURNS trigger LANGUAGE plpgsql AS 'BEGIN RETURN OLD; END'")
await pool.query("CREATE TRIGGER mcp_test_ignore_evo BEFORE UPDATE ON evobgp_settings FOR EACH ROW EXECUTE FUNCTION mcp_test_ignore_evo()")
try { await applyEvo({ settings: {}, apiKeyRef: evoKeyRef }, "partial") }
finally {
await pool.query("DROP TRIGGER mcp_test_ignore_evo ON evobgp_settings")
await pool.query("DROP FUNCTION mcp_test_ignore_evo()")
}
await applyEvo({ settings: { baseUrl: "https://different.example.invalid" }, apiKeyRef: null })
assert.equal((await readEvoBgpSettings()).apiKey, "")
await applyEvo({ settings: { baseUrl: evoRoot }, apiKeyRef: evoKeyRef })
await applyEvo({ settings: { enabled: true } })
assert.deepEqual(await readEvoBgpSettings(), { baseUrl: evoRoot, enabled: true, apiKey: evoKey })
const evoLogs = await pool.query("SELECT to_jsonb(request) AS payload FROM mcp_requests AS request WHERE connection_id=$1 UNION ALL SELECT intended_state FROM mcp_operation_steps WHERE operation_id IN (SELECT id FROM mcp_operations WHERE connection_id=$1)", [evoAccess.connection.id])
assert.ok(!JSON.stringify(evoLogs.rows).includes(evoKey))
console.log("✓ EvoBGP settings: read is non-mutating, owner/destination-bound opaque keys, encrypted/redacted plans, key rotation invalidates plans, protections and failed key read-back")
await writeEvoBgpSettings({ baseUrl: `http://127.0.0.1:${port}`, enabled: true })
await assert.rejects(invokeMcpTool(limitedEvoPrincipal, "mm_evobgp_catalog_get", {})); assert.equal(evoCatalogCalls, 0)
await assert.rejects(invokeMcpTool(evoPrincipal, "mm_evobgp_catalog_get", { baseUrl: "https://untrusted.invalid" })); assert.equal(evoCatalogCalls, 0)
const emptyCatalog = await invokeMcpTool(evoPrincipal, "mm_evobgp_catalog_get", {}) as { communities: unknown[]; incomplete: boolean }
assert.deepEqual(emptyCatalog.communities, []); assert.equal(emptyCatalog.incomplete, false)
assert.equal(evoCatalogAuthorization, "Bearer " + evoKey)
const evoAssociations = (await pool.query("INSERT INTO filter_rules(server_id,community,gateway_tunnel_id) VALUES(1,' 64512:4242 ','fixture'),(1,'64512:4242','fixture'),(2,'64512:4242','fixture') RETURNING id")).rows.map(row => row.id)
try {
evoCatalogPayload = { ...emptyEvoCatalog, modules: { items: [{ id: "m", name: evoKey, type: "custom" }] },
domains: { items: [1, 2].map(id => ({ module_id: "m", entry: { id: "d" + id, fqdn: `example${id}.invalid`, community_id: "c" } })) },
asns: { items: [{ module_id: "m", entry: { id: "a", asn: 64512, community_id: "c" } }] },
communities: { items: [{ id: "c", community: "64512:4242" }, { id: "z", community: "64512:4243" }] },
}
type EvoPage = { catalogVersion: string; domains: { id: string }[]; communities: { serverCount: number; prefixCount: number | null }[]; pages: { domains: { total: number; nextOffset: number | null } }; incomplete: boolean }
const first = await invokeMcpTool(evoPrincipal, "mm_evobgp_catalog_get", { limit: 1 }) as EvoPage
assert.equal(first.pages.domains.total, 2); assert.equal(first.pages.domains.nextOffset, 1)
assert.equal(first.communities[0].serverCount, 2); assert.equal(first.communities[0].prefixCount, null)
assert.equal(first.incomplete, true); assert.ok(!JSON.stringify(first).includes(evoKey))
const second = await invokeMcpTool(evoPrincipal, "mm_evobgp_catalog_get", { limit: 1, offset: 1 }) as EvoPage
assert.equal(second.catalogVersion, first.catalogVersion); assert.equal(second.pages.domains.nextOffset, null)
assert.notEqual(second.domains[0].id, first.domains[0].id); assert.equal(second.communities[0].prefixCount, 0)
evoCatalogPayload = { modules: { items: [] } }
await assert.rejects(invokeMcpTool(evoPrincipal, "mm_evobgp_catalog_get", {}))
evoCatalogRedirect = true
await assert.rejects(invokeMcpTool(evoPrincipal, "mm_evobgp_catalog_get", {}))
evoCatalogRedirect = false
await writeEvoBgpSettings({ enabled: false })
const callsBeforeDisabled = evoCatalogCalls
await assert.rejects(invokeMcpTool(evoPrincipal, "mm_evobgp_catalog_get", {})); assert.equal(evoCatalogCalls, callsBeforeDisabled)
const catalogRequests = (await pool.query("SELECT result FROM mcp_requests WHERE connection_id=$1 AND tool='mm_evobgp_catalog_get'", [evoAccess.connection.id])).rows
assert.ok(!JSON.stringify(catalogRequests).includes(evoKey))
} finally {
evoCatalogRedirect = false; evoCatalogPayload = emptyEvoCatalog
await pool.query("DELETE FROM filter_rules WHERE id=ANY($1::bigint[])", [evoAssociations])
}
console.log("✓ EvoBGP catalog: full scope before upstream/SQL, saved credentials only, shared formatting, nullable counts, paging/version, credential reflection masked, disabled/malformed/redirect rejected")
const evoProbeAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "EvoBGP connection check", permissions: ["mm:settings:admin"], scope: { allowGlobal: true, serverIds: [1, 2], operationIds: ["evobgp.connection.check"] } }), actor)
const evoProbePrincipal = await authenticateMcpToken(evoProbeAccess.token)
const partialEvoProbeAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Partial EvoBGP connection check", permissions: ["mm:settings:admin"], scope: { allowGlobal: true, serverIds: [1], operationIds: ["evobgp.connection.check"] } }), actor)
await assert.rejects(invokeMcpTool(await authenticateMcpToken(partialEvoProbeAccess.token), "mm_evobgp_connection_check", {})); assert.equal(evoProbeCalls, 0)
const beforeProbe = await readEvoBgpSettings()
evoProbePayload = { items: [{ name: evoKey }] }
const probeReceipt = await invokeMcpTool(evoProbePrincipal, "mm_evobgp_connection_check", {}) as { ok: boolean; configurationSaved: boolean; routingVerified: boolean }
assert.equal(probeReceipt.ok, true); assert.equal(probeReceipt.configurationSaved, false); assert.equal(probeReceipt.routingVerified, false)
assert.equal(evoProbeAuthorization, "Bearer " + evoKey); assert.ok(!JSON.stringify(probeReceipt).includes(evoKey))
assert.deepEqual(await readEvoBgpSettings(), beforeProbe)
await assert.rejects(invokeMcpTool(evoProbePrincipal, "mm_evobgp_connection_check", { baseUrl: "https://different.example.invalid" })); assert.equal(evoProbeCalls, 1)
await assert.rejects(invokeMcpTool(evoProbePrincipal, "mm_evobgp_connection_check", { apiKey: "raw-key-rejected" })); assert.equal(evoProbeCalls, 1)
const probeRoot = `http://127.0.0.1:${port}`
const foreignProbeRef = await issueEvoSecret(`evobgp-api:${probeRoot}`, "other-owner")
await assert.rejects(invokeMcpTool(evoProbePrincipal, "mm_evobgp_connection_check", { apiKeyRef: foreignProbeRef })); assert.equal(evoProbeCalls, 1)
await assert.rejects(invokeMcpTool(evoProbePrincipal, "mm_evobgp_connection_check", { apiKeyRef: evoKeyRef })); assert.equal(evoProbeCalls, 1)
const probeKeyRef = await issueEvoSecret(`evobgp-api:${probeRoot}`)
await writeEvoBgpSettings({ baseUrl: evoRoot })
await invokeMcpTool(evoProbePrincipal, "mm_evobgp_connection_check", { baseUrl: probeRoot, apiKeyRef: probeKeyRef })
assert.equal((await readEvoBgpSettings()).baseUrl, evoRoot)
evoProbePayload = { error: evoKey }
await assert.rejects(invokeMcpTool(evoProbePrincipal, "mm_evobgp_connection_check", { baseUrl: probeRoot, apiKeyRef: probeKeyRef }), error => error instanceof Error && !error.message.includes(evoKey))
evoProbeRedirect = true
await assert.rejects(invokeMcpTool(evoProbePrincipal, "mm_evobgp_connection_check", { baseUrl: probeRoot, apiKeyRef: probeKeyRef }))
evoProbeRedirect = false; evoProbePayload = { items: [] }
const probeRequests = (await pool.query("SELECT result,error_code FROM mcp_requests WHERE connection_id=$1", [evoProbeAccess.connection.id])).rows
assert.ok(!JSON.stringify(probeRequests).includes(evoKey))
console.log("✓ EvoBGP connection check: fixed bounded GET, full scope before network, owner/destination-bound draft secret, no save/credential reflection, malformed and redirects rejected")
const statsAccess = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Scoped statistics", permissions: ["mm:traffic:read"], scope: { allowGlobal: false, serverIds: [1], operationIds: ["statistics.read", "statistics.pivot"] } }), telemetryActor)
const statsPrincipal = await authenticateMcpToken(statsAccess.token)
const { ensurePartitionFor } = await import("../../db/partitions.js")
await ensurePartitionFor(pool, "flow_hour_facts", "day", new Date("2026-10-03T00:00:00Z"))
await pool.query("INSERT INTO flow_hour_facts(server_id,bucket_at,iface,country,service,asn,bytes,packets) VALUES(1,'2026-10-03T00:00:00Z','fixture-stats','RU','FixtureStats',0,12345,10),(2,'2026-10-03T00:00:00Z','fixture-stats','US','ForeignStats',0,98765,90)")
const touched: number[] = [], { setRefreshIfacesForTests } = await import("../../services/traffic-flow-ifaces.js")
setRefreshIfacesForTests(async id => { touched.push(id) })
try {
const summary = await invokeMcpTool(statsPrincipal, "mm_statistics_get", { serverId: 1, from: "2026-10-03", to: "2026-10-03", iface: "fixture-stats", planes: "all" }) as { kpis: { bytes: number }; services: { label: string }[] }
assert.equal(summary.kpis.bytes, 12345); assert.ok(!JSON.stringify(summary).includes("ForeignStats"))
const pivot = await invokeMcpTool(statsPrincipal, "mm_statistics_pivot_get", { serverId: 1, from: "2026-10-03", to: "2026-10-03", iface: "fixture-stats", planes: "all", row: "country", col: "service" }) as { rows: { total: number }[] }
assert.equal(pivot.rows.reduce((sum, row) => sum + row.total, 0), 12345)
assert.ok(touched.length > 0 && touched.every(id => id === 1), JSON.stringify(touched))
await assert.rejects(invokeMcpTool(statsPrincipal, "mm_statistics_get", { serverId: 2, from: "2026-10-03", to: "2026-10-03" }))
await assert.rejects(invokeMcpTool(statsPrincipal, "mm_statistics_get", { serverId: 1, from: "2026-01-01", to: "2026-10-03" }))
} finally { setRefreshIfacesForTests(null) }
console.log("✓ Scoped statistics/pivot filter SQL and native interface refresh to the selected server; long windows and foreign servers are denied")
const savedSocket = process.env.FLOW_AGENT_SOCKET
const socket = process.platform === "win32" ? "\\\\.\\pipe\\mcp-flow-" + randomUUID() : (await import("node:path")).join((await import("node:os")).tmpdir(), "mcp-flow-" + randomUUID() + ".sock")
let hostApplies = 0, hostMatches = true
const flowAgent = createServer((request, response) => {
request.resume()
request.on("end", () => {
if (request.url === "/apply") hostApplies++
response.setHeader("content-type", "application/json")
response.end(JSON.stringify({ interfaceUp: true, configMatches: hostMatches, publicKey: "public-key-fixture", listenPort: 51821, addresses: ["10.255.254.1/24"], peers: [], privateKey: "must-never-return" }))
})
})
await new Promise<void>((resolve, reject) => { flowAgent.once("error", reject); flowAgent.listen(socket, resolve) })
try {
process.env.FLOW_AGENT_SOCKET = socket
const hostConnection = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, name: "Host acceptance", permissions: ["mm:settings:admin"], scope: { allowGlobal: true, serverIds: [1, 2], operationIds: ["netflow.host.read", "netflow.host.reconcile"] } }), actor)
const hostPrincipal = await authenticateMcpToken(hostConnection.token)
assert.ok(!JSON.stringify(await invokeMcpTool(hostPrincipal, "mm_netflow_host_get", {})).includes("must-never-return"))
const hostPlan = await invokeMcpTool(hostPrincipal, "mm_netflow_host_reconcile_plan", {}) as { planId: string }
await approvePlan(hostPlan.planId, actor, true)
assert.equal(await waitOperation((await applyPlan(hostPrincipal, hostPlan.planId, "flow-host-apply")).id), "applied")
assert.equal(hostApplies, 1)
const protectedHost = randomUUID()
await pool.query("INSERT INTO mcp_protections(id,object_ref,reason,created_by) VALUES($1,$2::jsonb,'fixture',$3)", [protectedHost, JSON.stringify({ kind: "netflow-host", id: "1", protection: "deny" }), actor.id])
await assert.rejects(invokeMcpTool(hostPrincipal, "mm_netflow_host_reconcile_plan", {}))
await assert.rejects((await import("../../services/traffic-flow-host-agent.js")).reconcileFlowHost())
assert.equal(hostApplies, 1)
await pool.query("DELETE FROM mcp_protections WHERE id=$1", [protectedHost])
const failedHost = await invokeMcpTool(hostPrincipal, "mm_netflow_host_reconcile_plan", {}) as { planId: string }
await approvePlan(failedHost.planId, actor, true)
hostMatches = false
assert.equal(await waitOperation((await applyPlan(hostPrincipal, failedHost.planId, "flow-host-unverified")).id), "partial")
assert.equal(hostApplies, 2)
console.log("✓ NetFlow host uses saved settings and real local-agent protocol; protected legacy apply is blocked and a mismatched read-back remains partial")
} finally {
if (savedSocket === undefined) delete process.env.FLOW_AGENT_SOCKET; else process.env.FLOW_AGENT_SOCKET = savedSocket
await new Promise<void>(resolve => flowAgent.close(() => resolve()))
}
legacyRouteContextFixture = true
const profileConnection = await createMcpConnection(mcpConnectionCreateSchema.parse({ ...input, permissions: [...input.permissions, "mm:filters:write"], name: "Controller", scope: { ...input.scope, operationIds: ["routing.profiles.save", "routing.profiles.read", "routing.analyze", "routing.community.switch", "routing.path.verify"] } }), actor)
const controllerPrincipal = await authenticateMcpToken(profileConnection.token)
const profileInput = { name: "Persisted", serverId: 1, family: "ipv4", community: "65000:10", candidates: [{ id: "single", wanInterface: "wan", downstreamInterface: "down", jumpHostId: 1, exitNodeId: 1, gateway: "192.0.2.1", gatewayRef: { resource: "ipv4_route", id: "*1" } }] }
const legacyContext = await invokeMcpTool(controllerPrincipal, "mm_route_optimizer_analyze", { profile: profileInput }) as { contextVerified: boolean; currentCandidateId: string | null; executionAvailable: boolean; dependencyProof: string; targetRuleProof: string; sourceProofs: unknown }
assert.equal(legacyContext.contextVerified, true); assert.equal(legacyContext.currentCandidateId, "single"); assert.equal(legacyContext.executionAvailable, true, "legacy main profile needs no explicit table, probeVrf or bgpContext")
await assert.rejects(invokeMcpTool(controllerPrincipal, "mm_route_optimizer_plan", { profile: profileInput, candidateId: "single" }), error => error instanceof Error && "code" in error && error.code === "MEASUREMENT_UNKNOWN")
const { findMcpService, registerMcpService } = await import("./service-registry.js")
for (const iface of ["wan", "down"]) await pool.query("INSERT INTO mcp_routing_observations(id,src_server_id,dst_server_id,src_interface,dst_interface,family,routing_table,ping_ms,loss_pct,dl_mbps,ul_mbps,ping_at,bandwidth_at,context_verified,source) VALUES($1,1,1,$2,'peer','ipv4','main',10,0,100,100,now()-interval '2 hours',now()-interval '2 hours',true,'fixture')", [randomUUID(), iface])
await assert.rejects(findMcpService("routing.community")!.current({ serverId: 1, profile: profileInput, candidateId: "single" }), error => error instanceof Error && "code" in error && error.code === "STATE_CONFLICT", "an unbound legacy service input cannot bypass the native context proof")
await assert.rejects(findMcpService("routing.community")!.current({ serverId: 1, profile: profileInput, candidateId: "single", contextProof: legacyContext.dependencyProof, targetRuleProof: legacyContext.targetRuleProof, contextSources: legacyContext.sourceProofs }), error => error instanceof Error && "code" in error && error.code === "MEASUREMENT_UNKNOWN")
console.log("✓ Community plans reject missing measurements and recheck expired SLA evidence before any write")
const controllerOriginalAuthority = await effectiveMcpConnection(controllerPrincipal)
const controllerFixtureExpiry = () => fixtureGrantExpiry(Date.now(), Date.parse(controllerPrincipal.credentialExpiresAt), Date.parse(controllerOriginalAuthority.policy.expiresAt), controllerOriginalAuthority.owner_valid_until.getTime())
const profilePlan = await invokeMcpTool(controllerPrincipal, "mm_route_profile_save_plan", { profile: profileInput, enabled: true, expiresAt: controllerFixtureExpiry() }) as { planId: string }
await approvePlan(profilePlan.planId, actor, true)
const saved = await applyPlan(controllerPrincipal, profilePlan.planId, "profile-save")
for (let index = 0; index < 100; index++) {
state = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [saved.id])).rows[0].state
if (!["pending", "running"].includes(state)) break
await delay(30)
}
assert.equal(state, "applied")
const { tickRoutingProfiles } = await import("./routing-profiles.js")
await tickRoutingProfiles()
const persisted = (await pool.query("SELECT state,enabled FROM mcp_routing_profiles WHERE connection_id=$1", [profileConnection.connection.id])).rows[0]
assert.equal(persisted.enabled, true); assert.ok(persisted.state.checkedAt); assert.equal(persisted.state.planId, undefined)
await setConnectionStatus(profileConnection.connection.id, "paused", actor)
await tickRoutingProfiles()
assert.equal((await pool.query("SELECT enabled FROM mcp_routing_profiles WHERE connection_id=$1", [profileConnection.connection.id])).rows[0].enabled, false)
console.log("✓ Persistent controller preserves unknown path and stops after access revocation")
legacyRouteContextFixture = false
await setConnectionStatus(profileConnection.connection.id, "active", actor)
const webPayload = { connectionId: profileConnection.connection.id, profile: { ...profileInput, name: "From web" }, enabled: false, expiresAt: controllerFixtureExpiry() }
const webHeaders = { authorization: "Bearer " + jwt }
assert.equal((await app.inject({ method: "POST", url: "/api/mcp/routing-profiles/plan", payload: webPayload })).statusCode, 401)
const webPlanResponse = await app.inject({ method: "POST", url: "/api/mcp/routing-profiles/plan", headers: webHeaders, payload: webPayload })
assert.equal(webPlanResponse.statusCode, 200, webPlanResponse.body)
const webPlanId = webPlanResponse.json().planId
const otherJwt = await new SignJWT({ sub: "other-owner", apps: ["mm"], permissions: actor.permissions }).setProtectedHeader({ alg: "HS256" }).setIssuer(env.authIssuer).setExpirationTime("1h").sign(new TextEncoder().encode(env.jwtSecret))
assert.equal((await app.inject({ method: "POST", url: `/api/mcp/plans/${webPlanId}/apply`, headers: { authorization: "Bearer " + otherJwt }, payload: {} })).statusCode, 403)
assert.equal((await app.inject({ method: "POST", url: `/api/mcp/plans/${webPlanId}/apply`, headers: webHeaders, payload: {} })).statusCode, 409)
assert.equal((await app.inject({ method: "POST", url: `/api/mcp/plans/${webPlanId}/decision`, headers: webHeaders, payload: { approve: true } })).statusCode, 200)
const webOperation = await app.inject({ method: "POST", url: `/api/mcp/plans/${webPlanId}/apply`, headers: webHeaders, payload: {} })
assert.equal(webOperation.statusCode, 200, webOperation.body)
for (let index = 0; index < 100; index++) {
state = (await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [webOperation.json().id])).rows[0].state
if (!["pending", "running"].includes(state)) break
await delay(30)
}
assert.equal(state, "applied")
console.log("✓ Human profile UI uses scoped plans, requires approval and rejects another owner's execution")
const orphanPlan = randomUUID(), orphanOperation = randomUUID()
await pool.query("INSERT INTO mcp_plans SELECT $1,connection_id,operation_id,operation_version,policy_version,generation,payload,evidence,'executing',expires_at,approved_by,approved_at,created_at FROM mcp_plans WHERE id=$2", [orphanPlan, stale.planId])
await pool.query("INSERT INTO mcp_operations(id,plan_id,connection_id,idempotency_key,state,created_at) VALUES($1,$2,$3,'orphan','running',now()-interval '3 minutes')", [orphanOperation, orphanPlan, issued.connection.id])
const lease = await pool.connect()
try {
await lease.query("SELECT pg_advisory_lock(hashtextextended($1,0))", ["mcp-operation:" + orphanOperation])
await recoverMcpOperations()
assert.equal((await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [orphanOperation])).rows[0].state, "running")
} finally { await lease.query("SELECT pg_advisory_unlock(hashtextextended($1,0))", ["mcp-operation:" + orphanOperation]); lease.release() }
await recoverMcpOperations()
assert.equal((await pool.query("SELECT state FROM mcp_operations WHERE id=$1", [orphanOperation])).rows[0].state, "unknown")
console.log("✓ Recovery respects live runner leases and marks orphaned writes unknown")
const recoveryChannelServer = createServer((_req, res) => { res.setHeader("content-type", "application/json"); res.end(JSON.stringify({ "system-id": "fixture-primary" })) })
await new Promise<void>(resolve => recoveryChannelServer.listen(0, "127.0.0.2", resolve))
const restoreService = findMcpService("routing.community.restore")!, savedService = { ...restoreService }
try {
const channel = await registerManagementChannel({ serverId: 1, host: "127.0.0.2", port: (recoveryChannelServer.address() as { port: number }).port, useSsl: false, verifySsl: true, username: "fixture", password: "fixture", attestation: "Изолированный независимый канал для проверки заранее разрешённого восстановления", expiresAt: fixtureGrantExpiry(Date.now(), actor.expiresAt!) }, actor)
const { routeAiProfileSchema } = await import("@mmapp/contracts/mcp-routing")
const recoveryProfile = routeAiProfileSchema.parse({ ...profileInput, candidates: profileInput.candidates.map(candidate => ({ ...candidate, controlProbe: { targetInterface: "down", expectedHops: [{ serverId: 1, interface: "peer" }] } })), autoRecovery: true }), grantId = randomUUID()
const activePrincipal = await authenticateMcpToken(rotated.token)
const recoveryOriginalAuthority = await effectiveMcpConnection(activePrincipal)
const recoveryFixtureExpiry = fixtureGrantExpiry(Date.now(), Date.parse(activePrincipal.credentialExpiresAt), Date.parse(recoveryOriginalAuthority.policy.expiresAt), recoveryOriginalAuthority.owner_valid_until.getTime())
await pool.query("INSERT INTO mcp_routing_profiles(id,connection_id,config,enabled,grant_expires_at,credential_id,generation,policy_version) VALUES($1,$2,$3::jsonb,true,$6,$4,$5,1)", [grantId, issued.connection.id, JSON.stringify(recoveryProfile), activePrincipal.credentialId, await (await import("./security.js")).accessGeneration(), recoveryFixtureExpiry])
const before = settings["rp-filter"]
restoreService.current = async () => ({ value: settings["rp-filter"] })
restoreService.execute = async () => nativeClient.patch("/ip/settings", { "rp-filter": before })
restoreService.verify = async () => settings["rp-filter"] === before
registerMcpService("fixture.confirmed-write-failed-probe", { current: async () => ({ value: settings["rp-filter"] }), execute: async () => nativeClient.patch("/ip/settings", { "rp-filter": "loose" }), verify: async () => false })
const prepared = await invokeMcpTool(activePrincipal, "mm_ip_settings_update_plan", { serverId: 1, fields: { "rp-filter": "loose" } }) as { planId: string }
const sealed = (await pool.query("SELECT evidence FROM mcp_plans WHERE id=$1", [prepared.planId])).rows[0].evidence
const evidence = JSON.parse(await decryptSecret(sealed.sealed))
evidence.steps = [{ kind: "service", service: "fixture.confirmed-write-failed-probe", input: {} }]; evidence.before = { value: before }
evidence.managementChannels = [await verifyManagementChannel(1, channel.id)]
evidence.recovery = { authorityProfileId: grantId, validUntil: new Date(Date.now() + 120000).toISOString(), expected: { value: "loose" }, step: { kind: "service", service: "routing.community.restore", input: { profile: recoveryProfile } } }
await pool.query("UPDATE mcp_plans SET evidence=$2::jsonb WHERE id=$1", [prepared.planId, JSON.stringify({ sealed: await encryptSecret(JSON.stringify(evidence)) })])
await approvePlan(prepared.planId, actor, true)
const writesBeforeLegacyWriter = writes
const attempted = await applyPlan(activePrincipal, prepared.planId, "reserved-recovery")
// This deliberately unsupported legacy profile has no authentic baseline.
// Replacing an unavailable restore service cannot enroll a generic writer.
// Genuine positive inverse coverage lives in the scoped production suite.
assert.ok(["rejected", "partial", "unknown"].includes(await waitOperation(attempted.id)), "Legacy writer must reach a terminal refusal, never remain pending or time out")
assert.equal(writes, writesBeforeLegacyWriter); assert.equal(settings["rp-filter"], before)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_operation_checkpoints WHERE operation_id=$1 AND configuration_sealed IS NOT NULL", [attempted.id])).rows[0].n, 0)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_recovery_intents WHERE operation_id=$1 AND state='verified'", [attempted.id])).rows[0].n, 0)
const beforeReplay = writes
await applyPlan(activePrincipal, prepared.planId, "reserved-recovery"); await delay(50); assert.equal(writes, beforeReplay)
await pool.query("UPDATE mcp_routing_profiles SET enabled=false WHERE id=$1", [grantId])
const blockedPlan = await invokeMcpTool(activePrincipal, "mm_ip_settings_update_plan", { serverId: 1, fields: { "rp-filter": "loose" } }) as { planId: string }
const blockedSealed = (await pool.query("SELECT evidence FROM mcp_plans WHERE id=$1", [blockedPlan.planId])).rows[0].evidence
const blockedEvidence = JSON.parse(await decryptSecret(blockedSealed.sealed)); blockedEvidence.managementChannels = evidence.managementChannels; blockedEvidence.recovery = evidence.recovery
await pool.query("UPDATE mcp_plans SET evidence=$2::jsonb WHERE id=$1", [blockedPlan.planId, JSON.stringify({ sealed: await encryptSecret(JSON.stringify(blockedEvidence)) })])
await approvePlan(blockedPlan.planId, actor, true)
const writesBeforeRevokedGrant = writes
await assert.rejects(applyPlan(activePrincipal, blockedPlan.planId, "revoked-recovery"))
assert.equal(writes, writesBeforeRevokedGrant); assert.equal(settings["rp-filter"], before)
console.log("✓ Unsupported legacy autoRecovery cannot enroll a generic native writer or verified recovery; replay and revoked grant produce no writes")
} finally { Object.assign(restoreService, savedService); await new Promise<void>(resolve => recoveryChannelServer.close(() => resolve())) }
await pool.query("UPDATE mcp_connections SET owner_valid_until=now()-interval '1 second' WHERE id=$1", [limited.connection.id])
await assert.rejects(authenticateMcpToken(limited.token))
await revalidateMcpOwner(limited.connection.id, { ...actor, permissions: ["mm:mcp:read", "mm:servers:read"] })
const narrowed = await authenticateMcpToken(limited.token)
await assert.rejects(invokeMcpTool(narrowed, "mm_ip_settings_list", { serverId: 1 }))
console.log("✓ Owner claims expire; revalidation cannot preserve removed owner permissions")
const portalOwner: AuthUser = { ...actor, id: "portal-revoked-owner", issuedAt: Date.now() - 60000 }
const portalConnection = await createMcpConnection(input, portalOwner)
const event = { eventId: randomUUID(), userId: portalOwner.id, type: "permissions.changed" }
const timestamp = String(Math.floor(Date.now() / 1000)), raw = JSON.stringify(event)
process.env.MCP_PORTAL_WEBHOOK_SECRET = "integration-only-portal-secret-32-characters"
const signature = "sha256=" + createHmac("sha256", process.env.MCP_PORTAL_WEBHOOK_SECRET).update(timestamp + "." + raw).digest("hex")
const sendEvent = (body = raw, stamp = timestamp, sig = signature) => app!.inject({ method: "POST", url: "/_internal/mcp/portal/revocations", headers: { "content-type": "application/json", "x-mm-timestamp": stamp, "x-mm-signature": sig }, payload: body })
assert.equal((await sendEvent(raw + " ")).statusCode, 401)
assert.equal((await sendEvent(raw, String(Number(timestamp) - 600))).statusCode, 401)
assert.equal((await sendEvent()).statusCode, 200)
assert.equal((await sendEvent()).json().duplicate, true)
await assert.rejects(authenticateMcpToken(portalConnection.token))
await assert.rejects(createMcpConnection(input, portalOwner))
await assert.rejects(revalidateMcpOwner(portalConnection.connection.id, portalOwner))
const oldPortalJwt = app.jwt.sign({ sub: portalOwner.id, apps: ["mm"], permissions: actor.permissions, iss: "https://auth.shnt.top", iat: Number(timestamp) - 60, exp: Number(timestamp) + 1800 })
assert.equal((await app.inject({ method: "GET", url: "/api/mcp/connections", headers: { authorization: "Bearer " + oldPortalJwt } })).statusCode, 401)
const freshOwner = { ...portalOwner, issuedAt: (Number(timestamp) + 1) * 1000 }
const freshAccess = await createMcpConnection(input, freshOwner)
await authenticateMcpToken(freshAccess.token)
assert.equal((await pool.query("SELECT count(*)::int AS n FROM mcp_audit WHERE action='owner.revoke' AND payload->>'eventId'=$1", [event.eventId])).rows[0].n, 1)
delete process.env.MCP_PORTAL_WEBHOOK_SECRET
console.log("✓ Signed portal revocation: tamper/stale rejection, one atomic event, revoked credentials and stale-JWT regrant prevention")
await setConnectionStatus(issued.connection.id, "paused", actor)
await assert.rejects(authenticateMcpToken(rotated.token))
await setConnectionStatus(issued.connection.id, "active", actor)
await invalidateMcpAccess()
await assert.rejects(authenticateMcpToken(rotated.token))
console.log("✓ Immediate pause and external-generation invalidation")
await (await import("./native-conservation-acceptance.js")).acceptNativeConservation(actor)
await (await import("./native-create-id-acceptance.js")).acceptNativeCreateId(actor)
} finally {
await (await import("../../services/scheduler.js")).stopSchedulerForDatabaseOperation()
await (await import("../../services/traffic-flow-ingest.js")).stopTrafficFlowListenerForDatabaseOperation()
await app?.close()
await new Promise<void>((resolve, reject) => router.close(error => error ? reject(error) : resolve()))
await closePool()
}