From 6605ac1ff532e88dceaed554d6ec832d29f3211f Mon Sep 17 00:00:00 2001 From: Daniel Oon Date: Sun, 30 Aug 2026 00:33:29 +0800 Subject: [PATCH] fix: reject invalid action outcomes --- bin/aas.mjs | 7 ++++++- test/stack.test.mjs | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/bin/aas.mjs b/bin/aas.mjs index 7f80208..134e608 100644 --- a/bin/aas.mjs +++ b/bin/aas.mjs @@ -208,7 +208,12 @@ export function runAct( cwd: join(depsDir, "consequence-rail"), }); if (result.status !== 0) throw childProcessError("act", result); - return { ok: true, raw: parseJsonOutput(result.stdout, "act"), status: 0 }; + const payload = parseJsonOutput(result.stdout, "act"); + if (!payload || typeof payload !== "object" || Array.isArray(payload) + || ![null, "settled", "compensated", "disputed"].includes(payload.outcome)) { + throw new Error("act did not return a valid outcome"); + } + return { ok: true, raw: payload, status: 0 }; } export function runProve( diff --git a/test/stack.test.mjs b/test/stack.test.mjs index ebbb419..e577805 100644 --- a/test/stack.test.mjs +++ b/test/stack.test.mjs @@ -8,6 +8,7 @@ import { loadComponentLock, inspectDependencyDirectory, npmInvocation } from ".. import { persistRunBundle, resolveComponentProvenance, + runAct, runDemo, writeAtomicFile, } from "../bin/aas.mjs"; @@ -128,6 +129,16 @@ test("Windows npm commands run through the npm JavaScript entrypoint", () => { ); }); +test("act rejects a zero-exit payload without a valid outcome", () => { + assert.throws( + () => runAct("none", { + depsDir: tempRoot(), + runner: () => ({ status: 0, stdout: "{}\n", stderr: "", error: null }), + }), + /valid outcome/, + ); +}); + test("pass bundle contains stage status, provenance, and only current artifacts", async () => { const outputRoot = tempRoot(); const result = await runDemo(["--response", "pass"], stubOptions(outputRoot, { runId: "pass-run" }));