Files
reverse-engineering-anything/src/artifacts/inventory/ArtifactGraphConstruction.test.ts
T
morluto e8da7e1edd fix(artifacts): share bounded ASAR signature observations
Parse Pickle extents once at the ASAR boundary and carry finalized signature
facts through root and nested classification. Scan JSON whitespace within its
declared extent and decode budget without retaining the whitespace prefix.
Keep prefix storage bounded independently of stream chunk ownership.

Fill fixed ASAR prefixes and DMG trailers across short reads, preserve
cancellation through admission and stream EOF, and retain existing cleanup
ownership. Cover public CLI/MCP selection, root/nested inventory, malformed
JSON whitespace and padding, limits, native/XML consumers and descriptor faults.

Validation: 24 focused files / 170 tests; full check; docs check; test discovery.
Official inert ASAR fixtures and controlled descriptor faults were exercised;
real Electron execution, Windows and natural OS short-read frequency remain
unverified. Equivalent compact CLI tasks returned identical results and reply
token estimates; repeated timings do not establish a speedup.

Fixes #3574
Fixes #5188
2026-10-19 14:32:48 +08:00

288 lines
9.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { CPU, fatImage, machoImage } from "../apple/MachoImage.fixture.js";
import {
createArtifactEdges,
createOccurrence,
indexOccurrencesByPath,
resolveOccurrenceParents,
} from "./ArtifactGraphConstruction.js";
import { artifactIdForContent } from "../../domain/artifactIdentity.js";
import type { ArtifactEntry } from "../ArtifactReader.js";
import { classifyArtifactBytesAtPath } from "../../../tests/fixtures/artifactClassification.js";
const entry = (path: string, kind: ArtifactEntry["kind"]): ArtifactEntry => ({
path,
kind,
declaredSize: null,
compressedSize: null,
executable: false,
encrypted: false,
byteOffset: null,
declaredSha256: null,
unpacked: false,
limitations: [],
adapterKey: path,
});
describe("occurrence parent ownership", () => {
it("selects the nearest unique nested parent", () => {
const outer = createOccurrence(entry("a", "directory"), "a", null);
const inner = createOccurrence(entry("a/b", "directory"), "a/b", null);
const file = createOccurrence(entry("a/b/file", "file"), "a/b/file", null);
const occurrences = [outer, inner, file];
resolveOccurrenceParents(
occurrences,
indexOccurrencesByPath(occurrences),
new Set(),
);
expect(file.parent_occurrence_id).toBe(inner.occurrence_id);
});
it("leaves a child unparented when duplicate directories make ownership ambiguous", () => {
const first = createOccurrence(entry("a", "directory"), "a", null, 0);
const second = createOccurrence(entry("a", "directory"), "a", null, 1);
const file = createOccurrence(entry("a/file", "file"), "a/file", null);
const occurrences = [first, second, file];
const resolution = resolveOccurrenceParents(
occurrences,
indexOccurrencesByPath(occurrences),
new Set(),
);
expect(file.parent_occurrence_id).toBeNull();
expect(resolution.unknownParentOccurrences.has(file)).toBe(true);
expect(resolution.limitations).toContain(
'The parent occurrence for "a/file" is unknown because multiple observed directory or container occurrences share "a".',
);
expect([first, second].map(({ hash_status }) => hash_status)).toEqual([
"unavailable",
"unavailable",
]);
});
});
describe("source-map artifact relationships", () => {
const contentId = (digit: string): string =>
artifactIdForContent(digit.repeat(64));
it.each([
["missing target", [] as string[], "contains"],
["unread target", ["unread"] as string[], "contains"],
["unique identified target", ["identified"] as string[], "maps-source"],
["duplicate targets", ["identified", "identified"] as string[], "contains"],
] as const)(
"uses a truthful edge for a %s",
(_label, targetIdentities, relation) => {
const directory = createOccurrence(
entry("app", "directory"),
"app",
null,
);
directory.artifact_id = contentId("1");
const targets = targetIdentities.map((identity, index) => {
const target = createOccurrence(
entry("app/main.js", "file"),
"app/main.js",
directory.occurrence_id,
index,
);
target.artifact_id = identity === "unread" ? null : contentId("2");
return target;
});
const sourceMap = createOccurrence(
entry("app/main.js.map", "file"),
"app/main.js.map",
directory.occurrence_id,
);
sourceMap.artifact_id = contentId("3");
const result = createArtifactEdges(contentId("4"), [
directory,
...targets,
sourceMap,
]);
const edge = result.edges.find(
({ occurrence_id }) => occurrence_id === sourceMap.occurrence_id,
);
expect(edge).toMatchObject({
relation,
parent_artifact_id:
relation === "maps-source" ? contentId("2") : contentId("1"),
occurrence_id: sourceMap.occurrence_id,
});
expect(result.limitations.length > 0).toBe(
(targetIdentities.length === 1 && targetIdentities[0] === "unread") ||
targetIdentities.length > 1,
);
},
);
it("keeps a directory named like a source map contained by its parent", () => {
const archive = createOccurrence(entry("app", "directory"), "app", null);
archive.artifact_id = contentId("1");
const script = createOccurrence(
entry("app/main.js", "file"),
"app/main.js",
archive.occurrence_id,
);
script.artifact_id = contentId("2");
const directory = createOccurrence(
entry("app/main.js.map", "directory"),
"app/main.js.map",
archive.occurrence_id,
);
directory.artifact_id = contentId("3");
const { edges, limitations } = createArtifactEdges(contentId("4"), [
archive,
script,
directory,
]);
expect(directory).toMatchObject({
artifact_kind: "container",
artifact_format: "directory",
});
expect(
edges.find(
({ occurrence_id }) => occurrence_id === directory.occurrence_id,
),
).toMatchObject({
relation: "contains",
parent_artifact_id: contentId("1"),
});
expect(limitations).toEqual([]);
});
});
const fat = (wide = false): Buffer =>
Buffer.from(fatImage([{ cpu: CPU.arm64, bytes: machoImage({}) }], wide));
describe("bounded FAT inventory classification", () => {
it("requires the complete table but not slice bytes in the retained prefix", () => {
const bytes = fat();
for (const length of [4, 7, 8, 27]) {
expect(
classifyArtifactBytesAtPath(
"native",
bytes.subarray(0, length),
bytes.length,
),
).toEqual({ kind: "unknown", format: "unknown" });
}
expect(
classifyArtifactBytesAtPath(
"native.class",
bytes.subarray(0, 28),
bytes.length,
),
).toEqual({ kind: "executable", format: "mach-o-universal" });
});
it.each([
["empty table", (bytes: Buffer) => bytes.writeUInt32BE(0, 4)],
["slice overlapping table", (bytes: Buffer) => bytes.writeUInt32BE(0, 16)],
["empty slice", (bytes: Buffer) => bytes.writeUInt32BE(0, 20)],
[
"slice beyond file",
(bytes: Buffer) => bytes.writeUInt32BE(bytes.length, 20),
],
["unaligned slice", (bytes: Buffer) => bytes.writeUInt32BE(4097, 16)],
["unsupported alignment", (bytes: Buffer) => bytes.writeUInt32BE(53, 24)],
] as const)("keeps %s unknown", (_label, mutate) => {
const bytes = fat();
mutate(bytes);
expect(classifyArtifactBytesAtPath("native", bytes)).toEqual({
kind: "unknown",
format: "unknown",
});
});
it("does not infer Mach-O from an out-of-bounds architecture count", () => {
const bytes = fat();
bytes.writeUInt32BE(0xffffffff, 4);
expect(classifyArtifactBytesAtPath("native", bytes)).toEqual({
kind: "resource",
format: "file",
});
});
it("does not lose unsafe FAT64 range values to number conversion", () => {
const bytes = fat(true);
bytes.writeBigUInt64BE(BigInt(Number.MAX_SAFE_INTEGER) + 1n, 16);
expect(classifyArtifactBytesAtPath("native", bytes)).toEqual({
kind: "unknown",
format: "unknown",
});
});
it("requires valid ranges for every declared slice", () => {
const bytes = Buffer.from(
fatImage([
{ cpu: CPU.arm64, bytes: machoImage({}) },
{ cpu: CPU.x86_64, bytes: machoImage({ cpu: CPU.x86_64 }) },
]),
);
bytes.writeUInt32BE(bytes.length, 40);
expect(classifyArtifactBytesAtPath("native", bytes)).toEqual({
kind: "unknown",
format: "unknown",
});
});
it("requires observed slice magic for an unknown CPU type", () => {
const cpu = { type: 0x12345678, subtype: 0 };
const bytes = Buffer.from(fatImage([{ cpu, bytes: machoImage({ cpu }) }]));
expect(
classifyArtifactBytesAtPath(
"native",
bytes.subarray(0, 28),
bytes.length,
),
).toEqual({ kind: "unknown", format: "unknown" });
expect(classifyArtifactBytesAtPath("native", bytes)).toEqual({
kind: "executable",
format: "mach-o-universal",
});
});
it.each([NaN, Infinity, -1, 8.5, Number.MAX_SAFE_INTEGER + 1, 27])(
"keeps invalid or contradictory file size %s unknown",
(size) => {
const bytes = fat();
expect(classifyArtifactBytesAtPath("native", bytes, size)).toEqual({
kind: "unknown",
format: "unknown",
});
},
);
});
it("preserves path-selected inventory roles for XML content", () => {
const xml = Buffer.from(
'<?xml version="1.0"?><plist version="1.0"><dict/></plist>',
);
expect(classifyArtifactBytesAtPath("state.archive", xml)).toEqual({
kind: "plist",
format: "plist",
});
expect(classifyArtifactBytesAtPath("state.js", xml)).toEqual({
kind: "javascript",
format: "javascript-bundle",
});
expect(classifyArtifactBytesAtPath("state.map", xml)).toEqual({
kind: "source-map",
format: "source-map",
});
expect(classifyArtifactBytesAtPath("state.asar", xml)).toEqual({
kind: "resource",
format: "file",
});
});