Files
rea/tests/boundary/javascript/javascriptSelectedPathEvidence.test.ts
T

168 lines
6.1 KiB
TypeScript

import {
mkdir,
readFile,
realpath,
rm,
symlink,
writeFile,
} from "node:fs/promises";
import { join } from "node:path";
import { expect } from "vitest";
import { parseEvidence } from "../../../src/domain/evidence.js";
import { parseEvidenceBundle } from "../../../src/domain/evidenceBundle.js";
import { parseApplicationGraphEvidence } from "../../../src/application/javascript/JavaScriptApplicationEvidenceGraph.js";
import { JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE } from "../../../src/contracts/javascript/javascriptRuntimeReconciliationExample.js";
import { connectLocalToolsMcp } from "../../fixtures/localToolsMcp.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { cliTest } from "../../support/cli/cliFixture.js";
cliTest(
"retains selected JavaScript path separately from resolved identity",
async ({ cli }) => {
const root = await createTestTempDirectory("rea-js-selected-path-");
const physicalPath = join(root, "physical-app");
const selectedPath = join(root, "selected-app");
await mkdir(physicalPath);
await writeFile(join(physicalPath, "main.js"), "export const value = 7;\n");
await symlink(
physicalPath,
selectedPath,
process.platform === "win32" ? "junction" : "dir",
);
const resolvedPath = await realpath(physicalPath);
expect(await realpath(selectedPath)).toBe(resolvedPath);
const cliResponse = await cli.run({
arguments: [
"analyze-javascript-application",
selectedPath,
"--artifact-format",
"directory",
"--json",
],
environment: { REA_LOG_LEVEL: "silent" },
});
expect(cliResponse.exitCode, cliResponse.stderr).toBe(0);
const cliEvidence = parseEvidence(cliResponse.json);
for (const command of ["analyze", "analyze-javascript-application"]) {
const relativeResponse = await cli.run({
arguments: [command, "./selected-app", "--json"],
cwd: root,
environment: { REA_LOG_LEVEL: "silent" },
});
expect(relativeResponse.exitCode, relativeResponse.stderr).toBe(0);
const relativeEvidence = parseEvidence(relativeResponse.json);
expect(relativeEvidence.parameters.input_path, command).toBe(
selectedPath,
);
expect(relativeEvidence.subject).toEqual(cliEvidence.subject);
expect(relativeEvidence.normalized_result).toEqual(
cliEvidence.normalized_result,
);
}
const { call } = await connectLocalToolsMcp({ REA_LOG_LEVEL: "silent" });
const aliasResponse = await call("analyze_javascript_application", {
input_path: selectedPath,
format: "directory",
integrity_policy: "fail",
});
expect(
aliasResponse.isError,
JSON.stringify(aliasResponse.content),
).not.toBe(true);
const aliasEvidence = parseEvidence(aliasResponse.structuredContent);
const physicalResponse = await call("analyze_javascript_application", {
input_path: physicalPath,
format: "directory",
integrity_policy: "fail",
});
expect(
physicalResponse.isError,
JSON.stringify(physicalResponse.content),
).not.toBe(true);
const physicalEvidence = parseEvidence(physicalResponse.structuredContent);
for (const evidence of [cliEvidence, aliasEvidence]) {
expect(evidence.parameters.input_path).toBe(selectedPath);
expect(evidence.subject?.local_path).toBe(resolvedPath);
expect(evidence.normalized_result).toMatchObject({
input_path: resolvedPath,
});
expect(parseApplicationGraphEvidence(evidence).ok).toBe(true);
}
expect(cliEvidence.normalized_result).toEqual(
aliasEvidence.normalized_result,
);
expect(physicalEvidence.parameters.input_path).toBe(physicalPath);
expect(physicalEvidence.subject?.local_path).toBe(resolvedPath);
expect(physicalEvidence.normalized_result).toEqual(
aliasEvidence.normalized_result,
);
expect(physicalEvidence.subject?.digest.sha256).toBe(
aliasEvidence.subject?.digest.sha256,
);
expect(physicalEvidence.evidence_id).not.toBe(aliasEvidence.evidence_id);
const bundlePath = join(root, "retained-evidence.json");
expect(
(await call("export_evidence_bundle", { path: bundlePath })).isError,
).not.toBe(true);
await rm(selectedPath);
await rm(physicalPath, { recursive: true });
const bundle = parseEvidenceBundle(
JSON.parse(await readFile(bundlePath, "utf8")),
);
const retained = bundle.records.find(
(record) => record.evidence_id === aliasEvidence.evidence_id,
);
expect(retained?.parameters.input_path).toBe(selectedPath);
for (const evidence of [
cliEvidence,
aliasEvidence,
physicalEvidence,
retained,
])
expect(
parseApplicationGraphEvidence(JSON.parse(JSON.stringify(evidence))).ok,
).toBe(true);
expect((await call("close_binary", {})).isError).not.toBe(true);
expect(
(await call("import_evidence_bundle", { path: bundlePath })).isError,
).not.toBe(true);
expect(
JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE.parameters,
).not.toHaveProperty("input_path");
expect(
parseApplicationGraphEvidence(JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE).ok,
).toBe(true);
},
);
// Anchoring must not turn an empty selection into the working directory.
cliTest.for([
{
command: "analyze-javascript-application",
rejection: {
code: "invalid_request",
details: { issues: [expect.objectContaining({ path: ["input_path"] })] },
},
},
{ command: "analyze", rejection: { code: "VALIDATION_ERROR" } },
])(
"$command rejects an empty path instead of analyzing the working directory",
async ({ command, rejection }, { cli }) => {
const root = await createTestTempDirectory("rea-js-empty-path-");
await writeFile(join(root, "main.js"), "export const value = 7;\n");
const response = await cli.run({
arguments: [command, "", "--json"],
cwd: root,
environment: { REA_LOG_LEVEL: "silent" },
});
expect(response.exitCode, response.stderr).toBe(1);
expect(response.json).toMatchObject(rejection);
},
);