fix(hopper): keep the OS error when the FAT64 source cannot be reopened
resolveHopperMachOImage built its BinaryTargetError without the open failure as its cause, so a target that became unreadable after admission still projected as `target_unavailable` instead of `access_denied`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d0ff57a45c
commit
9f5dc52be8
|
|
@ -0,0 +1,37 @@
|
|||
import { chmod, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
|
||||
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
|
||||
import { resolveHopperMachOImage } from "./HopperMachOImage.js";
|
||||
|
||||
it.skipIf(process.platform === "win32" || process.getuid?.() === 0)(
|
||||
"reports a FAT64 source that became unreadable as a host read denial",
|
||||
async () => {
|
||||
const directory = await createTestTempDirectory("rea-hopper-fat64-");
|
||||
const path = join(directory, "universal");
|
||||
await writeFile(path, Buffer.alloc(64));
|
||||
await chmod(path, 0);
|
||||
try {
|
||||
const result = await resolveHopperMachOImage({
|
||||
path,
|
||||
sha256: "0".repeat(64),
|
||||
kind: "executable",
|
||||
format: "mach-o",
|
||||
architecture: "arm64",
|
||||
availableArchitectures: ["arm64"],
|
||||
});
|
||||
expect(result.ok).toBe(false);
|
||||
if (result.ok) return;
|
||||
expect(result.error).toMatchObject({ systemCode: "EACCES" });
|
||||
expect(projectAnalysisError(result.error)).toMatchObject({
|
||||
code: "access_denied",
|
||||
details: { path, system_code: "EACCES" },
|
||||
});
|
||||
} finally {
|
||||
await chmod(path, 0o600);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
@ -35,15 +35,23 @@ export const resolveHopperMachOImage = async (
|
|||
): Promise<
|
||||
Result<HopperMachOImage, BinaryTargetError | AnalysisCancelledError>
|
||||
> => {
|
||||
const invalid = (reason: string) =>
|
||||
err(new BinaryTargetError(target.path, reason));
|
||||
const invalid = (reason: string, cause?: unknown) =>
|
||||
err(
|
||||
new BinaryTargetError(
|
||||
target.path,
|
||||
reason,
|
||||
cause === undefined ? undefined : { cause },
|
||||
),
|
||||
);
|
||||
if (signal?.aborted) return err(new AnalysisCancelledError("open_binary"));
|
||||
let file: FileHandle;
|
||||
try {
|
||||
file = await open(target.path, "r");
|
||||
} catch (cause: unknown) {
|
||||
// Keep the OS error so a read-permission denial reports access_denied.
|
||||
return invalid(
|
||||
`Cannot read FAT64 source for Hopper image preparation: ${cause instanceof Error ? cause.message : String(cause)}`,
|
||||
cause,
|
||||
);
|
||||
}
|
||||
try {
|
||||
|
|
|
|||
Loading…
Reference in New Issue