Files
rea/tests/boundary/filesystem/keyedArchiveNumberMetadata.test.ts
T
Shreyash Patange f5410bdc4c fix(apple): keep scalar facts when object-table entries share a record (#5806)
Binary plist object tables may list one object offset more than once;
plistlib reads each entry independently. The scalar scanner marked any
repeated offset as incomplete metadata, which made the number projection
drop every exact decimal in the archive. A keyed archive whose entries
10 and 11 share an Int64 9007199254740993 reported both as observed
9007199254740992 and rounded an unrelated 2^60+3 sibling, with only the
generic incomplete-metadata caveat.

A repeated valid offset carries the same source facts as its first
visit, so observe it once and continue. Offsets that fail to parse still
mark metadata incomplete. Shared 16-byte integers and dates are rewritten
once in the decoder copy, which every entry then reads; the overlap plan
already treats one shared offset as one span. Keyed archives and
Interface Builder decoding share this scanner.
2026-10-21 17:51:24 +08:00

160 lines
5.0 KiB
TypeScript

import { readFile } from "node:fs/promises";
import { expect, it } from "vitest";
import { inspectBundleKeyedArchive } from "../../../src/artifacts/apple/KeyedArchiveReader.js";
import { parseEvidence } from "../../../src/domain/evidence.js";
import {
keyedArchiveSharedEntryFixture,
keyedArchiveWideIntegerFixture,
} from "../../fixtures/keyedArchiveWideIntegers.js";
import {
archiveNumberMetadataCases,
expectKeyedArchiveNumberMetadata,
keyedArchiveNumberMetadataFixture,
} from "../../fixtures/keyedArchiveNumberMetadata.js";
import { cliTest } from "../../support/cli/cliFixture.js";
it("preserves 16-byte binary integers and adjacent 64-bit integer metadata", async () => {
const fixture = await keyedArchiveWideIntegerFixture();
const result = await inspectBundleKeyedArchive({
bundlePath: fixture.root,
targetSha256: fixture.digest,
parameters: { path: "archive.bin" },
});
expect(result.archive_sha256).toBe(fixture.digest);
expect(result.objects).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: 1,
kind: "scalar",
status: "observed",
value: {
$plist_type: "integer",
decimal: "18446744073709551615",
},
}),
expect.objectContaining({
id: 2,
kind: "scalar",
status: "observed",
value: {
$plist_type: "integer",
decimal: "9223372036854775807",
},
}),
]),
);
expect(result.limitations).not.toContainEqual(
expect.stringMatching(/metadata could not be completely observed/u),
);
});
cliTest(
"compiled CLI preserves 16-byte binary archive integers",
async ({ cli }) => {
const fixture = await keyedArchiveWideIntegerFixture();
const output = await cli.run({
arguments: ["inspect-keyed-archive", fixture.path, "--json"],
environment: { REA_LOG_LEVEL: "silent", REA_ANALYSIS_PROVIDER: "auto" },
});
expect(output.exitCode, output.stderr).toBe(0);
expect(parseEvidence(output.json).normalized_result).toMatchObject({
objects: expect.arrayContaining([
expect.objectContaining({
id: 1,
value: {
$plist_type: "integer",
decimal: "18446744073709551615",
},
}),
expect.objectContaining({
id: 2,
value: {
$plist_type: "integer",
decimal: "9223372036854775807",
},
}),
]),
});
},
);
const sharedEntryObjects = [
expect.objectContaining({
id: 1,
status: "observed",
value: { $plist_type: "integer", decimal: "9007199254740993" },
}),
expect.objectContaining({
id: 2,
status: "observed",
value: { $plist_type: "integer", decimal: "9007199254740993" },
}),
expect.objectContaining({
id: 3,
status: "observed",
value: { $plist_type: "integer", decimal: "1152921504606846979" },
}),
];
it("keeps exact integers when two object-table entries share one record", async () => {
const fixture = await keyedArchiveSharedEntryFixture();
const result = await inspectBundleKeyedArchive({
bundlePath: fixture.root,
targetSha256: fixture.digest,
parameters: { path: "archive.plist" },
});
expect(result.archive_sha256).toBe(fixture.digest);
expect(result.objects.slice(1)).toEqual(sharedEntryObjects);
expect(result.limitations).not.toContainEqual(
expect.stringMatching(/metadata could not be completely observed/u),
);
expect(await readFile(fixture.path)).toEqual(fixture.bytes);
});
cliTest(
"compiled CLI keeps exact integers when object-table entries share one record",
async ({ cli }) => {
const fixture = await keyedArchiveSharedEntryFixture();
const output = await cli.run({
arguments: ["inspect-keyed-archive", fixture.path, "--json"],
environment: { REA_LOG_LEVEL: "silent", REA_ANALYSIS_PROVIDER: "auto" },
});
expect(output.exitCode, output.stderr).toBe(0);
const result = parseEvidence(output.json).normalized_result as {
objects: unknown[];
};
expect(result.objects.slice(1)).toEqual(sharedEntryObjects);
},
);
it.each(archiveNumberMetadataCases)(
"filesystem preserves numeric meaning for $name",
async (item) => {
const fixture = await keyedArchiveNumberMetadataFixture(item);
const result = await inspectBundleKeyedArchive({
bundlePath: fixture.root,
targetSha256: fixture.digest,
parameters: { path: "archive.plist" },
});
expectKeyedArchiveNumberMetadata(result, item, fixture.digest);
},
);
cliTest.for(archiveNumberMetadataCases)(
"built CLI preserves numeric meaning for $name",
async (item, { cli }) => {
const fixture = await keyedArchiveNumberMetadataFixture(item);
const output = await cli.run({
arguments: ["inspect-keyed-archive", fixture.path, "--json"],
environment: { REA_LOG_LEVEL: "silent", REA_ANALYSIS_PROVIDER: "auto" },
});
expectKeyedArchiveNumberMetadata(
parseEvidence(output.json).normalized_result,
item,
fixture.digest,
);
},
);