diff --git a/runs/offload-test.test.ts b/runs/offload-test.test.ts index 2c67090..3e3b306 100644 --- a/runs/offload-test.test.ts +++ b/runs/offload-test.test.ts @@ -787,6 +787,36 @@ describe("offload-test staged mode", () => { }, ); + it.effect("a dead stage's marker keeps the platform's own incident id", () => { + const { layer, handles } = makeCFRuntimeTest({ + sandboxProgram: { + // What a dying container actually reports. The class is the half a + // consumer can already infer; the reference is the half only the + // platform's operator can act on, and it used to be dropped. + "run-a": { + fail: "ExecFailed", + exitCode: -1, + stderrTail: "exec failed (exit -1): internal error; reference = aggq3f5m407e2vb2ht76l2vf", + }, + }, + config: { + "offload-test.stages:owner/name": "a", + "offload-test.command:owner/name:a": "run-a", + }, + }); + + return Effect.gen(function* () { + yield* Effect.exit(offloadTest.run(webhookInput)); + const markerWrite = handles.sandbox.execs.find((e) => e.command.includes("stage=a")); + expect(markerWrite?.command).toContain("reference=aggq3f5m407e2vb2ht76l2vf"); + // Shell-safe by construction: whatever lands after `reference=` is drawn + // from `[A-Za-z0-9_-]` only, so no vendor text can close the quote the + // marker is printed inside. + const id = /reference=([^\s']*)/.exec(markerWrite?.command ?? "")?.[1]; + expect(id).toMatch(/^[A-Za-z0-9_-]+$/); + }).pipe(Effect.provide(layer)); + }); + it.effect( "an Action dispatch that passes `command` stays single-exec even with stages set", () => { diff --git a/runs/offload-test.ts b/runs/offload-test.ts index 943f6e1..4b65956 100644 --- a/runs/offload-test.ts +++ b/runs/offload-test.ts @@ -805,9 +805,29 @@ export const offloadTest = defineRun({ }); const elapsedMs = (yield* io.now) - stageStartMs; const elapsedS = Math.round(elapsedMs / 1000); - // Label (STAGE_LABEL_RE), tag, and number only — shell-quote-safe - // by construction. - const markerLine = `stage=${stage.label} error=${errorClass} elapsedMs=${elapsedMs}`; + // Label (STAGE_LABEL_RE), tag, numbers, and — when the platform + // supplied one — its own incident id. + // + // `ExecFailed: exec failed (exit -1): internal error; reference = + // aggq3f5m407e2vb2ht76l2vf` is what a dying container reports, and + // that reference is the only thing that identifies the incident to + // the platform's operator. The marker used to record the CLASS and + // drop the id, which is the half a consumer can already infer from + // the fact that their stage died. + // + // EXTRACTED, not interpolated: the marker is shell-quoted into a + // `printf '%s\n' ''`, so free vendor text could close the + // quote. A `[A-Za-z0-9_-]` id and a signed integer cannot. + const rendered = Option.match(Cause.failureOption(exit.cause), { + onSome: (f) => `${String((f as { cause?: unknown }).cause ?? "")} ${String((f as { message?: unknown }).message ?? "")}`, + onNone: () => "", + }); + const reference = /reference\s*=\s*([A-Za-z0-9_-]{1,64})/.exec(rendered)?.[1]; + const platformExit = /exit\s+(-?\d{1,5})\)/.exec(rendered)?.[1]; + const markerLine = + `stage=${stage.label} error=${errorClass} elapsedMs=${elapsedMs}` + + (platformExit !== undefined ? ` exit=${platformExit}` : "") + + (reference !== undefined ? ` reference=${reference}` : ""); // The marker rides the marker exec's OWN log stream: `sandbox.exec` // streams stdout to an R2 log key and returns it as `logPath`, so // uploading THAT key in R2-source mode (no `container` — same mode