fix(cli): report result sources when Evidence publication fails
A trace keeps linked sources on the result. Use those records for the undelivered source closure as well as the bundle, so a refused output does not report them as not captured.
This commit is contained in:
2 files changed
+37
-7
No files matched your search
@@ -250,13 +250,24 @@ export const publishCliAnalysisEvidence = async (
|
||||
input: CliEvidenceDelivery,
|
||||
): Promise<JsonValue> => {
|
||||
const { operation, signal, detail, evidenceOutput } = input;
|
||||
// Failure reporting uses the same captured sources as publication. A trace
|
||||
// carries them on the result, while other commands pass them on the input.
|
||||
const capturedSources = [
|
||||
...(input.sourceEvidence ?? []),
|
||||
...(result.sourceEvidence ?? []),
|
||||
];
|
||||
const closureInput =
|
||||
capturedSources.length === 0
|
||||
? input
|
||||
: { ...input, sourceEvidence: capturedSources };
|
||||
const projectFailure = (error: AnalysisError) =>
|
||||
projectAnalysisError(
|
||||
redactExplicitFailure(error, input.sensitiveValues ?? []),
|
||||
);
|
||||
const undelivered = (error: AnalysisError) =>
|
||||
withUndeliveredSourceClosure(projectFailure(error), input);
|
||||
if (!result.ok) return withUndeliveredSourceClosure(result.error, input);
|
||||
withUndeliveredSourceClosure(projectFailure(error), closureInput);
|
||||
if (!result.ok)
|
||||
return withUndeliveredSourceClosure(result.error, closureInput);
|
||||
const complete = parseEvidence(result.value);
|
||||
const inputError = cliEvidenceDeliveryInputError(input);
|
||||
if (inputError !== undefined) {
|
||||
@@ -285,11 +296,10 @@ export const publishCliAnalysisEvidence = async (
|
||||
if (!inspectionSources.ok) return undelivered(inspectionSources.error);
|
||||
const records = [
|
||||
...new Map(
|
||||
[
|
||||
...(input.sourceEvidence ?? []),
|
||||
...(result.sourceEvidence ?? []),
|
||||
...inspectionSources.value,
|
||||
].map((record) => [record.evidence_id, record]),
|
||||
[...capturedSources, ...inspectionSources.value].map((record) => [
|
||||
record.evidence_id,
|
||||
record,
|
||||
]),
|
||||
).values(),
|
||||
];
|
||||
// Only skip the writer's heap check when every record is already sealed.
|
||||
|
||||
@@ -435,6 +435,26 @@ it("reports the closure when an existing output refuses publication", async () =
|
||||
expect(await readFile(requested.evidenceOutput, "utf8")).toBe("original");
|
||||
});
|
||||
|
||||
it("reports result sources when an existing output refuses publication", async () => {
|
||||
const root = await createTestTempDirectory("rea-closure-result-sources-");
|
||||
const held = source("held");
|
||||
const requested = delivery(root);
|
||||
await writeFile(requested.evidenceOutput, "original");
|
||||
const output = await publishCliAnalysisEvidence(
|
||||
{ ...ok(observed([held.evidence_id])), sourceEvidence: [held] },
|
||||
requested,
|
||||
);
|
||||
expect(output).toMatchObject({ details: { reason: "exists" } });
|
||||
expect(closureOf(output)).toMatchObject({
|
||||
publication: "not_published",
|
||||
complete: true,
|
||||
omitted_count: 0,
|
||||
omitted: [],
|
||||
});
|
||||
expect(closureOf(output).records).toEqual([held]);
|
||||
expect(await readFile(requested.evidenceOutput, "utf8")).toBe("original");
|
||||
});
|
||||
|
||||
it("defers to the committed bundle receipt after cancellation wins late", async () => {
|
||||
const root = await createTestTempDirectory("rea-closure-committed-");
|
||||
const held = source("held");
|
||||
|
||||
Reference in new issue
Block a user