Files
reverse-engineering-anything/src/firmware/FirmwareCommand.test.ts
T
Kaoru0822andClaude Opus 5.5 170d0bf9e2 fix: name host and tool requirements in optional adapter refusals
Host and tool-configuration refusals from the pwntools, EVMole, firmware,
mitmproxy, Wakaru, LLDB and xcrun adapters carried no userMessage, so CLI
and MCP callers saw the generic "This analysis is unavailable for the
current target. Choose another analysis or target." as both message and
remediation. Choosing another target cannot satisfy a Linux-only profile
or an unset REA_*_COMMAND. The actual requirement appeared only in
details.reason.

Pass each refusal's reason as its userMessage, as the adapters' other
configuration refusals (EVMole limits, JADX, pwndbg) already do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:12:25 +00:00

102 lines
3.2 KiB
TypeScript

import { chmod, mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it as test } from "vitest";
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
import { AnalysisCapabilityUnavailableError } from "../domain/analysisErrorCore.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import { resolveFirmwareCommand } from "./FirmwareCommand.js";
const it = test.skipIf(process.platform !== "linux");
test("names the host and tool requirement of an unconfigured engine", async () => {
const refusal: unknown = await resolveFirmwareCommand(
{},
"binwalk",
"inspect_firmware_regions",
).catch((cause: unknown) => cause);
expect(refusal).toMatchObject({
_tag: "AnalysisCapabilityUnavailableError",
});
if (!(refusal instanceof AnalysisCapabilityUnavailableError))
throw new Error("Expected a capability refusal");
expect(projectAnalysisError(refusal)).toMatchObject({
code: "capability_unavailable",
message: refusal.reason,
remediation: { action: refusal.reason },
});
expect(refusal.reason).toContain("REA_BINWALK_COMMAND");
});
it("rejects a directory configured as the firmware engine executable", async () => {
const root = await createTestTempDirectory("rea-firmware-command-");
const command = join(root, "binwalk");
const limiter = await executableFixture(root, "prlimit");
await mkdir(command);
await expect(
resolveFirmwareCommand(
{
REA_BINWALK_COMMAND: command,
REA_FIRMWARE_PRLIMIT_COMMAND: limiter,
},
"binwalk",
"inspect_firmware_regions",
),
).rejects.toMatchObject({
_tag: "AnalysisCapabilityUnavailableError",
reason: expect.stringContaining(command),
});
});
it("classifies an unusable firmware engine as an unavailable capability", async () => {
const root = await createTestTempDirectory("rea-firmware-command-");
const command = join(root, "binwalk");
const limiter = await executableFixture(root, "prlimit");
await writeFile(command, "not executable", { mode: 0o600 });
await expect(
resolveFirmwareCommand(
{
REA_BINWALK_COMMAND: command,
REA_FIRMWARE_PRLIMIT_COMMAND: limiter,
},
"binwalk",
"inspect_firmware_regions",
),
).rejects.toMatchObject({
_tag: "AnalysisCapabilityUnavailableError",
reason: expect.stringContaining(command),
});
});
it("rejects a directory configured as the resource limiter executable", async () => {
const root = await createTestTempDirectory("rea-firmware-limiter-");
const command = await executableFixture(root, "binwalk");
const limiter = join(root, "prlimit");
await mkdir(limiter);
await expect(
resolveFirmwareCommand(
{
REA_BINWALK_COMMAND: command,
REA_FIRMWARE_PRLIMIT_COMMAND: limiter,
},
"binwalk",
"inspect_firmware_regions",
),
).rejects.toMatchObject({
_tag: "AnalysisCapabilityUnavailableError",
reason: expect.stringContaining(limiter),
});
});
const executableFixture = async (root: string, name: string) => {
const path = join(root, name);
await writeFile(path, "#!/bin/sh\n");
await chmod(path, 0o700);
return path;
};