[upstream-queue] feat: optional/anonymous auth mode (AUTH_MODE) (PR-2/8)#5
Open
damienriehl wants to merge 4 commits into
Open
[upstream-queue] feat: optional/anonymous auth mode (AUTH_MODE) (PR-2/8)#5damienriehl wants to merge 4 commits into
damienriehl wants to merge 4 commits into
Conversation
…odes - Add auth_mode field (required/optional/disabled) to Settings class in config.py - Add ANONYMOUS_USER constant to auth.py (id=anonymous, roles=[viewer]) - Add early returns in get_current_user, get_current_user_optional, get_current_user_with_token for disabled mode - Optional mode: RequiredUser still 401s (write protection), OptionalUser returns None (browse works)
…disabled) - Test ANONYMOUS_USER properties (id, roles, type, not superadmin) - Test disabled mode: all three auth functions return ANONYMOUS_USER - Test required mode: get_current_user raises 401, get_current_user_optional returns None - Test optional mode: RequiredUser raises 401 (write protection), OptionalUser returns None (browse works)
/ce:review (PR-2) follow-ups: - config.py: auth_mode str -> Literal[required|optional|disabled] so pydantic-settings rejects config typos at startup (fail-fast) instead of silently falling through to required behavior. - test_auth_disabled.py: add test_disabled_ignores_valid_credentials proving disabled mode ignores even a valid Bearer token (everyone anonymous viewer). WS-auth parity (authenticate_ws does not consult auth_mode) is intentionally NOT changed here — it is new work beyond the extracted phase-08 slice; noted on the PR for a follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ELAutiUDrKdGf2vZAwgt9Q
Author
|
| Sev | Finding | Resolution |
|---|---|---|
| MED | auth_mode was a bare str — a typo silently falls through to required behavior |
Fixed (c4a4a36) — now Literal["required","optional","disabled"]; pydantic-settings rejects bad values at startup |
| MED | WebSocket auth (ws_auth.authenticate_ws) never consults auth_mode — in disabled mode REST goes anonymous but WS collab still hard-requires a token |
Deferred + noted — this is new work beyond the extracted phase-08 slice (the upstream feature didn't touch WS auth); real-time collab requiring identity is defensible. Flagging for a follow-up PR rather than silently widening this slice. Direction is the more restrictive one (no security hole). |
| MED | TestAuthModeOptional/TestAuthModeRequired don't actually branch on the mode value (no "optional" vs "required" conditional exists) → false coverage impression |
Kept as intent-documentation; the genuinely new behavior is covered by the disabled tests + the new credential-ignoring test below |
| LOW | No test for "disabled ignores a valid token" | Fixed (c4a4a36) — test_disabled_ignores_valid_credentials |
| NIT | "anonymous" magic-string token sentinel |
Kept — access_token is currently dead downstream (# noqa: ARG002); noted for when/if it's wired up |
Auth suite 43 passed (was 42); ruff + mypy clean.
authenticate_ws hard-required a token regardless of settings.auth_mode, so a disabled/optional deployment admitted anonymous callers on its HTTP API but rejected them at the WebSocket handshake. Resolve caller identity per auth_mode mirroring core.auth: - disabled -> ANONYMOUS_USER, no token required - optional -> absent/invalid token downgrades to anonymous (get_current_user_optional) - required -> valid token mandatory (unchanged) Project-access check still gates private projects for anonymous callers. +7 parity tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018eQ2CoAwpGv9Q8vBhuGGtH
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.
PR-2 of 8 — LLM node-expansion drain: "optional/anonymous auth mode" (api)
Queue policy (TODAY-2026-07-07): staged INSIDE the alea fork, base
dev, UNMERGED (dev/mainstay pure upstream mirrors). Retarget to CatholicOS decided post-today. Tracked inontokit-web/docs/UPSTREAM-TRACKING.md(A2.2). Paired with web PR-2 (alea-institute/ontokit-web#5) — the frontend AUTH_MODE gating.What this is
The backend half of
AUTH_MODE=required|optional|disabled— lets the API serve anonymous browse without a Zitadel token. Cherry-picked from thellm-helperlineage (phase 08-optional-auth, commits0bd679b,f98f3e0) onto freshorigin/dev.ontokit/core/config.py— addsauth_mode: str = "required"toSettings(default = unchanged behavior).ontokit/core/auth.py— addsANONYMOUS_USERconstant (id="anonymous",roles=["viewer"]— least privilege) and an early-return guard for disabled mode in all three auth dependencies:get_current_user,get_current_user_optional,get_current_user_with_token.tests/unit/test_auth_disabled.py(new, 11 tests) — covers ANONYMOUS_USER properties + all three modes across all three dependency functions.Mode semantics:
required(default): unchanged — token enforced, 401 without it.optional: unchanged —OptionalUserreturnsNonefor no credentials (browse works),RequiredUserstill 401s (write protection). No code path change needed.disabled: the three dependencies returnANONYMOUS_USER(viewer-only) instead of enforcing a token.Purely additive (+150 lines, 0 deletions); backward compatible.
Verification (all green)
pytest tests/unit/test_auth_disabled.py— 11 passedpytestfull auth suite (test_auth_core,test_auth,test_auth_disabled) — 42 passed (confirms no regression in required/optional paths my change touches)Note for review
auth_modeis a freestr(not anEnum/Literal). An unrecognized value (e.g. a typo) falls through to enforcing auth (fail-closed / safe default), but aLiteral["required","optional","disabled"]would surface config typos at load time — flagged for reviewer preference before upstream merge.Merge order: 0 → 1 → 2 → 3 → 4 → 5 → 6 → (7). Pairs with web PR-2. Backend endpoints for PR-3+ (
/llm/*) are not part of this slice.