fabro/lib/crates
Bryan Helmkamp 93452001a1
feat(api): require typed PermissionLevel on session create (#300)
## Summary

- `POST /api/v1/sessions` now requires `permissions` as a typed enum
(`read-only` | `read-write` | `full`) instead of accepting an optional
plain string.
- Removes the silent fallback at `sessions.rs:906-911` where unknown
values (e.g. `"readonly"`) were coerced to `read-write` — a real
security footgun: a client trying to lock the agent down would get write
access instead.
- Invalid or missing values are now rejected by axum's `Json` extractor
with `422 Unprocessable Entity`.

## Approach

- New `PermissionLevel` OpenAPI schema (`type: string, enum: [...]`).
- Moves `PermissionLevel` from `fabro_agent::cli` to
`fabro_types::session` so `fabro-api` can `with_replacement` it without
a circular dep. `fabro_agent::cli::PermissionLevel` remains as a `pub
use` re-export so existing call sites keep working.
- `SessionRecord.permissions` becomes required and non-nullable for
coherence — every created session has a concrete level.
- `build_tool_approval` in the server takes `PermissionLevel` directly;
the string-match fallback is deleted.
- CLI's `session_permissions` returns a concrete `PermissionLevel`
(defaults to `read-write` when neither flag nor settings provide one)
and is sent explicitly on every request.

## Scope notes

Confirmed out of scope and not addressed here:
- Mid-session model/permission switching
- Interactive tool approval / HITL

## Breaking change

The `permissions` field is now required on `CreateSessionRequest` and
non-nullable on `SessionRecord`. Existing on-disk session records
persisted with `"permissions": null` will fail to deserialize.
Acceptable per project policy (no migration); local dev users may need
to clear `~/.fabro/storage/sessions/` once.

## Test plan

- [x] `cargo build --workspace`
- [x] `cargo nextest run -p fabro-api` — 125/125 (includes new
`permission_level_round_trip` parity tests)
- [x] `cargo nextest run -p fabro-server` — 554/554 (includes new 422
tests for missing + invalid permissions)
- [x] `cargo nextest run -p fabro-cli` — 892/892
- [x] `cargo +nightly-2026-04-14 clippy --workspace --all-targets -- -D
warnings`
- [x] `cargo +nightly-2026-04-14 fmt --check --all`
- [x] `bun run generate` on `fabro-api-client` — emits typed
`PermissionLevel` union and required field on `CreateSessionRequest`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 17:15:20 -04:00
..
build-support fix(build): refresh embedded git sha on branch commits 2026-05-09 14:10:04 -04:00
fabro-acp feat(errors): add structured failure diagnostics (#277) 2026-05-16 13:25:07 -04:00
fabro-agent feat(api): require typed PermissionLevel on session create (#300) 2026-05-17 17:15:20 -04:00
fabro-api feat(api): require typed PermissionLevel on session create (#300) 2026-05-17 17:15:20 -04:00
fabro-auth refactor(llm): split provider identity from adapters (#280) 2026-05-16 13:13:41 -04:00
fabro-checkpoint Make git metadata sandbox-native 2026-04-27 21:43:15 -07:00
fabro-cli feat(api): require typed PermissionLevel on session create (#300) 2026-05-17 17:15:20 -04:00
fabro-client feat(session): add server-backed agent sessions (#278) 2026-05-16 17:25:05 -04:00
fabro-config feat(llm): support agent profile overrides (#291) 2026-05-16 17:40:59 -04:00
fabro-core feat(errors): add structured failure diagnostics (#277) 2026-05-16 13:25:07 -04:00
fabro-dev feat(llm): support agent profile overrides (#291) 2026-05-16 17:40:59 -04:00
fabro-devcontainer refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-dump feat(sandbox): prepare clone layout for multi-repo runs (#250) 2026-05-14 09:38:20 -04:00
fabro-github fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-graphviz refactor: remove compatibility shims (#281) 2026-05-16 15:29:25 -04:00
fabro-hooks refactor(llm): split provider identity from adapters (#280) 2026-05-16 13:13:41 -04:00
fabro-http refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-install fix(server): default foreground logs to stdout 2026-05-06 12:41:52 -04:00
fabro-interview Wire end-to-end steering for running agents (#209) 2026-05-05 15:34:16 -04:00
fabro-llm refactor(llm): split provider identity from adapters (#280) 2026-05-16 13:13:41 -04:00
fabro-macros refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-manifest fix(validate): treat undefined template vars in @file prompts as warnings (#290) 2026-05-16 17:31:22 -04:00
fabro-mcp feat(cli): add Fabro MCP server (#236) 2026-05-11 18:20:50 -04:00
fabro-mcp-server feat(mcp): support run parent relationships (#295) 2026-05-17 12:26:18 -04:00
fabro-model feat(llm): support agent profile overrides (#291) 2026-05-16 17:40:59 -04:00
fabro-oauth fix(error): preserve remaining error context 2026-05-02 10:51:15 -04:00
fabro-options-metadata refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-proc refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-redact refactor(integrations): make chat integrations Slack-only 2026-05-09 11:43:16 -04:00
fabro-sandbox fix(sandbox): clone Daytona repos under /home/daytona/repos (#285) 2026-05-16 13:47:54 -04:00
fabro-server feat(api): require typed PermissionLevel on session create (#300) 2026-05-17 17:15:20 -04:00
fabro-slack feat(slack): render plan summary + run link in interview messages (re #253, stacked on #252) (#254) 2026-05-13 07:41:54 -04:00
fabro-spa feat(dev): gitignore embedded spa assets 2026-04-26 21:31:11 -04:00
fabro-static refactor(llm): split provider identity from adapters (#280) 2026-05-16 13:13:41 -04:00
fabro-store feat(web): add Children tab to Run detail page (#294) 2026-05-17 10:21:40 -04:00
fabro-telemetry refactor(workflow): remove retro stage (#230) 2026-05-09 10:18:20 -04:00
fabro-template feat(template): add source-aware diagnostics (#292) 2026-05-16 18:47:37 -04:00
fabro-test feat(cli): add Fabro MCP server (#236) 2026-05-11 18:20:50 -04:00
fabro-tracker fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-types feat(api): require typed PermissionLevel on session create (#300) 2026-05-17 17:15:20 -04:00
fabro-util feat(errors): add structured failure diagnostics (#277) 2026-05-16 13:25:07 -04:00
fabro-validate feat(template): add source-aware diagnostics (#292) 2026-05-16 18:47:37 -04:00
fabro-vault refactor(api): unify secret metadata types 2026-04-29 20:26:13 -04:00
fabro-workflow feat(template): add source-aware diagnostics (#292) 2026-05-16 18:47:37 -04:00