mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
2cf9c28f27
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
71 lines
2.0 KiB
TypeScript
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__"),
|
|
);
|
|
});
|