Files
reverse-engineering-anything/src/artifacts/ArtifactEmbeddedFormatProbes.test.ts
T
morluto 7134053d27 feat(artifacts): name integrity checks for DMG, directory and release-exposure readers (#11056)
* feat(artifacts): name integrity checks for DMG, directory and release-exposure readers

Directory members and release-exposure members whose file identity or
bytes changed since inventory report member-identity; a directory entry
without captured state reports entry-metadata and a changed directory root
container-identity; an hdiutil checksum failure reports image-checksum.
AnalysisArtifactChangedError carries the check from the reader failure and
projects it as details.integrity_check.

* fix(artifacts): name missing directory entry state and keep integrity checks through error copies

* feat(artifacts): name integrity checks for ZIP, PyInstaller and changed release files (#11081)

feat(artifacts): name integrity checks for ZIP, PyInstaller and changed release files, and keep them through reader projections

* feat(artifacts): name integrity checks for the remaining readers and their projections (#11098)
2026-11-15 20:35:28 +08:00

262 lines
9.6 KiB
TypeScript

import { appendFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it, vi } from "vitest";
import { createTestTempDirectory } from "../../tests/fixtures/temporaryDirectory.js";
import { withOwnedRegularFile } from "../filesystem/OwnedRegularFile.js";
import { ArtifactEmbeddedFormatProbes } from "./ArtifactEmbeddedFormatProbes.js";
import * as dotnetLayout from "./dotnet/DotnetBundle.js";
import { dotnetBundleFixture } from "./dotnet/DotnetBundle.fixture.js";
import { denoMachO } from "./deno/DenoStandalone.fixture.js";
import * as denoLocation from "./deno/DenoStandaloneLocation.js";
import * as pckLocation from "./GodotPckLocation.js";
import { resolveArtifactReaderLimits } from "../domain/artifactReaderLimits.js";
import { nodeSeaElf } from "./nodeSea/NodeSea.fixture.js";
it("readmits cached SEA recognition when the accepted policy changes", async () => {
const path = join(
await createTestTempDirectory("rea-probe-policy-"),
"carrier",
);
await writeFile(path, nodeSeaElf({ fuse: "set", ownership: "section" }));
await withOwnedRegularFile(path, {}, async (source) => {
const original = new ArtifactEmbeddedFormatProbes(path, source);
const location = await original.nodeSea();
expect(location).toBeDefined();
const lower = new ArtifactEmbeddedFormatProbes(
path,
source,
undefined,
original.completedFacts(),
resolveArtifactReaderLimits({ node_sea: { blob_bytes: 1 } }),
);
await expect(lower.nodeSea()).rejects.toMatchObject({
reason: "limit",
readerLimit: {
parameter: "artifact_limits.node_sea.blob_bytes",
effective_value: 1,
},
});
expect(Object.hasOwn(lower.completedFacts(), "nodeSea")).toBe(false);
const restored = new ArtifactEmbeddedFormatProbes(
path,
source,
undefined,
lower.completedFacts(),
resolveArtifactReaderLimits(),
);
expect(await restored.nodeSea()).toEqual(location);
const recognitionLimited = new ArtifactEmbeddedFormatProbes(
path,
source,
undefined,
restored.completedFacts(),
resolveArtifactReaderLimits({
node_sea: { recognition_header_count: 1 },
}),
);
await expect(recognitionLimited.nodeSea()).resolves.toBeUndefined();
expect(Object.hasOwn(recognitionLimited.completedFacts(), "nodeSea")).toBe(
false,
);
expect(
recognitionLimited.completedFacts().nodeSeaRecognitionFailure,
).toMatchObject({
readerLimit: {
parameter: "artifact_limits.node_sea.recognition_header_count",
effective_value: 1,
required_value: 3,
},
});
const recognitionRestored = new ArtifactEmbeddedFormatProbes(
path,
source,
undefined,
recognitionLimited.completedFacts(),
resolveArtifactReaderLimits({
node_sea: { recognition_header_count: 3 },
}),
);
expect(await recognitionRestored.nodeSea()).toEqual(location);
expect(
recognitionRestored.completedFacts().nodeSeaRecognitionFailure,
).toBeUndefined();
});
});
it("distinguishes examined absence from unexamined formats and honors cancellation on a cached result", async () => {
const root = await createTestTempDirectory("rea-embedded-probe-facts-");
const path = join(root, "plain");
await writeFile(path, "plain bytes without an embedded archive");
const locate = vi.spyOn(pckLocation, "locateGodotPck");
try {
await withOwnedRegularFile(path, {}, async (source) => {
const controller = new AbortController();
const probes = new ArtifactEmbeddedFormatProbes(
path,
source,
controller.signal,
);
await expect(probes.godotPck()).resolves.toBeUndefined();
const facts = probes.completedFacts();
expect(facts.godotPck).toBeNull();
expect(Object.hasOwn(facts, "nodeSea")).toBe(false);
expect(Object.hasOwn(facts, "denoStandalone")).toBe(false);
expect(Object.hasOwn(facts, "pyInstaller")).toBe(false);
const resumed = new ArtifactEmbeddedFormatProbes(
path,
source,
controller.signal,
facts,
);
await expect(resumed.godotPck()).resolves.toBeUndefined();
expect(locate).toHaveBeenCalledTimes(1);
const reason = new Error("cancel cached observation");
controller.abort(reason);
await expect(resumed.godotPck()).rejects.toMatchObject({
reason: "cancelled",
cause: reason,
});
expect(locate).toHaveBeenCalledTimes(1);
});
} finally {
locate.mockRestore();
}
});
it("leaves a failed probe unexamined so a subsequent successful observation can be retained", async () => {
const root = await createTestTempDirectory("rea-embedded-probe-failure-");
const path = join(root, "plain");
await writeFile(path, "plain bytes without an embedded archive");
const failure = Object.assign(new Error("injected read failure"), {
code: "EIO",
});
const locate = vi
.spyOn(pckLocation, "locateGodotPck")
.mockRejectedValueOnce(failure);
try {
await withOwnedRegularFile(path, {}, async (source) => {
const probes = new ArtifactEmbeddedFormatProbes(path, source);
await expect(probes.godotPck()).rejects.toBe(failure);
expect(Object.hasOwn(probes.completedFacts(), "godotPck")).toBe(false);
await expect(probes.godotPck()).resolves.toBeUndefined();
expect(probes.completedFacts().godotPck).toBeNull();
expect(locate).toHaveBeenCalledTimes(2);
});
} finally {
locate.mockRestore();
}
});
it("reuses a located .NET header only for the same source and honors cached cancellation", async () => {
const root = await createTestTempDirectory("rea-dotnet-probe-facts-");
const path = join(root, "host");
const fixture = dotnetBundleFixture();
await writeFile(path, fixture.bytes);
const locate = vi.spyOn(dotnetLayout, "findDotnetBundleHeader");
try {
const facts = await withOwnedRegularFile(path, {}, async (source) => {
const controller = new AbortController();
const first = new ArtifactEmbeddedFormatProbes(
path,
source,
controller.signal,
);
expect(
Object.hasOwn(first.completedFacts(), "dotnetBundleHeaderOffset"),
).toBe(false);
await expect(first.dotnetBundle()).resolves.toBe(fixture.headerOffset);
const completed = first.completedFacts();
const resumed = new ArtifactEmbeddedFormatProbes(
path,
source,
controller.signal,
completed,
);
await expect(resumed.dotnetBundle()).resolves.toBe(fixture.headerOffset);
expect(locate).toHaveBeenCalledTimes(1);
const reason = new Error("cancel cached .NET observation");
controller.abort(reason);
await expect(resumed.dotnetBundle()).rejects.toMatchObject({
reason: "cancelled",
cause: reason,
});
return completed;
});
await appendFile(path, "changed");
await withOwnedRegularFile(path, {}, async (source) => {
expect(
() => new ArtifactEmbeddedFormatProbes(path, source, undefined, facts),
).toThrow(
expect.objectContaining({
reason: "integrity",
integrityCheck: "container-identity",
}),
);
});
expect(locate).toHaveBeenCalledTimes(1);
} finally {
locate.mockRestore();
}
});
it("keeps a failed .NET probe unexamined before a successful absence observation", async () => {
const root = await createTestTempDirectory("rea-dotnet-probe-retry-");
const path = join(root, "plain");
await writeFile(path, "plain bytes");
const failure = new Error("injected marker read failure");
const locate = vi
.spyOn(dotnetLayout, "findDotnetBundleHeader")
.mockRejectedValueOnce(failure);
try {
await withOwnedRegularFile(path, {}, async (source) => {
const probes = new ArtifactEmbeddedFormatProbes(path, source);
await expect(probes.dotnetBundle()).rejects.toBe(failure);
expect(
Object.hasOwn(probes.completedFacts(), "dotnetBundleHeaderOffset"),
).toBe(false);
await expect(probes.dotnetBundle()).resolves.toBeUndefined();
expect(probes.completedFacts().dotnetBundleHeaderOffset).toBeNull();
expect(locate).toHaveBeenCalledTimes(2);
});
} finally {
locate.mockRestore();
}
});
it("caches a present Deno section and records examined absence", async () => {
const root = await createTestTempDirectory("rea-deno-probe-facts-");
const presentPath = join(root, "deno");
const absentPath = join(root, "plain");
await writeFile(presentPath, denoMachO());
await writeFile(absentPath, "plain bytes without a Deno section");
const locate = vi.spyOn(denoLocation, "locateDenoStandalone");
try {
await withOwnedRegularFile(presentPath, {}, async (source) => {
const probes = new ArtifactEmbeddedFormatProbes(presentPath, source);
expect(Object.hasOwn(probes.completedFacts(), "denoStandalone")).toBe(
false,
);
const found = await probes.denoStandalone();
expect(found.status).toBe("present");
await expect(probes.denoStandalone()).resolves.toBe(found);
expect(locate).toHaveBeenCalledTimes(1);
});
await withOwnedRegularFile(absentPath, {}, async (source) => {
const probes = new ArtifactEmbeddedFormatProbes(absentPath, source);
expect(Object.hasOwn(probes.completedFacts(), "denoStandalone")).toBe(
false,
);
await expect(probes.denoStandalone()).resolves.toEqual({
status: "absent",
});
expect(probes.completedFacts().denoStandalone).toEqual({
status: "absent",
});
});
} finally {
locate.mockRestore();
}
});