Skip to content

Wave 1 — API auth, structured outputs, sandbox env scrub - #2

Merged
tobyvee merged 1 commit into
wave-0-foundationsfrom
wave-1-safety-and-enablers
Jun 27, 2026
Merged

tobyvee merged 1 commit into
wave-0-foundationsfrom
wave-1-safety-and-enablers

Conversation

@tobyvee

@tobyvee tobyvee commented Jun 27, 2026

Copy link
Copy Markdown
Owner

Wave 1 — safety + enablers

Implements Wave 1 of the roadmap (project/ROADMAP.md). Stacked on #1 — base is
wave-0-foundations so this diff shows only the Wave 1 changes; retarget to main once #1 merges.

ENG-004 — API auth + approval identity

  • apps/server/src/auth.ts: bearer-token middleware on /api/* (timing-safe compare) — mutating
    (non-GET) requests require Authorization: Bearer $API_AUTH_TOKEN; GET read views stay open.
  • Principal resolved from X-Actor (default operator); approval endpoints append an
    approval_decided audit event stamped with the principal (payload.by), so the append-only log
    records who released each gate.
  • Open "dev mode" + loud startup warning when API_AUTH_TOKEN is unset (keeps docker compose up
    working). 9 auth tests (pure checkAuth + middleware via app.request).

ENG-009 — Structured outputs for agent parsing

  • WorkerInput.outputSchema; the API backend emits output_config: { format: { type: "json_schema", schema } } so responses are schema-constrained JSON. Hand-written schemas (schemas.ts) for the
    proposal / tickets / verdict; the CLI backend keeps the prose-parse fallback.
  • ProposedChanges.parsed lets implementTicket audit "agent output could not be parsed" distinctly
    from "no file changes proposed".

ENG-005 — Scrub the CLI sandbox env

  • sandboxEnv() forwards only a benign allow-list (PATH/HOME/XDG/locale) to the claude -p child;
    ANTHROPIC_API_KEY / GITHUB_TOKEN / DATABASE_URL and everything else are withheld. Opt-in
    widening via AGENT_SANDBOX_ENV_PASSTHROUGH.

Verification

pnpm typecheck · pnpm lint · pnpm test (73 tests) all green.

Follow-ups (noted in the tickets)

  • ENG-004 activates when API_AUTH_TOKEN is set; require-by-default and protecting read views are an
    operator hardening decision. First-class persisted approvals (with decidedBy on the entity) are
    ENG-006.

🤖 Generated with Claude Code

…04, ENG-009, ENG-005)

ENG-004: bearer-token auth middleware on /api/* (apps/server/src/auth.ts) — mutating requests require Authorization: Bearer $API_AUTH_TOKEN (timing-safe), GET read views open; principal from X-Actor; approval endpoints append an approval_decided audit event stamped with the principal; open dev-mode + startup warning when unset. ENG-009: WorkerInput.outputSchema; API backend emits output_config.format (json_schema); hand-written schemas for proposal/tickets/verdict; CLI keeps prose fallback; ProposedChanges.parsed distinguishes parse failure from empty change set. ENG-005: sandboxEnv() forwards only an allow-list to the claude -p child, withholding host secrets. typecheck + lint + 73 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant