Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c76e981dcd |
No files matched your search
@@ -447,6 +447,16 @@ const artifactMessage = ({
|
||||
return `ASAR unpacked companion bytes are unavailable for ${details.logicalPath}. Select the archive in place with its .unpacked directory beside it, then retry.`;
|
||||
if (reason === "unavailable")
|
||||
return "Artifact processing is unavailable for the current target or host. Check artifact support and required tools.";
|
||||
// integrity_policy records only declared-versus-observed digest
|
||||
// contradictions, which carry their declared and observed facts. Container
|
||||
// self-verification (such as a DMG checksum) and source changes fail closed
|
||||
// under either policy, so offering a policy retry would be ineffective.
|
||||
if (
|
||||
reason === "integrity" &&
|
||||
details === undefined &&
|
||||
INTEGRITY_POLICY_OPERATIONS.has(operation)
|
||||
)
|
||||
return "Artifact failed an integrity check that integrity_policy cannot relax, such as a container checksum or a source that changed while being read. Get a valid, unchanged copy and try again.";
|
||||
if (reason === "integrity" && INTEGRITY_POLICY_OPERATIONS.has(operation))
|
||||
return `${
|
||||
details?.unpacked === true &&
|
||||
|
||||
@@ -22,6 +22,7 @@ import { createTestBinarySession } from "../../fixtures/binarySession.js";
|
||||
import { ArtifactProvider } from "../../../src/artifacts/ArtifactProvider.js";
|
||||
import { ARTIFACT_COMPARISON_EXAMPLE } from "../../../src/contracts/artifactComparisonExample.js";
|
||||
import { createServer } from "../../../src/server/createServer.js";
|
||||
import { execFileOutput } from "../../../src/process/ExecFileOutput.js";
|
||||
import { observed } from "../../fixtures/analysisExecution.js";
|
||||
|
||||
const integrityMessage = (unpacked: boolean): string =>
|
||||
@@ -104,6 +105,85 @@ it.each([
|
||||
20_000,
|
||||
);
|
||||
|
||||
it.skipIf(process.platform !== "darwin")(
|
||||
"does not offer an ineffective integrity-policy retry for a checksum-invalid DMG",
|
||||
async () => {
|
||||
const root = await createTestTempDirectory("rea-dmg-checksum-mcp-");
|
||||
const writableImagePath = join(root, "writable.dmg");
|
||||
const imagePath = join(root, "fixture.dmg");
|
||||
await execFileOutput("/usr/bin/hdiutil", [
|
||||
"create",
|
||||
"-quiet",
|
||||
"-size",
|
||||
"1m",
|
||||
"-layout",
|
||||
"NONE",
|
||||
"-type",
|
||||
"UDIF",
|
||||
writableImagePath,
|
||||
]);
|
||||
await execFileOutput("/usr/bin/hdiutil", [
|
||||
"convert",
|
||||
"-quiet",
|
||||
writableImagePath,
|
||||
"-format",
|
||||
"UDRO",
|
||||
"-o",
|
||||
imagePath,
|
||||
]);
|
||||
const image = await readFile(imagePath);
|
||||
const footer = image.subarray(-512);
|
||||
expect(footer.subarray(0, 4).toString("ascii")).toBe("koly");
|
||||
const corruptionOffset = Number(footer.readBigUInt64BE(24)) + 4096;
|
||||
const originalByte = image[corruptionOffset];
|
||||
if (originalByte === undefined)
|
||||
throw new Error("expected a byte in the generated image data fork");
|
||||
image[corruptionOffset] = originalByte ^ 0x01;
|
||||
await writeFile(imagePath, image);
|
||||
|
||||
const session = createTestBinarySession(new ArtifactProvider(process.env));
|
||||
const server = createServer({ kind: "session", session });
|
||||
const client = new Client({ name: "dmg-integrity-test", version: "1" });
|
||||
const [clientTransport, serverTransport] =
|
||||
InMemoryTransport.createLinkedPair();
|
||||
try {
|
||||
await server.connect(serverTransport);
|
||||
await client.connect(clientTransport);
|
||||
const opened = await client.callTool({
|
||||
name: "open_binary",
|
||||
arguments: { path: imagePath },
|
||||
});
|
||||
expect(opened.isError).not.toBe(true);
|
||||
|
||||
const message =
|
||||
"Artifact failed an integrity check that integrity_policy cannot relax, such as a container checksum or a source that changed while being read. Get a valid, unchanged copy and try again.";
|
||||
for (const integrity_policy of ["fail", "record-and-continue"]) {
|
||||
const result = await client.callTool({
|
||||
name: "inspect_artifact",
|
||||
arguments: { integrity_policy },
|
||||
});
|
||||
expect(result.isError).toBe(true);
|
||||
expect(parseMcpToolError(result)).toMatchObject({
|
||||
error: {
|
||||
code: "artifact_operation_failed",
|
||||
category: "integrity_mismatch",
|
||||
message,
|
||||
retryable: false,
|
||||
remediation: { action: message },
|
||||
},
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
await Promise.allSettled([
|
||||
client.close(),
|
||||
server.close(),
|
||||
session.close(),
|
||||
]);
|
||||
}
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
|
||||
it("extracts an active archive through MCP when requested", async () => {
|
||||
const root = await createTestTempDirectory("rea-artifact-extract-mcp-");
|
||||
const archive = join(root, "fixture.zip");
|
||||
|
||||
Reference in new issue
Block a user