mirror of
https://github.com/morluto/rea.git
synced 2026-11-04 22:06:10 +00:00
* fix(domain): replace bare parser errors with typed codes OpenStep syntax, canonical JSON digests, managed-graph source checks, frame fingerprints, and reference-flow invariants threw Error and published the sentence. Each refusal now carries a code. Tests assert that code, including OpenStep position, instead of the previous prose. * test(domain): pin OpenStep refusal codes and positions The syntax cases accepted any code and any offset. Each container refusal now expects its code and source position, including the deep suffix that changes (x from unterminated_array to expected_separator. Scalar failures stay identical to the pinned decoder. * test(filesystem): assert OpenStep keyed-archive codes The deep-suffix keyed archive cases compared ArtifactReaderFailure message text with the pinned decoder sentence. They now require reason format and the OpenStep code and source position on the cause. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
106 lines
3.9 KiB
TypeScript
106 lines
3.9 KiB
TypeScript
import { writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
|
|
import { expect, it } from "vitest";
|
|
|
|
import { ArtifactReaderFailure } from "../../../src/artifacts/ArtifactReader.js";
|
|
import { inspectBundleKeyedArchive } from "../../../src/artifacts/apple/KeyedArchiveReader.js";
|
|
import { plistNestingLimitMessage } from "../../../src/domain/apple/plistValue.js";
|
|
import type { OpenStepPropertyListCode } from "../../../src/domain/propertyListOpenStep.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { deeplyNestedXmlPlist } from "../../fixtures/keyedArchiveXmlNesting.js";
|
|
|
|
it.each([129, 3000])(
|
|
"reports XML nesting of %i levels as the keyed archive decode limit",
|
|
async (depth) => {
|
|
const root = await createTestTempDirectory("rea-keyed-depth-");
|
|
await writeFile(join(root, "Deep.plist"), deeplyNestedXmlPlist(depth));
|
|
const rejected = await inspectBundleKeyedArchive({
|
|
bundlePath: root,
|
|
targetSha256: "a".repeat(64),
|
|
parameters: { path: "Deep.plist" },
|
|
platform: "linux",
|
|
}).catch((cause: unknown) => cause);
|
|
// The format owner must reject source depth before recursive decoding
|
|
// exhausts the call stack.
|
|
expect(rejected).toMatchObject({
|
|
reason: "limit",
|
|
message: `Cannot decode selected Foundation keyed archive: ${plistNestingLimitMessage()}`,
|
|
});
|
|
},
|
|
);
|
|
|
|
it.each([
|
|
["(}", "unexpected_character", 1],
|
|
["{)", "unexpected_character", 1],
|
|
["(@", "unexpected_character", 1],
|
|
["{key @", "expected_equals", 5],
|
|
["(x @", "expected_separator", 3],
|
|
["(x ", "expected_separator", 3],
|
|
["{key ", "expected_equals", 5],
|
|
["{key = x,", "unexpected_character", 8],
|
|
] as const)(
|
|
"reports OpenStep %s before a deep suffix as %s at %s",
|
|
async (prefix, code: OpenStepPropertyListCode, position) => {
|
|
const root = await createTestTempDirectory("rea-keyed-openstep-malformed-");
|
|
await writeFile(join(root, "Malformed.plist"), prefix + "(".repeat(130));
|
|
const rejected = await inspectBundleKeyedArchive({
|
|
bundlePath: root,
|
|
targetSha256: "a".repeat(64),
|
|
parameters: { path: "Malformed.plist" },
|
|
platform: "linux",
|
|
}).catch((cause: unknown) => cause);
|
|
expect(rejected).toBeInstanceOf(ArtifactReaderFailure);
|
|
expect(rejected).toMatchObject({
|
|
reason: "format",
|
|
cause: {
|
|
_tag: "OpenStepPropertyListError",
|
|
code,
|
|
position,
|
|
},
|
|
});
|
|
},
|
|
);
|
|
|
|
it("retains the limit classification for syntactically valid deep OpenStep values", async () => {
|
|
const root = await createTestTempDirectory("rea-keyed-openstep-limit-");
|
|
await writeFile(
|
|
join(root, "Deep.plist"),
|
|
"(".repeat(129) + "x" + ")".repeat(129),
|
|
);
|
|
const rejected = await inspectBundleKeyedArchive({
|
|
bundlePath: root,
|
|
targetSha256: "a".repeat(64),
|
|
parameters: { path: "Deep.plist" },
|
|
platform: "linux",
|
|
}).catch((cause: unknown) => cause);
|
|
expect(rejected).toMatchObject({
|
|
reason: "limit",
|
|
message: `Cannot decode selected Foundation keyed archive: ${plistNestingLimitMessage()}`,
|
|
});
|
|
});
|
|
|
|
it.each([
|
|
["array sibling", (deep: string) => `((x),${deep})`],
|
|
["compound dictionary key", (deep: string) => `{(key)=${deep};}`],
|
|
] as const)(
|
|
"retains the named OpenStep depth limit after a completed %s",
|
|
async (_name, document) => {
|
|
const root = await createTestTempDirectory(
|
|
"rea-keyed-openstep-sibling-depth-",
|
|
);
|
|
const deep = "(".repeat(30000) + "x" + ")".repeat(30000);
|
|
await writeFile(join(root, "Deep.plist"), document(deep));
|
|
const rejected = await inspectBundleKeyedArchive({
|
|
bundlePath: root,
|
|
targetSha256: "a".repeat(64),
|
|
parameters: { path: "Deep.plist" },
|
|
platform: "linux",
|
|
}).catch((cause: unknown) => cause);
|
|
expect(rejected).toMatchObject({
|
|
reason: "limit",
|
|
message: `Cannot decode selected Foundation keyed archive: ${plistNestingLimitMessage()}`,
|
|
});
|
|
},
|
|
);
|