You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(api): tenant-scoped task API authentication with fail-closed token mode (#3) (#51)
Closes#3.
Gate GET /api/github/tasks behind an [api] config section: 'open' keeps the
unauthenticated local-development path (doctor warns), 'token' requires
bearer tokens and fails closed. A service_token grants operator-wide
visibility; each [[api.tenants]] token is scoped server-side to one
installation id, optionally narrowed to specific repositories — the scope is
enforced in the store query, not the client.
Token comparison is constant-time (fixed-length digest equality), the 401
body is uniform and reveals nothing about existing data, and every read —
allowed or denied — lands in a new api_audit table (schema v3) with caller,
scope, action, and result.
Two-installation route tests prove tenant A cannot list tenant B's tasks,
missing/invalid tokens fail closed, repo narrowing holds inside an
installation, and the audit trail records each read. docs/security.md and
config/example.toml document the boundary; doctor validates token-mode
misconfigurations and duplicate tokens.
Signed-off-by: Val Alexander <bunsthedev@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy file name to clipboardExpand all lines: README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -160,7 +160,7 @@ duplicate comments.
160
160
| Headless execution contract | Locked (v1) | Brief, result envelope, exit codes, and git-auth channel are pinned in [`docs/headless-contract.md`](docs/headless-contract.md) with JSON Schemas, golden fixtures, and a conformance test. |
161
161
|`coven-code --headless` execution | Partial | Worker spawns headless sessions with a tokenless session brief and enforces task timeouts; result quality depends on the runtime. |
162
162
| Pull request creation | Partial | Opens draft PRs from session results against the repository's resolved default/base branch. |
163
-
| CovenCave task polling |Partial| Task API is served from the durable store and survives restarts; hosted control-plane auth is planned (#3). |
163
+
| CovenCave task polling |Implemented| Task API served from the durable store, survives restarts, and is gated by the tenant boundary — `token` mode fails closed, tenant tokens are installation-scoped, and every read is audited (see [docs/security.md](docs/security.md)). |
164
164
| Durable queue / task store | Implemented | Deliveries deduplicated by `X-GitHub-Delivery` before GitHub hears success; the SQLite `tasks` table is the queue (atomic claims, no drop path) and interrupted work is requeued at startup ([design](docs/durable-task-store.md)). |
165
165
| Hosted tier | Planned | See [Hosted vs self-hosted](docs/hosted-vs-self-hosted.md). |
"tokens are configured but api.mode is 'open' — they are ignored; set api.mode = \"token\" to enforce them.",
415
+
));
416
+
}else{
417
+
out.push(Diagnostic::warning(
418
+
"api.mode",
419
+
"the task API is unauthenticated (api.mode = \"open\") — fine for local development, never expose it publicly; hosted deployments must use \"token\".",
0 commit comments