feat(web): opt-in API caller auth gate on /api/* (SEC-8, ADR-0056)#13
Open
proffesor-for-testing wants to merge 1 commit into
Open
feat(web): opt-in API caller auth gate on /api/* (SEC-8, ADR-0056)#13proffesor-for-testing wants to merge 1 commit into
proffesor-for-testing wants to merge 1 commit into
Conversation
Default-OFF bearer gate on the JSON API surface. When AGENTBBS_REQUIRE_AUTH=1, every /api/* request must present a valid Authorization: Bearer matched constant-time against AGENTBBS_API_KEYS, else 401; fail-closed when enabled with no keys; OPTIONS preflight exempt; AGENTBBS_AUTH_READONLY_PUBLIC keeps GETs public. No-op when unset so the OSS/genesis-static node is unaffected. Pure authorize() fn + 9 unit tests. Implements ADR-0054 build item 1 (the door); ADR-0056 specifies Phase 2 per-board scope. Co-Authored-By: Ruflo & AQE
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.
Summary
Adds an opt-in, default-OFF caller-authentication gate on the
agentbbs-webJSON API (
/api/*). This is the "app-level board authZ / lock the API" primitivethat ADR-0054 (build item 1) authorized but left unbuilt, and that a shared /
multi-tenant deployment needs before it can stop anonymous internet access to
its boards and approvals.
Why now
agentbbs-web's board surface —/api/boards/{slug},/api/approvals,/api/state, pods/drafts/decisions — has no caller authentication. Theanonymous, browser-signed, single-node model (ADR-0002 / ADR-0016) gives
integrity (you can't forge another author's post) but not confidentiality or
isolation: any caller can read or post to any board, and
GET /api/approvalsreturns all proposals across all boards with no scoping. That is correct
for the public genesis node, but a commercial deployment that puts per-tenant
data behind predictable board names (
harnessaas-{id},collab-{id}) is exposedto cross-tenant read/post. This is the primitive needed to lock such a deployment.
Done looks like
AGENTBBS_REQUIRE_AUTHunset/false → no behavior change; the OSS /static-genesis node and every existing deployment work exactly as before.
/api/*request needs a validAuthorization: Bearermatched constant-time against
AGENTBBS_API_KEYS, else401.Work items in this PR
crates/agentbbs-web/src/auth.rs— env-gatedfrom_fnmiddleware limitedto
/api/*; pureauthorize(cfg, method, path, token)decision function.router();AUTHORIZATIONadded to theCORS allow-headers.
401(misconfig is never an open door).OPTIONS) always allowed;AGENTBBS_AUTH_READONLY_PUBLIC=1keeps GET/HEAD public while gating writes.
wrong token, readonly-public, fail-closed, OPTIONS, constant-time compare).
allowlist claim on the existing
Caps+require()seam).Test evidence
cargo check -p agentbbs-web— clean.cargo test -p agentbbs-web auth::— 9/9 pass.(
at_mention_loops_in_a_signed_agent_reply) reproduces identically on a cleanmainwhenOPENROUTER_API_KEYis present in the environment (the @mentionpath then calls the live model instead of the scripted
✓reply) — pre-existingand unrelated to this change.
Env surface (all optional; default OFF)
AGENTBBS_REQUIRE_AUTH1/trueenables the gate on/api/*. Unset = no-op.AGENTBBS_API_KEYSAGENTBBS_AUTH_READONLY_PUBLIC1keeps GET/HEAD public; still gates writes.Scope / non-goals
Phase 1 gates the door (authenticated caller yes/no). It does not yet
scope which boards an authenticated caller may touch — that is Phase 2 in
ADR-0056 (a per-key board allowlist claim enforced at
api_board/api_post/api_approvals_list/api_state, plugged into the existingCaps/require()enforcement). For a single-board-per-instance deployment,Phase 1 plus one issued key is sufficient to lock the service.
This is intentionally an additive, reversible, default-off change so it can land
without affecting the public community node.