From fa6904bf95ce973bbd5cd2eb3e490e3db06e169b Mon Sep 17 00:00:00 2001 From: matamune Date: Fri, 15 May 2026 17:02:18 +0000 Subject: [PATCH] Accept Patch flow dispatch signatures --- apps/flow-backend-systemd-local/src/signature.ts | 2 +- .../flow-backend-systemd-local/test/backend.test.ts | 8 +++++++- docs/flows.md | 13 +++++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/apps/flow-backend-systemd-local/src/signature.ts b/apps/flow-backend-systemd-local/src/signature.ts index 8e9de19..d94c694 100644 --- a/apps/flow-backend-systemd-local/src/signature.ts +++ b/apps/flow-backend-systemd-local/src/signature.ts @@ -14,5 +14,5 @@ export function verifyBodySignature(secret: string, body: string, signature: str } export function requestSignature(headers: Headers): string | null { - return headers.get("x-flow-signature-256") ?? headers.get("x-patchbay-flow-signature-256"); + return headers.get("x-flow-signature-256") ?? headers.get("x-patch-flow-signature-256") ?? headers.get("x-patchbay-flow-signature-256"); } diff --git a/apps/flow-backend-systemd-local/test/backend.test.ts b/apps/flow-backend-systemd-local/test/backend.test.ts index a9f542f..e906e07 100644 --- a/apps/flow-backend-systemd-local/test/backend.test.ts +++ b/apps/flow-backend-systemd-local/test/backend.test.ts @@ -5,7 +5,7 @@ import path from "node:path"; import { dispatchFlowEvent, replayFlowEvent } from "../src/backend.ts"; import { parseCli, readConfig } from "../src/config.ts"; import { flowCommand } from "../src/executor.ts"; -import { signBody, verifyBodySignature } from "../src/signature.ts"; +import { requestSignature, signBody, verifyBodySignature } from "../src/signature.ts"; import { FlowBackendStore } from "../src/store.ts"; test("signs and verifies dispatch bodies", () => { @@ -16,6 +16,12 @@ test("signs and verifies dispatch bodies", () => { expect(verifyBodySignature("secret", `${body}\n`, signature)).toBe(false); }); +test("reads generic, Patch, and legacy Patchbay dispatch signatures", () => { + expect(requestSignature(new Headers({ "x-flow-signature-256": "sha256=generic" }))).toBe("sha256=generic"); + expect(requestSignature(new Headers({ "x-patch-flow-signature-256": "sha256=patch" }))).toBe("sha256=patch"); + expect(requestSignature(new Headers({ "x-patchbay-flow-signature-256": "sha256=legacy" }))).toBe("sha256=legacy"); +}); + test("dispatches matching flow steps and records runs", async () => { const directory = await mkdtemp(path.join(os.tmpdir(), "flow-backend-")); try { diff --git a/docs/flows.md b/docs/flows.md index b4ccd4a..77516b6 100644 --- a/docs/flows.md +++ b/docs/flows.md @@ -107,7 +107,7 @@ bun run flow run openai-codex-bindings regenerate-bindings --event event.json ## Systemd-Local Backend -`codex-flow-systemd-local` is the first execution backend. Patchbay posts +`codex-flow-systemd-local` is the first execution backend. Patch posts generic `FlowEvent` JSON to this service; the service persists events and runs to SQLite, discovers matching flow steps, and starts each step locally. @@ -141,14 +141,19 @@ Endpoints: - `GET /runs/`: inspect one recorded run - `GET /healthz`: health check +When `CODEX_FLOW_BACKEND_SECRET` is configured, HTTP dispatches must include an +HMAC SHA-256 body signature. The preferred header is `x-flow-signature-256`; +`x-patch-flow-signature-256` and the legacy `x-patchbay-flow-signature-256` +are accepted during the Patch migration. + The CLI exposes the same operational surface: ```bash bun run flow:backend list-events --limit 20 -bun run flow:backend show-event 'patchbay:source:entry:upstream.release' +bun run flow:backend show-event 'patch:source:entry:upstream.release' bun run flow:backend list-runs --status failed --limit 20 bun run flow:backend show-run run_abc123 -bun run flow:backend replay-event 'patchbay:source:entry:upstream.release' --wait +bun run flow:backend replay-event 'patch:source:entry:upstream.release' --wait ``` Normal dispatch is idempotent by `event.id`: a duplicate `POST /events` returns @@ -190,7 +195,7 @@ running Codex or shell work executes. A future Convex backend should: - receive heartbeats and final `FLOW_RESULT` records from that worker - expose programmatic fire/retry/cancel APIs -This keeps Patchbay dispatch-only, keeps Convex durable, and keeps process-heavy +This keeps Patch dispatch-only, keeps Convex durable, and keeps process-heavy work on infrastructure that can run Codex, Bun, Git, Cargo, and system tools. The reusable component package now lives at