mirror of
https://github.com/morluto/rea
synced 2026-10-28 06:46:47 -04:00
fix(providers): preserve report bytes and dictionary facts
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import { truncate, writeFile } from "node:fs/promises";
|
||||
import { readFile, truncate, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { expect, it } from "vitest";
|
||||
import { projectAnalysisError } from "../../domain/analysisErrorProjection.js";
|
||||
import { ProviderAdapterError } from "../../domain/providerAdapterError.js";
|
||||
import { createTestTempDirectory } from "../../../tests/fixtures/temporaryDirectory.js";
|
||||
import { parseWakaruReports } from "./WakaruReport.js";
|
||||
import { AnalysisOutputError } from "../../domain/analysisErrorCore.js";
|
||||
import {
|
||||
parseWakaruReports,
|
||||
validateRecoverySourceMap,
|
||||
} from "./WakaruReport.js";
|
||||
import { RECOVERY_LIMITS } from "./WakaruRelease.js";
|
||||
|
||||
const reportStdout = JSON.stringify({
|
||||
@@ -73,3 +77,56 @@ it("keeps a malformed provenance report distinct from the fixed report allowance
|
||||
expect(JSON.stringify(projected)).not.toContain("report allowance");
|
||||
expect(JSON.stringify(projected)).not.toContain("no runtime override");
|
||||
});
|
||||
|
||||
it("rejects malformed UTF-8 provenance bytes and retains literal replacement characters", async () => {
|
||||
const root = await createTestTempDirectory("rea-wakaru-provenance-utf8-");
|
||||
const provenancePath = join(root, "provenance.json");
|
||||
const prefix = Buffer.from('{"format":"');
|
||||
const suffix = Buffer.from('","strategy":"safe","modules":{}}');
|
||||
await writeFile(
|
||||
provenancePath,
|
||||
Buffer.concat([prefix, Buffer.from([0xff]), suffix]),
|
||||
);
|
||||
const context = {
|
||||
execution,
|
||||
provenancePath,
|
||||
snapshots: new Map<string, Buffer>(),
|
||||
files: [{ relativePath: "provenance.json" }],
|
||||
};
|
||||
const refusal: unknown = await parseWakaruReports(context).catch(
|
||||
(cause: unknown) => cause,
|
||||
);
|
||||
expect(refusal).toBeInstanceOf(ProviderAdapterError);
|
||||
if (!(refusal instanceof ProviderAdapterError))
|
||||
throw new Error("Expected provider wrapper");
|
||||
expect(refusal.cause).toBeInstanceOf(TypeError);
|
||||
await writeFile(
|
||||
provenancePath,
|
||||
Buffer.concat([prefix, Buffer.from("�"), suffix]),
|
||||
);
|
||||
const accepted = await parseWakaruReports(context);
|
||||
expect(accepted.provenance.format).toBe("�");
|
||||
});
|
||||
|
||||
it("rejects malformed UTF-8 emitted source maps without rejecting literal replacement characters", async () => {
|
||||
const root = await createTestTempDirectory("rea-wakaru-sourcemap-utf8-");
|
||||
const mapPath = join(root, "module.js.map");
|
||||
const prefix = Buffer.from('{"version":3,"sources":["');
|
||||
const suffix = Buffer.from('"],"names":[],"mappings":""}');
|
||||
await writeFile(
|
||||
mapPath,
|
||||
Buffer.concat([prefix, Buffer.from([0xff]), suffix]),
|
||||
);
|
||||
let refusal: unknown;
|
||||
try {
|
||||
validateRecoverySourceMap(await readFile(mapPath), "module.js");
|
||||
} catch (cause: unknown) {
|
||||
refusal = cause;
|
||||
}
|
||||
expect(refusal).toBeInstanceOf(AnalysisOutputError);
|
||||
if (!(refusal instanceof AnalysisOutputError))
|
||||
throw new Error("Expected source-map wrapper");
|
||||
expect(refusal.cause).toBeInstanceOf(TypeError);
|
||||
await writeFile(mapPath, Buffer.concat([prefix, Buffer.from("�"), suffix]));
|
||||
validateRecoverySourceMap(await readFile(mapPath), "module.js");
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { z } from "zod";
|
||||
import { safeParseUtf8Json } from "../../domain/safeJson.js";
|
||||
import { ArtifactReaderFailure } from "../../artifacts/ArtifactReader.js";
|
||||
import type { ArtifactResourceScope } from "../../artifacts/ArtifactResourceScope.js";
|
||||
import {
|
||||
@@ -78,13 +79,11 @@ export const parseWakaruReports = async (context: ReportContext) => {
|
||||
"Wakaru did not complete recovery (expected exit 0 or a reported partial exit 1)",
|
||||
);
|
||||
const report = reportSchema.parse(JSON.parse(execution.stdout));
|
||||
const provenance = provenanceSchema.parse(
|
||||
JSON.parse(
|
||||
(
|
||||
await readWakaruProvenanceReport(provenancePath, signal, resources)
|
||||
).toString("utf8"),
|
||||
),
|
||||
const decoded = safeParseUtf8Json(
|
||||
await readWakaruProvenanceReport(provenancePath, signal, resources),
|
||||
);
|
||||
if (!decoded.ok) throw decoded.cause;
|
||||
const provenance = provenanceSchema.parse(decoded.value);
|
||||
if (report.total !== report.modules.length || report.failed > report.total)
|
||||
throw new TypeError("Reported module totals disagree");
|
||||
if (
|
||||
@@ -249,7 +248,9 @@ export const validateRecoverySourceMap = (
|
||||
mappings: z.string(),
|
||||
});
|
||||
try {
|
||||
schema.parse(JSON.parse(bytes.toString("utf8")));
|
||||
const decoded = safeParseUtf8Json(bytes);
|
||||
if (!decoded.ok) throw decoded.cause;
|
||||
schema.parse(decoded.value);
|
||||
} catch (cause: unknown) {
|
||||
throw new AnalysisOutputError(
|
||||
OPERATION,
|
||||
|
||||
Reference in New Issue
Block a user