fix: address PR #589 review feedback (round 2)

Consolidate three independent RefreshTokenStorage lazy singletons into a
single lock-protected get_shared_storage() function, eliminating race
conditions on concurrent first-access. Remove blanket try/except in
_get_stored_scopes so storage errors propagate as proper MCP errors
instead of silently triggering "please provision" messages. Handle
declined/cancelled elicitation results in Login Flow tools by cleaning up
sessions and returning clear status. Add update_app_password_scopes() to
avoid unnecessary decrypt/re-encrypt when only scopes change. Add
unprovisioned-user early exit and no-op detection to nc_auth_update_scopes.
Remove four dead config fields and misleading NEXTCLOUD_PASSWORD deprecation
warning. Add periodic login flow session cleanup task. Generate separate
Fernet keys per service. Add board cleanup in deck integration test. Gate
CI unit tests on linting and skip Astrolabe build for single-user profile.
Fix test markers from oauth to multi_user_basic for astrolabe integration
tests. Update login_flow.py docstrings to document outbound HTTP calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-03-01 16:35:31 +01:00
co-authored by Claude Opus 4.6
parent 33cf0fee9b
commit db1e0606ad
15 changed files with 248 additions and 131 deletions
-18
View File
@@ -207,10 +207,6 @@ class Settings:
# Login Flow v2 settings (ADR-022)
enable_login_flow: bool = False
login_flow_poll_interval: int = 2 # seconds between polls
login_flow_poll_timeout: int = 300 # max seconds to wait for completion
login_flow_cleanup_interval: int = 3600 # seconds between expired session cleanup
app_password_max_age_days: int = 0 # 0 = no expiration
# Token exchange cache settings
token_exchange_cache_ttl: int = 300 # seconds (5 minutes default)
@@ -268,14 +264,6 @@ class Settings:
"""Validate configuration and set defaults."""
logger = logging.getLogger(__name__)
# Deprecation warning: NEXTCLOUD_PASSWORD without NEXTCLOUD_APP_PASSWORD
if self.nextcloud_password and not self.nextcloud_app_password:
logger.warning(
"NEXTCLOUD_PASSWORD is deprecated for app password usage. "
"Please use NEXTCLOUD_APP_PASSWORD instead. "
"Support for NEXTCLOUD_PASSWORD as app password will be removed in v1.0.0."
)
# Validate SSL/TLS configuration
if not self.nextcloud_verify_ssl:
logger.warning(
@@ -563,12 +551,6 @@ def get_settings() -> Settings:
),
# Login Flow v2 settings (ADR-022)
enable_login_flow=(os.getenv("ENABLE_LOGIN_FLOW", "false").lower() == "true"),
login_flow_poll_interval=int(os.getenv("LOGIN_FLOW_POLL_INTERVAL", "2")),
login_flow_poll_timeout=int(os.getenv("LOGIN_FLOW_POLL_TIMEOUT", "300")),
login_flow_cleanup_interval=int(
os.getenv("LOGIN_FLOW_CLEANUP_INTERVAL", "3600")
),
app_password_max_age_days=int(os.getenv("APP_PASSWORD_MAX_AGE_DAYS", "0")),
# Token exchange cache settings
token_exchange_cache_ttl=int(os.getenv("TOKEN_EXCHANGE_CACHE_TTL", "300")),
# Token and webhook storage settings (encryption key optional for webhook-only usage)