fix(config): derive mode flags in Settings.__post_init__; address review round 2
The integration jobs for `mcp-multi-user-basic` and `mcp-login-flow`
were failing with HTTP 500s. Root cause: `get_settings()` builds a
fresh Settings on every call (not cached). Commits 3 and 4 set the
derived `enable_login_flow` / `enable_multi_user_basic_auth` flags as
a side effect of `detect_auth_mode`. detect_auth_mode runs once at
startup, against the Settings instance owned by `validate_configuration`.
Every per-request call site that does `settings = get_settings()` got
a fresh Settings with both flags at their default `False` (since the
env-var aliases were dropped), causing the multi-user dispatcher in
`context.py` to take the wrong branch and crash.
Fix: move the derivation into `Settings.__post_init__`. Every Settings
instance now carries correct flags from the moment it's constructed —
no caching needed, no mutation-after-construction race. detect_auth_mode
becomes a pure reader of the already-derived state.
The legacy env-var deprecation check moves with it. It also picks up
the reviewer's truthy-string fix: previously `os.getenv(legacy)` fired
for the literal string "false" (a non-empty Python string is truthy),
which would have errored on any user with a leftover
`ENABLE_LOGIN_FLOW=false` in their `.env`. The check now only fires
when the value lowercases to one of {"1", "true", "yes", "on"}.
- nextcloud_mcp_server/config.py: extend Settings.__post_init__ with
the legacy-deprecation block and the derived-flag derivation
(resolve mode from deployment_mode + username/password, set flags).
- nextcloud_mcp_server/config_validators.py: drop the
`_sync_derived_flags` helper (superseded by __post_init__). Drop the
legacy-env-var deprecation block (moved). `detect_auth_mode` is now
pure — no mutation. Drop the now-unused `import os`.
- tests/unit/test_config_validators.py: legacy-env-var tests now
expect `ValueError` at `Settings(...)` construction (via `get_settings()`),
not at `detect_auth_mode` call. Added two new tests:
* `test_legacy_env_var_check_ignores_falsy_strings` — pins the
truthy-string fix (reviewer round 2 finding).
* `test_derived_flags_stable_across_get_settings_calls` — regression
test pinning the integration-test fix (two consecutive
`get_settings()` calls return Settings instances with the same
derived flags).
Also reworked `test_login_flow_mode_auto_derives_enable_login_flow_flag`
to assert at-construction derivation (not the old mutation pattern).
- docs/configuration-migration-v2.md: dropped the duplicate
`MCP_DEPLOYMENT_MODE=multi_user_basic` line (review round 2 nit — a
sed artifact from commit 4).
- docs/ADR-021-configuration-consolidation.md: sed-replaced the in-body
`MCP_DEPLOYMENT_MODE=oauth_single_audience` examples with `login_flow`
(review round 2 nit — only the status header was updated in commit 4).
- tests/conftest.py: docstring comment for the multi-user-basic fixture
switched from `ENABLE_MULTI_USER_BASIC_AUTH=true` to
`MCP_DEPLOYMENT_MODE=multi_user_basic` (review round 2 nit).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
282c245da1
commit
6e7c821761
@@ -607,6 +607,49 @@ class Settings:
|
||||
f"Smaller chunks may lose context. Consider using at least 1024 characters."
|
||||
)
|
||||
|
||||
# --- ADR-022 follow-up: deployment mode is the single source of truth ---
|
||||
# The ENABLE_MULTI_USER_BASIC_AUTH and ENABLE_LOGIN_FLOW env vars were
|
||||
# removed in favour of MCP_DEPLOYMENT_MODE. We do TWO things here:
|
||||
#
|
||||
# 1. Loud-fail if a user still has either legacy env var set to a
|
||||
# truthy value (silent removal would have flipped them into the
|
||||
# wrong runtime mode). Only fires for truthy strings, so an
|
||||
# explicit `ENABLE_LOGIN_FLOW=false` in a leftover .env passes
|
||||
# through harmlessly.
|
||||
# 2. Derive `enable_login_flow` and `enable_multi_user_basic_auth`
|
||||
# from the resolved deployment mode here, in __post_init__, so
|
||||
# every Settings instance carries correct flags. (`get_settings()`
|
||||
# builds a fresh Settings on each call — without this, the
|
||||
# mutation that used to live in detect_auth_mode would only stick
|
||||
# on the startup Settings instance, leaving per-request handlers
|
||||
# with default False values.)
|
||||
_truthy = {"1", "true", "yes", "on"}
|
||||
for _legacy, _replacement in (
|
||||
("ENABLE_MULTI_USER_BASIC_AUTH", "multi_user_basic"),
|
||||
("ENABLE_LOGIN_FLOW", "login_flow"),
|
||||
):
|
||||
if os.environ.get(_legacy, "").strip().lower() in _truthy:
|
||||
raise ValueError(
|
||||
f"{_legacy} is no longer read from the environment. "
|
||||
f"Set MCP_DEPLOYMENT_MODE={_replacement} instead "
|
||||
"(ADR-022). The deployment mode is the single source "
|
||||
"of truth for selecting an auth flow."
|
||||
)
|
||||
|
||||
resolved_mode = (self.deployment_mode or "").strip().lower()
|
||||
if not resolved_mode:
|
||||
if self.nextcloud_username and self.nextcloud_password:
|
||||
resolved_mode = "single_user_basic"
|
||||
else:
|
||||
# Default multi-user mode is Login Flow v2 (browser-based
|
||||
# app-password acquisition); the un-augmented OAuth bearer
|
||||
# pass-through it replaced needed unmerged Nextcloud
|
||||
# user_oidc patches and is no longer supported.
|
||||
resolved_mode = "login_flow"
|
||||
|
||||
self.enable_multi_user_basic_auth = resolved_mode == "multi_user_basic"
|
||||
self.enable_login_flow = resolved_mode == "login_flow"
|
||||
|
||||
def get_embedding_model_name(self) -> str:
|
||||
"""
|
||||
Get the active embedding model name based on provider priority.
|
||||
|
||||
Reference in New Issue
Block a user