mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
90 lines
3.5 KiB
TypeScript
90 lines
3.5 KiB
TypeScript
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { createPackageWithOptions } from "@electron/asar";
|
|
import { expect } from "vitest";
|
|
import { z } from "zod";
|
|
import { artifactInspectionResultSchema } from "../../../src/domain/artifactInspection.js";
|
|
import { parseEvidence } from "../../../src/domain/evidence.js";
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { cliTest } from "../../support/cli/cliFixture.js";
|
|
|
|
const summarySchema = z.object({
|
|
unknowns: z.array(z.string()),
|
|
summary: z.object({ source_complete: z.boolean() }),
|
|
});
|
|
|
|
cliTest(
|
|
"discloses unavailable ASAR content hashes in both summary routes and retains the parent",
|
|
async ({ cli }) => {
|
|
const root = await createTestTempDirectory("rea-asar-summary-");
|
|
const source = join(root, "source");
|
|
await mkdir(join(source, "native"), { recursive: true });
|
|
await writeFile(join(source, "main.js"), "console.log(1);\n");
|
|
const bytes = "inert addon bytes\n";
|
|
await writeFile(join(source, "native", "addon.node"), bytes);
|
|
const archive = join(root, "app.asar");
|
|
await createPackageWithOptions(source, archive, { unpack: "*.node" });
|
|
const companion = join(`${archive}.unpacked`, "native", "addon.node");
|
|
const caveat =
|
|
"Content hashes are unknown for some recorded files; missing node IDs do not prove content absence.";
|
|
for (const phase of ["present", "missing", "restored"]) {
|
|
if (phase === "missing") await rm(companion);
|
|
if (phase === "restored") await writeFile(companion, bytes);
|
|
const bundle = join(root, `${phase}-evidence.json`);
|
|
const direct = await cli.run({
|
|
arguments: [
|
|
"inspect-artifact",
|
|
archive,
|
|
"--detail",
|
|
"summary",
|
|
"--evidence_output",
|
|
bundle,
|
|
"--json",
|
|
],
|
|
});
|
|
expect(direct.exitCode).toBe(0);
|
|
const compact = z
|
|
.object({ summary: z.object({ normalized_result: summarySchema }) })
|
|
.parse(direct.json);
|
|
const retained = z
|
|
.object({ records: z.array(z.unknown()) })
|
|
.parse(JSON.parse(await readFile(bundle, "utf8")));
|
|
const parent = retained.records
|
|
.map(parseEvidence)
|
|
.find((record) => record.operation === "inspect_artifact");
|
|
expect(parent).toBeDefined();
|
|
const request = join(root, "request.json");
|
|
await writeFile(
|
|
request,
|
|
JSON.stringify({
|
|
source: { kind: "inline", evidence: parent },
|
|
view: { kind: "summary" },
|
|
}),
|
|
);
|
|
const inline = await cli.run({
|
|
arguments: ["inspect-analysis-view", request, "--json"],
|
|
});
|
|
expect(inline.exitCode).toBe(0);
|
|
const summary = summarySchema.parse(
|
|
parseEvidence(inline.json).normalized_result,
|
|
);
|
|
const inspection = artifactInspectionResultSchema.parse(
|
|
parent!.normalized_result,
|
|
);
|
|
const occurrence = inspection.substeps
|
|
.flatMap((step) => step.evidence.normalized_result.occurrences)
|
|
.find((row) => row.logical_path === "native/addon.node");
|
|
expect(occurrence).toMatchObject({
|
|
hash_status: phase === "missing" ? "unavailable" : "verified",
|
|
...(phase === "missing" ? { artifact_id: null } : {}),
|
|
});
|
|
for (const result of [compact.summary.normalized_result, summary]) {
|
|
expect(result.summary.source_complete).toBe(true);
|
|
expect(result.unknowns.includes(caveat), phase).toBe(
|
|
phase === "missing",
|
|
);
|
|
}
|
|
}
|
|
},
|
|
);
|