Files
rea/tests/boundary/cli/jsonInputSize.test.ts
morluto ec271121e4 fix(artifacts): preserve path identity and exclusion applicability
Normalize path facts once at the owning filesystem boundary, preserve caller spelling and unavailable inventory members, and retain typed read failures. Record exclusion entry kinds so only proven directories can establish descendant symlink targets; omitted legacy kinds stay unknown.

Reviewed fixes include #1969, #2642, #2759, and #2994.

Validation: 26 reference graph source tests passed; prior artifact checks passed 275 tests with one Windows-only skip. Updated compiled import workflows are included in final validation after regeneration.
2026-10-14 08:31:16 +08:00

228 lines
7.9 KiB
TypeScript

import { constants } from "node:buffer";
import { mkdir, open, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest(
"rejects malformed oversized input through CLI and Evidence readers",
async ({ cli, processes }) => {
const root = await createTestTempDirectory("rea-json-string-limit-");
const input = join(root, "oversized.json");
const file = await open(input, "wx");
try {
// Sparse zero bytes are valid UTF-8. Both streaming readers reject
// their invalid JSON syntax without assembling a whole-document string.
await file.truncate(constants.MAX_STRING_LENGTH + 1);
} finally {
await file.close();
}
// Run readers sequentially in owned child processes, releasing each large
// read buffer when its process exits instead of retaining it in Vitest.
const result = await cli.run({
arguments: ["trace-application-feature", input, "--json"],
});
expect(result.json).toMatchObject({
code: "invalid_request",
input_path: input,
input_reason: "invalid-json",
});
expect(result.exitCode).toBe(1);
expect(result.stderr).toBe("");
const evidence = await processes.run(process.execPath, [
"--input-type=module",
"-e",
`import { readJsonFile } from "./dist/application/JsonFiles.js";
import { projectAnalysisError } from "./dist/domain/analysisErrorProjection.js";
const result = await readJsonFile(process.argv[1]);
console.log(JSON.stringify(result.ok ? result : projectAnalysisError(result.error)));`,
input,
]);
expect(JSON.parse(evidence.stdout)).toMatchObject({
code: "evidence_integrity_mismatch",
details: {
operation: "read",
reason: "invalid-json",
path: input,
},
});
expect(evidence.stderr).toBe("");
expect(evidence.exitCode).toBe(0);
},
);
cliTest(
"traces valid Evidence beyond the whole-document string limit",
async ({ cli, processes }) => {
const root = await createTestTempDirectory("rea-json-streamed-evidence-");
const source = join(root, "application");
await mkdir(source);
await writeFile(
join(source, "package.json"),
JSON.stringify({
name: "streamed-evidence",
type: "module",
main: "entry.mjs",
}),
);
await writeFile(
join(source, "entry.mjs"),
'export const observed = "source-owned";',
);
const application = await cli.run({
arguments: [
"analyze-javascript-application",
source,
"--artifact-format",
"directory",
"--json",
],
});
expect(application.exitCode).toBe(0);
const request = JSON.stringify({
application: application.json,
seed: { kind: "module", value: "entry.mjs", match: "contains" },
direction: "incoming",
});
const input = join(root, "trace.json");
await writeFile(input, request);
const ordinary = await cli.run({
arguments: ["trace-application-feature", input, "--json"],
});
expect(ordinary.exitCode).toBe(0);
const file = await open(input, "a");
try {
const whitespace = Buffer.alloc(1024 * 1024, 0x20);
let remaining =
constants.MAX_STRING_LENGTH + 1 - Buffer.byteLength(request);
while (remaining > 0) {
const length = Math.min(remaining, whitespace.length);
await file.writeFile(whitespace.subarray(0, length));
remaining -= length;
}
} finally {
await file.close();
}
const streamed = await cli.run({
arguments: ["trace-application-feature", input, "--json"],
});
expect(streamed.exitCode).toBe(0);
expect(streamed.json).toEqual(ordinary.json);
expect(streamed.stderr).toBe("");
},
);
cliTest(
"returns a typed container assembly constraint and allows a following read",
async ({ cli, processes }) => {
const root = await createTestTempDirectory("rea-json-container-headroom-");
const input = join(root, "containers.json");
const following = join(root, "following.json");
const file = await open(input, "wx");
try {
await file.writeFile("[");
const chunk = Buffer.from("[],".repeat(65_536));
for (let index = 0; index < 128; index++) await file.writeFile(chunk);
await file.writeFile("null]");
} finally {
await file.close();
}
await writeFile(following, '{"after":true}');
const result = await cli.run({
arguments: ["trace-application-feature", input, "--json"],
environment: { NODE_OPTIONS: "--max-old-space-size=768" },
});
expect(result.exitCode).toBe(1);
expect(result.stderr).toBe("");
expect(result.json).toMatchObject({
code: "resource_constraint",
details: {
resource: "memory",
reported_limits: {
input_path: input,
projected_value_bytes: expect.any(Number),
assembly_headroom_bytes: expect.any(Number),
},
},
});
const evidence = await processes.run(process.execPath, [
"--max-old-space-size=768",
"--input-type=module",
"-e",
`import { readJsonFile } from "./dist/application/JsonFiles.js";
import { projectAnalysisError } from "./dist/domain/analysisErrorProjection.js";
const large = await readJsonFile(process.argv[1]);
const following = await readJsonFile(process.argv[2]);
console.log(JSON.stringify({large: large.ok ? large : projectAnalysisError(large.error), following}));`,
input,
following,
]);
expect(evidence.exitCode).toBe(0);
expect(evidence.stderr).toBe("");
expect(JSON.parse(evidence.stdout)).toMatchObject({
large: {
code: "resource_constraint",
details: { reported_limits: { input_path: input } },
},
following: { ok: true, value: { after: true } },
});
},
);
cliTest(
"returns a typed string assembly constraint under a bounded heap",
async ({ cli, processes }) => {
const root = await createTestTempDirectory("rea-json-string-headroom-");
const input = join(root, "long-string.json");
const file = await open(input, "wx");
try {
await file.writeFile('"');
const chunk = Buffer.alloc(1024 * 1024, 0x78);
let remaining = constants.MAX_STRING_LENGTH + 1;
while (remaining > 0) {
const length = Math.min(remaining, chunk.length);
await file.writeFile(chunk.subarray(0, length));
remaining -= length;
}
await file.writeFile('"');
} finally {
await file.close();
}
const result = await cli.run({
arguments: ["trace-application-feature", input, "--json"],
environment: { NODE_OPTIONS: "--max-old-space-size=768" },
});
expect(result.exitCode, result.stderr).toBe(1);
expect(result.stderr).toBe("");
expect(result.json).toMatchObject({
code: "resource_constraint",
input_path: input,
input_reason: "too-large",
details: { resource: "memory" },
remediation: {
action: expect.stringContaining("re-analyze a smaller selection"),
},
});
const evidence = await processes.run(process.execPath, [
"--max-old-space-size=768",
"--input-type=module",
"-e",
`import { readJsonFile } from "./dist/application/JsonFiles.js";
import { projectAnalysisError } from "./dist/domain/analysisErrorProjection.js";
const result = await readJsonFile(process.argv[1]);
console.log(JSON.stringify(result.ok ? result : projectAnalysisError(result.error)));`,
input,
]);
expect(JSON.parse(evidence.stdout)).toMatchObject({
code: "resource_constraint",
details: { operation: "read_evidence_file", resource: "memory" },
});
expect(evidence.stderr).toBe("");
expect(evidence.exitCode).toBe(0);
},
);