Files

124 lines
5.7 KiB
TypeScript

import assert from "node:assert/strict"
import test from "node:test"
import {
createEnterpriseMcpMockServer,
createFaultScenario,
listFaultDefinitions,
probeEnterpriseMcpMockServer,
scenarioSchema,
} from "../src/index.js"
const oauthClientSecret = "synthetic-test-client-secret-32-bytes"
const hostileGatewayCases = [
{ faultId: "redirect-uri-whitelist", snippet: "redirect URI is not an allowed destination" },
{ faultId: "per-connector-redirect", snippet: "External MCP connect callback token exchange failed" },
{ faultId: "dcr-required", snippet: "The MCP connection failed before OpenWork could complete the protocol lifecycle" },
{ faultId: "method-405", snippet: "HTTP 405" },
{ faultId: "duplicate-amplification", snippet: "duplicate requests" },
{ faultId: "refresh-expired", snippet: "refresh token expired" },
{ faultId: "trailing-dot-url", snippet: "trailing-dot URL" },
{ faultId: "per-user-403", snippet: "Authorization with MCP server failed — check your credentials and permissions" },
]
test("hostile gateway fault catalog advertises every required selectable case", () => {
const faultIds = new Set(listFaultDefinitions().map((fault) => fault.id))
assert.deepEqual(hostileGatewayCases.map((fault) => fault.faultId).filter((faultId) => !faultIds.has(faultId)), [])
})
test("hostile gateway probes preserve the required safe evidence strings", async (context) => {
for (const { faultId, snippet } of hostileGatewayCases) {
await context.test(faultId, async () => {
const scenario = createFaultScenario("servicenow-inbound-quickstart", faultId)
const server = createEnterpriseMcpMockServer({ scenario, secrets: { oauthClientSecret } })
await server.start()
try {
const result = await probeEnterpriseMcpMockServer({
baseUrl: server.baseUrl,
scenario,
credentials: { clientSecret: oauthClientSecret },
})
assert.equal(result.ok, true, result.error?.messageSafe)
assert.match(result.error?.messageSafe ?? "", new RegExp(snippet.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")))
} finally {
await server.stop()
}
})
}
})
test("every advertised fault is observed at its actual first phase and leaves bounded state", async (context) => {
for (const fault of listFaultDefinitions()) {
for (const profileId of fault.applicableProfiles) {
await context.test(`${fault.id} / ${profileId}`, async () => {
const scenario = createFaultScenario(profileId, fault.id)
const server = createEnterpriseMcpMockServer({ scenario, secrets: { oauthClientSecret } })
await server.start()
try {
const result = await probeEnterpriseMcpMockServer({
baseUrl: server.baseUrl,
scenario,
credentials: { clientSecret: oauthClientSecret },
})
assert.equal(result.ok, true, `${fault.id} / ${profileId}: ${result.error?.messageSafe ?? "unexpected success"}`)
assert.equal(result.observed.outcome, "failure")
assert.equal(result.observed.firstFailedPhase, fault.phase)
assert.equal(result.observed.category, fault.category)
assert.equal(server.snapshot().counts.sessions, 0)
const events = server.events()
const appliedIndex = events.findIndex((event) => event.kind === "fault" && event.details.faultId === fault.id)
assert.notEqual(appliedIndex, -1, `${fault.id} did not emit its safe fault event`)
assert.equal(
events.slice(appliedIndex + 1).some((event) => event.phase === fault.phase && event.outcome === "passed"),
false,
`${fault.id} emitted a contradictory passed event after the fault was applied`,
)
} finally {
await server.stop()
}
})
}
}
})
test("probe cannot pass by copying expected fault metadata", async () => {
const serverScenario = createFaultScenario("synthetic-enterprise-oauth-mcp", "mcp-wrong-content-type")
const claimedScenario = createFaultScenario("synthetic-enterprise-oauth-mcp", "mcp-version-unsupported")
const server = createEnterpriseMcpMockServer({ scenario: serverScenario, secrets: { oauthClientSecret } })
await server.start()
try {
const result = await probeEnterpriseMcpMockServer({ baseUrl: server.baseUrl, scenario: claimedScenario })
assert.equal(result.ok, false)
assert.equal(result.observed.firstFailedPhase, "MCP_TRANSPORT")
assert.equal(result.observed.category, "mcp_transport")
assert.notEqual(result.observed.firstFailedPhase, claimedScenario.expected.firstFailedPhase)
} finally {
await server.stop()
}
})
test("probe refuses non-loopback targets before sending any request", async () => {
const scenario = createFaultScenario("synthetic-enterprise-oauth-mcp", "mcp-version-unsupported")
await assert.rejects(
probeEnterpriseMcpMockServer({ baseUrl: "https://example.com", scenario }),
/literal loopback/,
)
})
test("once-triggered cursor and duplicate faults are consumed only when their effect is reachable", async () => {
for (const faultId of ["mcp-catalog-cursor-loop", "mcp-duplicate-tool"] as const) {
const base = createFaultScenario("synthetic-enterprise-oauth-mcp", faultId)
const scenario = scenarioSchema.parse({
...base,
activeFault: { id: faultId, trigger: { occurrence: "once" } },
})
const server = createEnterpriseMcpMockServer({ scenario, secrets: { oauthClientSecret } })
await server.start()
try {
const result = await probeEnterpriseMcpMockServer({ baseUrl: server.baseUrl, scenario })
assert.equal(result.ok, true, `${faultId}: ${result.error?.messageSafe ?? "unexpected success"}`)
} finally {
await server.stop()
}
}
})