mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(artifacts): stop offering integrity-policy retries for checksum-invalid DMGs
integrity_policy=record-and-continue only records declared-versus-observed digest contradictions, which carry declared and observed facts. Integrity failures without those facts, such as hdiutil checksum verification, fail closed under either policy, so the policy retry advice could never succeed. Explain the limitation and recommend a valid copy instead. Fixes #5549 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
080c0e2b2b
commit
c76e981dcd
2 files changed
+90
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