fix(artifacts): preserve mounted DMG traversal coverage

This commit is contained in:
morluto committed 2026-10-27 10:03:15 +08:00
1 parent 2146caeb3d
commit 650873e772
2 files changed
+84 -1

No files matched your search

+1
View File
@@ -202,6 +202,7 @@ export class NativeDmgArtifactReader implements ArtifactReader {
const prefix = basename(this.path);
const entries = directory
.entries(signal, {
onCoverage: (coverage) => options?.onCoverage?.(coverage),
onOmission: (omission) =>
options?.onOmission?.({
...omission,
+83 -1
View File
@@ -1,13 +1,95 @@
import { ExecFileOutputCancelledError } from "../process/ExecFileOutput.js";
import { ArtifactReaderFailure } from "./ArtifactReader.js";
import { build } from "plist";
import { expect, it } from "vitest";
import { expect, it, vi } from "vitest";
import {
NativeDmgArtifactReader,
type NativeDmgHost,
} from "./NativeDmgArtifactReader.js";
import { translateArtifactFailure } from "./ArtifactOperationFailure.js";
import { projectAnalysisError } from "../domain/analysisErrorProjection.js";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import type { ArtifactReaderTraversal } from "./ArtifactReader.js";
import { DirectoryArtifactReader } from "./DirectoryArtifactReader.js";
it.skipIf(process.platform === "win32").each([false, true])(
"preserves mounted-directory coverage alongside readable DMG entries (unknown coverage: %s)",
async (unknownCoverage) => {
let mountPoint: string | undefined;
const coverage: ArtifactReaderTraversal[] = [];
const producerCoverage: ArtifactReaderTraversal = {
status: "unknown",
examinedEntries: 3,
limitations: [
"Directory contains an entry name that is not valid UTF-8.",
],
};
// APFS rejects invalid UTF-8 basenames at creation. Inject the directory
// owner's completed observation while retaining its real entry traversal.
const entries = DirectoryArtifactReader.prototype.entries;
const traversal = vi
.spyOn(DirectoryArtifactReader.prototype, "entries")
.mockImplementation(async function* (
this: DirectoryArtifactReader,
signal,
options,
) {
yield* entries.call(this, signal, options);
if (unknownCoverage && typeof options !== "function")
options?.onCoverage?.(producerCoverage);
});
const host: NativeDmgHost = {
run: async (args) => {
if (args[0] === "verify" || args[0] === "detach")
return { stdout: "", exitCode: 0 };
if (args[0] === "attach") {
const root = args[args.indexOf("-mountroot") + 1];
if (root === undefined) throw new Error("Missing mount root");
mountPoint = join(root, "Volume");
await mkdir(mountPoint);
await writeFile(join(mountPoint, "readable.txt"), "visible");
}
if (args[0] === "info" || args[0] === "attach") {
const entities =
mountPoint === undefined
? []
: [{ "dev-entry": "/dev/disk800", "mount-point": mountPoint }];
return {
stdout: build(
args[0] === "info"
? {
images:
entities.length === 0
? []
: [{ "system-entities": entities }],
}
: { "system-entities": entities },
),
exitCode: 0,
};
}
throw new Error(`Unexpected command ${String(args[0])}`);
},
};
const reader = new NativeDmgArtifactReader("/fixture/image.dmg", {}, host);
const paths: string[] = [];
try {
for await (const entry of reader.entries(undefined, {
onCoverage: (value) => coverage.push(value),
}))
paths.push(entry.path);
expect(paths).toContain("image.dmg/Volume/readable.txt");
expect(coverage).toEqual(unknownCoverage ? [producerCoverage] : []);
} finally {
try {
await reader.close();
} finally {
traversal.mockRestore();
}
}
},
);
it("retains malformed successful hdiutil inventory output as a typed producer parse failure before attach", async () => {
const calls: string[] = [];