Files
reverse-engineering-anything/tests/acceptance/artifactClassification.test.ts
T
morluto 60149282fc test: strengthen integration oracles and verification (#8295)
* test: strengthen integration oracles and verification

* test: bound lifecycle gates and strengthen workflow checks

* test: verify complete paged and extracted results

* test: preserve bytecode and cancellation evidence

* test: strengthen retained evidence and fixture cleanup

* test: require cross-projection bridge identities

* test: retain fixture owners through cleanup failures

* test: verify graph examples and project selectors

* test: tighten provider and lifecycle regressions

* test: consolidate hex coverage and bound cutter cleanup

* test: bound subprocess output waits and strengthen graph checks

* test: check mcp recovery and preserve cleanup owners

* test: verify structured mcp argument failures

* test: preserve artifact cleanup and gdb limit evidence

* test: preserve evidence identities and bound provider gates

* test: retain browser and comparison cleanup owners

* test: bound startup and strengthen fixture oracles

* test: bound lifecycle gates and verify recovered evidence

* test: verify public outcomes and lifecycle ownership

* test: assert precise evidence and release lifecycle gates

* test: verify selected facts and bound cleanup waits

* test: check retained evidence and decoded records

* test: verify final reports and retain cleanup ownership

* test: bound reviewed startup gates and retain cleanup

* test: verify PE errors and preserve MCP cleanup

* test: preserve MCP fixture cleanup ownership

* test: release provider gates before late startup
2026-11-01 00:15:28 +08:00

112 lines
4.1 KiB
TypeScript

import { createHash } from "node:crypto";
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { Uint8ArrayReader, Uint8ArrayWriter, ZipWriter } from "@zip.js/zip.js";
import { expect } from "vitest";
import {
CPU,
fatImage,
machoImage,
} from "../../src/artifacts/apple/MachoImage.fixture.js";
import { artifactInventoryResultSchema } from "../../src/domain/artifactGraph.js";
import { artifactInspectionResultSchema } from "../../src/domain/artifactInspection.js";
import { parseEvidence } from "../../src/domain/evidence.js";
import { javaClassFile } from "../fixtures/javaClassFile.js";
import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js";
import { cliTest } from "../support/cli/cliFixture.js";
cliTest.for(["jar", "zip"])(
"distinguishes JVM classes from universal Mach-O files in %s inventory",
async (extension, { cli }) => {
const root = await createTestTempDirectory("rea-class-inventory-");
// The large class can hold the entire 65-entry table suggested by its
// version bytes. Checking only the table length does not distinguish it.
const classes = [
["Hello.class", javaClassFile()],
["pkg/Big.class", javaClassFile(4_000)],
["renamed.bin", javaClassFile()],
] as const;
const nativeEntries: [string, Uint8Array][] = [];
for (const wide of [false, true]) {
for (const littleEndian of [false, true]) {
nativeEntries.push([
`fat${wide ? 64 : 32}-${littleEndian ? "le" : "be"}`,
fatImage(
[{ cpu: CPU.arm64, bytes: machoImage({ cpu: CPU.arm64 }) }],
wide,
littleEndian,
),
]);
}
}
// Exercise a JAR without FAT controls as well as mixed JAR and ZIP files.
const scenarios = extension === "jar" ? [false, true] : [true];
for (const includeNative of scenarios) {
const path = join(
root,
`${includeNative ? "mixed" : "classes"}.${extension}`,
);
const selectedClasses = includeNative ? classes : classes.slice(0, 2);
const writer = new ZipWriter(new Uint8ArrayWriter());
if (!includeNative)
await writer.add(
"META-INF/MANIFEST.MF",
new Uint8ArrayReader(Buffer.from("Manifest-Version: 1.0\n\n")),
);
for (const [name, bytes] of [
...selectedClasses,
...(includeNative ? nativeEntries : []),
])
await writer.add(name, new Uint8ArrayReader(bytes));
await writeFile(path, await writer.close());
const reply = await cli.run({
arguments: ["inspect-artifact", path, "--json"],
});
expect(reply.exitCode, reply.stdout + reply.stderr).toBe(0);
const inspection = artifactInspectionResultSchema.parse(
parseEvidence(reply.json).normalized_result,
);
const inventory = artifactInventoryResultSchema.parse(
inspection.substeps[0]?.evidence.normalized_result,
);
expect(
inventory.occurrences
.filter(({ logical_path }) => logical_path.endsWith(".class"))
.map(({ logical_path }) => logical_path),
).toEqual(["Hello.class", "pkg/Big.class"]);
if (includeNative) {
for (const [name] of nativeEntries) {
expect(inventory.occurrences).toContainEqual(
expect.objectContaining({
logical_path: name,
artifact_kind: "executable",
artifact_format: "mach-o-universal",
limitations: [],
}),
);
}
}
for (const [name, bytes] of selectedClasses) {
const occurrence = inventory.occurrences.find(
(item) => item.logical_path === name,
);
expect(occurrence, name).toMatchObject({
artifact_kind: "resource",
artifact_format: "file",
});
const node = inventory.nodes.find(
(item) => item.artifact_id === occurrence?.artifact_id,
);
expect(node, name).toMatchObject({
format: "file",
sha256: createHash("sha256").update(bytes).digest("hex"),
});
}
}
},
);