refactor(config)!: derive enable_login_flow from mode, remove ENABLE_LOGIN_FLOW env var
Once OAUTH_SINGLE_AUDIENCE was renamed to LOGIN_FLOW and the validation
gate ensured the only meaningful configuration was
`MCP_DEPLOYMENT_MODE=login_flow + ENABLE_LOGIN_FLOW=true`, the two
controls became redundant. Setting the mode is sufficient; the
ENABLE_LOGIN_FLOW env var doesn't add information.
This commit makes the deployment mode the single source of truth for
the Login Flow v2 toggle:
- `nextcloud_mcp_server/config.py`: drop the `ENABLE_LOGIN_FLOW`
dynaconf env-var alias. The `enable_login_flow` field stays as an
internal attribute so the 6 runtime call sites (app.py x4,
context.py, auth/scope_authorization.py) keep working unchanged.
Updated field docstring to flag it as derived.
- `nextcloud_mcp_server/config_validators.py`:
- Drop `enable_login_flow` from `MODE_REQUIREMENTS[LOGIN_FLOW].required`.
- Drop the validation gate that required ENABLE_LOGIN_FLOW=true for
LOGIN_FLOW mode (no longer possible to misconfigure — the flag is
derived, not user input).
- Add `_sync_derived_flags()` helper called at every return path of
`detect_auth_mode` to set `settings.enable_login_flow` from the
resolved mode.
- `tests/unit/test_config_validators.py`: drop `enable_login_flow=True`
from happy-path fixtures (no longer needed — detection sets it).
Repurpose `test_login_flow_requires_enable_login_flow_flag` into
`test_login_flow_mode_auto_derives_enable_login_flow_flag` which
asserts the new auto-derivation behaviour for both LOGIN_FLOW and a
non-LOGIN_FLOW mode.
- `docker-compose.yml`: remove `ENABLE_LOGIN_FLOW=true` from the
`mcp-login-flow` and `mcp-keycloak` profiles.
- `env.sample`: remove the ENABLE_LOGIN_FLOW reference; the comment
on `MCP_DEPLOYMENT_MODE` now notes the derived flag.
- `docs/configuration.md`, `docs/authentication.md`,
`docs/login-flow-v2.md`, `docs/auth-flows.md`,
`docs/troubleshooting.md`, `docs/ADR-025-*.md`: replace
ENABLE_LOGIN_FLOW=true examples and references with
MCP_DEPLOYMENT_MODE=login_flow.
BREAKING CHANGE: `ENABLE_LOGIN_FLOW` is no longer read from the
environment. Anyone who relied on `ENABLE_LOGIN_FLOW=true` to activate
Login Flow v2 should set `MCP_DEPLOYMENT_MODE=login_flow` instead (or
rely on it being the default when no other auth env vars are set).
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
c74ef014ee
commit
df4994e860
@@ -458,7 +458,10 @@ class Settings:
|
||||
# and passes them through to Nextcloud APIs (no storage, stateless)
|
||||
enable_multi_user_basic_auth: bool = False
|
||||
|
||||
# Login Flow v2 settings (ADR-022)
|
||||
# Login Flow v2 derived flag (ADR-022). Internal — not user-settable.
|
||||
# Auto-set by detect_auth_mode() when the resolved deployment mode is
|
||||
# LOGIN_FLOW. Kept as a field for backward compat with the runtime call
|
||||
# sites that read it (app.py, context.py, scope_authorization.py).
|
||||
enable_login_flow: bool = False
|
||||
|
||||
# Token and webhook storage settings
|
||||
@@ -853,8 +856,10 @@ def get_settings() -> Settings:
|
||||
"userinfo_uri": "USERINFO_URI",
|
||||
# Multi-user BasicAuth pass-through mode
|
||||
"enable_multi_user_basic_auth": "ENABLE_MULTI_USER_BASIC_AUTH",
|
||||
# Login Flow v2 settings (ADR-022)
|
||||
"enable_login_flow": "ENABLE_LOGIN_FLOW",
|
||||
# NOTE: `enable_login_flow` used to have an `ENABLE_LOGIN_FLOW` env-var
|
||||
# alias here, but it was removed in the ADR-022 follow-up — the flag
|
||||
# is now derived from MCP_DEPLOYMENT_MODE=login_flow and set by
|
||||
# detect_auth_mode() so users only need to configure the mode.
|
||||
# Token and webhook storage settings
|
||||
"token_encryption_key": "TOKEN_ENCRYPTION_KEY",
|
||||
"token_storage_db": "TOKEN_STORAGE_DB",
|
||||
|
||||
@@ -114,7 +114,7 @@ MODE_REQUIREMENTS: dict[AuthMode, ModeRequirements] = {
|
||||
"Optional background sync using app passwords stored via Astrolabe.",
|
||||
),
|
||||
AuthMode.LOGIN_FLOW: ModeRequirements(
|
||||
required=["nextcloud_host", "enable_login_flow"],
|
||||
required=["nextcloud_host"],
|
||||
optional=[
|
||||
# OAuth credentials (uses DCR if not provided)
|
||||
"oidc_client_id",
|
||||
@@ -201,24 +201,42 @@ def detect_auth_mode(settings: Settings) -> AuthMode:
|
||||
|
||||
explicit_mode = mode_map[mode_str]
|
||||
logger.info(f"Using explicit deployment mode: {explicit_mode.value}")
|
||||
_sync_derived_flags(settings, explicit_mode)
|
||||
return explicit_mode
|
||||
|
||||
# Auto-detection (existing behavior)
|
||||
# Check for multi-user BasicAuth
|
||||
if settings.enable_multi_user_basic_auth:
|
||||
_sync_derived_flags(settings, AuthMode.MULTI_USER_BASIC)
|
||||
return AuthMode.MULTI_USER_BASIC
|
||||
|
||||
# Check for single-user BasicAuth (explicit credentials)
|
||||
if settings.nextcloud_username and settings.nextcloud_password:
|
||||
_sync_derived_flags(settings, AuthMode.SINGLE_USER_BASIC)
|
||||
return AuthMode.SINGLE_USER_BASIC
|
||||
|
||||
# Default: Login Flow v2 multi-user mode (browser-based app-password flow).
|
||||
# The un-augmented OAuth bearer pass-through it replaced required unmerged
|
||||
# Nextcloud user_oidc patches (see ADR-022); selecting LOGIN_FLOW without
|
||||
# ENABLE_LOGIN_FLOW=true fails validation below.
|
||||
# Nextcloud user_oidc patches (see ADR-022).
|
||||
_sync_derived_flags(settings, AuthMode.LOGIN_FLOW)
|
||||
return AuthMode.LOGIN_FLOW
|
||||
|
||||
|
||||
def _sync_derived_flags(settings: Settings, mode: AuthMode) -> None:
|
||||
"""Derive internal feature flags from the resolved deployment mode.
|
||||
|
||||
Some runtime call sites (app.py, context.py, auth/scope_authorization.py)
|
||||
still read individual boolean flags rather than passing the mode around.
|
||||
Keep those flags in sync with the mode here so the mode is the single
|
||||
source of truth and users don't have to set redundant env vars.
|
||||
|
||||
Specifically: `enable_login_flow` is now derived from
|
||||
`mode == AuthMode.LOGIN_FLOW`. The ENABLE_LOGIN_FLOW env-var alias was
|
||||
removed in the ADR-022 follow-up (PR #787).
|
||||
"""
|
||||
settings.enable_login_flow = mode == AuthMode.LOGIN_FLOW
|
||||
|
||||
|
||||
def validate_configuration(settings: Settings) -> tuple[AuthMode, list[str]]:
|
||||
"""Validate configuration for detected mode.
|
||||
|
||||
@@ -308,16 +326,12 @@ def validate_configuration(settings: Settings) -> tuple[AuthMode, list[str]]:
|
||||
)
|
||||
|
||||
if mode == AuthMode.LOGIN_FLOW:
|
||||
# ADR-022: LOGIN_FLOW requires the Login Flow v2 layer. The un-augmented
|
||||
# OAuth bearer pass-through (formerly OAUTH_SINGLE_AUDIENCE without
|
||||
# ENABLE_LOGIN_FLOW) needed unmerged Nextcloud user_oidc patches and
|
||||
# is no longer supported.
|
||||
if not settings.enable_login_flow:
|
||||
errors.append(
|
||||
f"[{mode.value}] ENABLE_LOGIN_FLOW=true is required for "
|
||||
"login_flow mode. The un-augmented OAuth path is no longer "
|
||||
"supported — see ADR-022."
|
||||
)
|
||||
# ADR-022 follow-up: the un-augmented OAuth bearer pass-through (the
|
||||
# old OAUTH_SINGLE_AUDIENCE without ENABLE_LOGIN_FLOW) needed unmerged
|
||||
# Nextcloud user_oidc patches and is no longer supported. The
|
||||
# `enable_login_flow` flag is now derived from the resolved mode by
|
||||
# `_sync_derived_flags`, so users only configure the mode — no
|
||||
# separate ENABLE_LOGIN_FLOW env var is needed.
|
||||
|
||||
# If OAuth credentials not provided, DCR must be available
|
||||
# (This is a runtime check, not a config check, so we just warn)
|
||||
|
||||
Reference in New Issue
Block a user