diff --git a/src/dotnet/ManagedStaticProvider.ts b/src/dotnet/ManagedStaticProvider.ts index d456455a20..eda9a5458f 100644 --- a/src/dotnet/ManagedStaticProvider.ts +++ b/src/dotnet/ManagedStaticProvider.ts @@ -23,6 +23,7 @@ import { AnalysisCancelledError, AnalysisCapabilityUnavailableError, AnalysisInputError, + AnalysisUnsupportedTargetError, } from "../domain/analysisErrorCore.js"; import { EvidenceIntegrityError } from "../domain/evidenceErrors.js"; import { ProviderAdapterError } from "../domain/providerAdapterError.js"; @@ -85,11 +86,13 @@ class ManagedStaticClient implements AnalysisClient { "Operation is not implemented by the managed static provider.", ), ); + // A non-PE target is outside this operation's formats, not a missing + // provider capability; the unimplemented-operation refusal above is. if (this.target.format !== "pe") return err( - new AnalysisCapabilityUnavailableError( - MANAGED_STATIC_PROVIDER.id, + new AnalysisUnsupportedTargetError( operation, + this.target.path, `Managed static triage requires a PE target; observed ${this.target.format}.`, ), ); diff --git a/tests/acceptance/managedCliOutput.test.ts b/tests/acceptance/managedCliOutput.test.ts index ed96e5eab7..cefb178e0f 100644 --- a/tests/acceptance/managedCliOutput.test.ts +++ b/tests/acceptance/managedCliOutput.test.ts @@ -3,6 +3,7 @@ import { join } from "node:path"; import { expect } from "vitest"; +import { elf, thinMach } from "../../src/domain/binaryTarget.fixture.js"; import { buildManagedPeFixture } from "../../src/dotnet/ManagedPe.fixture.js"; import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js"; import { cliTest } from "../support/cli/cliFixture.js"; @@ -418,3 +419,39 @@ cliTest( } }, ); + +cliTest( + "managed CLI refuses non-PE executables as unsupported targets", + async ({ cli }) => { + const root = await createTestTempDirectory("rea-managed-non-pe-"); + for (const [name, bytes, format] of [ + ["native.elf", elf(2, 1, 0x3e), "elf"], + ["native.macho", thinMach(0xfeedfacf, 0x01000007), "mach-o"], + ] as const) { + const path = join(root, name); + await writeFile(path, bytes); + for (const command of [ + "inspect-managed-artifact", + "inspect-managed-members", + "inspect-managed-native-boundaries", + ]) { + const result = await cli.run({ arguments: [command, path, "--json"] }); + expect(result.exitCode).not.toBe(0); + expect(result.json).toMatchObject({ + code: "unsupported_target", + category: "unsupported_target", + retryable: false, + remediation: { + action: + "Select a target supported by this operation or choose an operation supporting the reported target format.", + }, + details: { + operation: command.replaceAll("-", "_"), + path, + reason: `Managed static triage requires a PE target; observed ${format}.`, + }, + }); + } + } + }, +); diff --git a/tests/boundary/mcp/managedMcp.test.ts b/tests/boundary/mcp/managedMcp.test.ts index d2e414a55e..fb082fb72d 100644 --- a/tests/boundary/mcp/managedMcp.test.ts +++ b/tests/boundary/mcp/managedMcp.test.ts @@ -20,6 +20,7 @@ import { toolContract } from "../../../src/contracts/toolContracts.js"; import { ManagedStaticProvider } from "../../../src/dotnet/ManagedStaticProvider.js"; import { createServer } from "../../../src/server/createServer.js"; import { buildManagedPeFixture } from "../../../src/dotnet/ManagedPe.fixture.js"; +import { elf } from "../../../src/domain/binaryTarget.fixture.js"; type ManagedOutputAssertion = Awaited>; @@ -89,6 +90,20 @@ it("runs every managed static inspection independently of an active native targe arguments: { path: join(directory, "missing.dll") }, }); expect(invalidSelection.isError).toBe(true); + const nativePath = join(directory, "native.elf"); + await writeFile(nativePath, elf(2, 1, 0x3e)); + expect( + parseMcpToolError( + await client.callTool({ + name: "inspect_managed_artifact", + arguments: { path: nativePath }, + }), + ).error, + ).toMatchObject({ + code: "unsupported_target", + category: "unsupported_target", + details: { operation: "inspect_managed_artifact", path: nativePath }, + }); const members = structured( await client.callTool({ name: "inspect_managed_members", arguments: {} }), ); diff --git a/tests/boundary/providers/managed/managedStaticProvider.test.ts b/tests/boundary/providers/managed/managedStaticProvider.test.ts index eaabc9c30b..562dec2bd2 100644 --- a/tests/boundary/providers/managed/managedStaticProvider.test.ts +++ b/tests/boundary/providers/managed/managedStaticProvider.test.ts @@ -275,7 +275,12 @@ describe("managed static provider path boundary", () => { nativeClient.execute("inspect_managed_artifact", {}), ).resolves.toMatchObject({ ok: false, - error: { _tag: "AnalysisCapabilityUnavailableError" }, + error: { + _tag: "AnalysisUnsupportedTargetError", + operation: "inspect_managed_artifact", + path: parsed.value.path, + reason: "Managed static triage requires a PE target; observed elf.", + }, }); });