security(api): require bearer-token auth on all endpoints (closes #179)#193
Open
jeremylongshore wants to merge 3 commits into
Open
security(api): require bearer-token auth on all endpoints (closes #179)#193jeremylongshore wants to merge 3 commits into
jeremylongshore wants to merge 3 commits into
Conversation
…llwaveSolutions#179) Every endpoint except /health now requires `Authorization: Bearer <key>`. 127.0.0.1 is not an authorization boundary: on the multi-agent same-box deployment pattern any local process could read the index via /query or wipe it via DELETE /index (OWASP API1/API2:2023). Implements the three adjustments green-lit on SpillwaveSolutions#179: - Q1 secure-by-default: key auto-generated by `agent-brain init` into .agent-brain/runtime.json (mode 600); server backfills on first start; refuses to start without a key unless --insecure (loud warning), like Postgres --allow-empty-password / Redis protected-mode no. CLI sends the key automatically so single-user dev stays frictionless. - Q2 Authorization: Bearer (not X-API-Key) for forward-compat with the MCP v4 OAuth 2.1 work (SpillwaveSolutions#188). - Q3 /docs /redoc /openapi.json gated unless DEBUG=true. verify_bearer_token uses constant-time comparison, 401s on missing/bad credentials, and fails closed (503) if auth is on but misconfigured. Tests: server 17 (unit branches + HTTP 401/200 + insecure + key persistence + refuse-to-start), CLI 7 (key resolution + bearer header). Existing suite kept green via a session-scoped auth-bypass fixture. server:pr-qa-gate: 1219 passed, 79.26% coverage. No version bumps.
…illwaveSolutions#179) `agent-brain init` now writes runtime.json to store the API key (Issue SpillwaveSolutions#179), so `agent-brain stop` with no server running finds a PID-less runtime and was reporting "No server PID found in runtime state" instead of "No server running" — breaking test_stop_no_server_running. A runtime.json without a PID means no server is running; report that. JSON status stays "not_running".
…pillwaveSolutions#179) Match the repo convention (security PRs add a [Unreleased] ### Security entry to docs/CHANGELOG.md, as SpillwaveSolutions#180 and SpillwaveSolutions#181 did) so the maintainer doesn't have to add it on review.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
agent-brain-serverexposed every endpoint with no authentication (#179). On the multi-agent same-box deployment pattern, any local process could read the whole index via/queryor wipe it viaDELETE /index—127.0.0.1is not an authorization boundary (OWASP API1/API2:2023).This adds bearer-token auth on every endpoint except
/health, implementing the three adjustments you green-lit on #179.How
Q1 — secure by default (not opt-in).
agent-brain initauto-generates a key (secrets.token_urlsafe(32)) into.agent-brain/runtime.jsonat mode600; the server backfills one on first start if absent (smooth upgrade for existing installs). The server refuses to start without a key unless--insecureis passed (loud warning) — mirroring Postgres--allow-empty-password/ Redisprotected-mode no. The CLI reads the key fromruntime.jsonand sends it automatically, so single-user dev stays frictionless.Q2 —
Authorization: Bearer(notX-API-Key), for forward-compat with the MCP v4 OAuth 2.1 work (#188) — one scheme that evolves from a static key to OAuth-issued bearer tokens.Q3 — docs gated.
/docs,/redoc,/openapi.jsonare served only whenDEBUG=true, so shared/prod hosts don't leak the API surface.verify_bearer_tokenuses constant-time comparison, 401s on missing/malformed/wrong credentials, and fails closed (503) if auth is required but no key is configured.Tests
tests/test_api_auth.py, 17): every dependency branch (valid / missing / wrong / wrong-scheme / insecure / misconfigured), HTTP integration (/healthopen,/query401 without token, 401 wrong, 200 right, insecure bypass), key generation +runtime.jsonmode-600 persistence + refuse-to-start.tests/test_api_key_auth.py, 7):get_api_keyresolution (env >runtime.json> none) andAuthorization: Bearerheader attachment.task server:pr-qa-gate: 1219 passed, 79.26% coverage.Notes
security/issue-179-bearer-authper your<type>/issue-<N>-<slug>convention.--insecureopt-out preserved for trusted single-user localhost dev.Closes #179.
intentsolutions.io