feat(werkbank): runner queue endpoints + result persistence (WB-05) #207

Merged
sharang merged 1 commits from feat/werkbank-runner-endpoints into main 2026-07-17 11:42:30 +00:00
Owner

The control-plane side of the pull API — implements sharang/werkbank#6. A Werkbank runner can now reach a real queue end-to-end.

Endpoints (/api/v1/werkbank/jobs/*)

Thin handlers over the WB-02 JobQueue, tenant-scoped from the request's tenant:

  • POST …/lease — lease the oldest runnable job (200 + LeasedJob) or 204 when empty.
  • POST …/heartbeat — extend the lease (200 + HeartbeatAck), or 409 when the lease is lost.
  • POST …/complete — record the terminal result, then persist the runner's findings + DAST findings against the job's target (dedup'd by fingerprint) — so a job run by a remote runner lands the same findings an in-process run would.

Auth

A static WERKBANK_RUNNER_TOKEN bearer (require_runner_token), mounted only when the token is set — mirroring the admin API, and deliberately not a Keycloak JWT (a runner acts across tenants). /api/v1/werkbank/* is added to the JWT PUBLIC_PREFIXES so it routes to the runner-token gate rather than the customer-JWT path.

Shared contract

LeaseRequest / HeartbeatRequest / CompleteRequest / CompleteResponse live in compliance-core::models::werkbank, so the runner (client, in the werkbank repo) and the control plane (server) compile against one set of types.

Tests

3 HTTP integration tests against a live Mongo — lease→complete→persist, empty-queue 204, and the bearer-token gate (missing/wrong → 401) — plus a token-compare unit test. Skip cleanly with no Mongo. clippy + fmt clean.

Follow-up

Wiring the scan pipeline to enqueue plc-provision jobs needs an artifact-fetch path so the runner can pull the program blob — tracked with the on-prem work (werkbank#8). The werkbank runner will switch from its local transport structs to these shared compliance-core types once this merges to main.

🤖 Generated with Claude Code

The control-plane side of the pull API — implements sharang/werkbank#6. A Werkbank runner can now reach a real queue end-to-end. ## Endpoints (`/api/v1/werkbank/jobs/*`) Thin handlers over the WB-02 `JobQueue`, tenant-scoped from the request's `tenant`: - **`POST …/lease`** — lease the oldest runnable job (`200` + `LeasedJob`) or `204` when empty. - **`POST …/heartbeat`** — extend the lease (`200` + `HeartbeatAck`), or `409` when the lease is lost. - **`POST …/complete`** — record the terminal result, then **persist** the runner's findings + DAST findings against the job's target (dedup'd by fingerprint) — so a job run by a remote runner lands the same findings an in-process run would. ## Auth A static **`WERKBANK_RUNNER_TOKEN`** bearer (`require_runner_token`), mounted only when the token is set — mirroring the admin API, and deliberately **not** a Keycloak JWT (a runner acts across tenants). `/api/v1/werkbank/*` is added to the JWT `PUBLIC_PREFIXES` so it routes to the runner-token gate rather than the customer-JWT path. ## Shared contract `LeaseRequest` / `HeartbeatRequest` / `CompleteRequest` / `CompleteResponse` live in `compliance-core::models::werkbank`, so the runner (client, in the werkbank repo) and the control plane (server) compile against one set of types. ## Tests 3 HTTP integration tests against a live Mongo — lease→complete→persist, empty-queue `204`, and the bearer-token gate (missing/wrong → `401`) — plus a token-compare unit test. Skip cleanly with no Mongo. clippy + fmt clean. ## Follow-up Wiring the scan pipeline to *enqueue* `plc-provision` jobs needs an artifact-fetch path so the runner can pull the program blob — tracked with the on-prem work (`werkbank#8`). The werkbank runner will switch from its local transport structs to these shared `compliance-core` types once this merges to `main`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
sharang added 1 commit 2026-07-17 10:28:20 +00:00
feat(werkbank): runner queue endpoints + result persistence (WB-05)
CI / Deploy Agent (pull_request) Has been skipped
CI / Deploy Dashboard (pull_request) Has been skipped
CI / Deploy Docs (pull_request) Has been skipped
CI / Check (pull_request) Successful in 5m35s
CI / Detect Changes (pull_request) Has been skipped
CI / Deploy MCP (pull_request) Has been skipped
420af3af9e
The control-plane side of the pull API (implements sharang/werkbank#6), so a
Werkbank runner can reach a real queue end-to-end:

- POST /api/v1/werkbank/jobs/{lease,heartbeat,complete} — thin handlers over the
  JobQueue (WB-02), tenant-scoped from the request's `tenant` (db_pool
  .for_tenant_id). lease→204 when empty; heartbeat→409 on a lost lease.
- Machine auth: a static WERKBANK_RUNNER_TOKEN bearer (require_runner_token),
  mounted only when the token is set — like the admin API, and NOT a Keycloak JWT
  (a runner acts across tenants). /api/v1/werkbank/* is added to the JWT
  PUBLIC_PREFIXES so it routes to the runner-token gate, not the customer-JWT one.
- On completion, the runner's findings + DAST findings are persisted against the
  job's target (dedup'd by fingerprint), so a job run by a remote runner lands
  the same findings an in-process run would.
- Shared transport types (LeaseRequest/HeartbeatRequest/CompleteRequest/
  CompleteResponse) live in compliance-core so the runner (client) and control
  plane (server) agree on shapes.

Tests: 3 HTTP integration tests against a live Mongo (lease→complete→persist,
empty-queue 204, and the bearer-token gate) + a token-compare unit test. Skips
cleanly with no Mongo. clippy + fmt clean.

Follow-up: wiring the scan pipeline to enqueue plc-provision jobs needs an
artifact-fetch path for the runner (so it can pull the program blob); tracked
with the on-prem work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
sharang merged commit 91a87677bc into main 2026-07-17 11:42:30 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sharang/compliance-scanner-agent#207