Files
rea/tests/boundary/filesystem/keyedArchiveScalarStructure.test.ts
T
morluto 2cf9c28f27 fix(apple): preserve decoded keyed archive scalar identity
Move plist projection into the graph owner and identify generated scalar
wrappers by producer identity through every dictionary/UID consumer. Remove
the intermediate JSON clone that erased those facts. Literal wrapper-shaped
dictionaries remain dictionaries; scalar $top values fail as malformed.
Keep numeric projection after graph interpretation, preserve unknown counts,
and retain binary prototype-key partial facts with an explicit limitation.

Adapt @Jax367's relevant scalar proposal and public regression from PR #4317.
Add scalar-root, literal-root and binary prototype controls. Correct only
the captured Foundation data node expectation and its manifest digest;
original producer bytes and source are unchanged. Unrelated PR changes excluded.

Validation: 175 focused checks across 23 files pass, one skipped; build,
check:fast and docs:check pass. Public CLI and stdio MCP cover both encodings.
Baseline scalar controls fail; 24 tiny completed CLI cost comparisons retain
ordinary full replies and Evidence IDs byte for byte. No statistical speed
claim, heavy profiling, target execution or real deep-provider verification.

Fixes #4295
Fixes #4785
2026-10-17 20:20:53 +08:00

71 lines
2.0 KiB
TypeScript

import { build, buildBinary } from "plist";
import { expect, it } from "vitest";
import { decodeKeyedArchiveBytes } from "../../../src/artifacts/apple/KeyedArchiveReader.js";
it.each([
{ name: "data", value: new Uint8Array([0]) },
{ name: "date", value: new Date(0) },
{ name: "real", value: Number.POSITIVE_INFINITY },
])(
"rejects a $name scalar used as the top-level root dictionary in either encoding",
({ value }) => {
const archive = {
$archiver: "NSKeyedArchiver",
$version: 100000,
$objects: ["$null"],
$top: value,
};
for (const encode of [build, buildBinary]) {
const bytes = Buffer.from(encode(archive));
expect(() =>
decodeKeyedArchiveBytes(bytes, { offset: 0, limit: 10 }),
).toThrow("Keyed archive has no $top roots");
}
},
);
it("keeps literal wrapper-shaped dictionaries as real root maps", () => {
const top = { $plist_type: "data", base64: "AA==" };
const archive = {
$archiver: "NSKeyedArchiver",
$version: 100000,
$objects: ["$null"],
$top: top,
};
for (const encode of [build, buildBinary]) {
const graph = decodeKeyedArchiveBytes(Buffer.from(encode(archive)), {
offset: 0,
limit: 10,
});
expect(graph.roots).toEqual(top);
expect(graph.references).toEqual([]);
}
});
it("retains own binary dictionary facts when a prototype key changes the decoder prototype", () => {
const object = Object.fromEntries([
["__proto__", { inherited: "not an own fact" }],
["payload", "retained"],
]);
const graph = decodeKeyedArchiveBytes(
Buffer.from(
buildBinary({
$archiver: "NSKeyedArchiver",
$version: 100000,
$objects: ["$null", object],
$top: { root: { UID: 1 } },
}),
),
{ offset: 0, limit: 10 },
);
expect(graph.objects[1]).toMatchObject({
kind: "dictionary",
value: { payload: "retained" },
});
expect(graph.objects[1]?.value).toEqual({ payload: "retained" });
expect(graph.limitations).toContainEqual(
expect.stringContaining("__proto__"),
);
});