feat: implement dynaconf configuration management (ADR-024 phases 1-3)

Replace ~80 manual os.getenv() calls in config.py with dynaconf-backed
configuration, enabling TOML file-based config alongside existing env
var support. Zero breaking changes — Settings dataclass interface and
all consumers unchanged.

Phase 1: Create settings.toml with all config keys and defaults,
.secrets.toml.example template, update .gitignore, initialize Dynaconf
instance with envvar_prefix=False and environment section switching.

Phase 2: Wire adapter — replace os.getenv() with _dynaconf.get() in
get_settings(), get_document_processor_config(), and deprecation/
dependency resolution helpers. Automatic type coercion eliminates ~30
manual int()/float()/.lower()=="true" patterns.

Phase 3: Add 12 declarative validators for port ranges, positive
integers, enum constraints, and float ranges. Remove redundant negative
overlap check from Settings.__post_init__.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-04-07 09:22:19 +02:00
co-authored by Claude Opus 4.6
parent f34c74afbc
commit c8e4cbe825
9 changed files with 455 additions and 125 deletions
+20 -1
View File
@@ -10,7 +10,7 @@ Tests cover:
import os
from unittest.mock import patch
from nextcloud_mcp_server.config import Settings
from nextcloud_mcp_server.config import Settings, _reload_config
from nextcloud_mcp_server.config_validators import (
AuthMode,
detect_auth_mode,
@@ -274,6 +274,7 @@ class TestMultiUserBasicValidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
mode, errors = validate_configuration(settings)
@@ -372,6 +373,7 @@ class TestOAuthSingleAudienceValidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
mode, errors = validate_configuration(settings)
@@ -459,6 +461,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
assert settings.vector_sync_enabled is True
@@ -474,6 +477,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
assert settings.vector_sync_enabled is True
@@ -490,6 +494,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
assert settings.enable_offline_access is True
@@ -506,6 +511,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
assert settings.enable_offline_access is True
@@ -525,6 +531,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
# Semantic search enabled
@@ -549,6 +556,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
# Semantic search enabled
@@ -572,6 +580,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
# Semantic search NOT enabled
@@ -593,6 +602,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
# Should use new name value (true)
@@ -612,6 +622,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
# Should use new name value (true)
@@ -637,6 +648,7 @@ class TestConfigurationConsolidation:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
mode, errors = validate_configuration(settings)
@@ -671,6 +683,7 @@ class TestExplicitModeSelection:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
mode = detect_auth_mode(settings)
@@ -688,6 +701,7 @@ class TestExplicitModeSelection:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
mode = detect_auth_mode(settings)
@@ -705,6 +719,7 @@ class TestExplicitModeSelection:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
mode = detect_auth_mode(settings)
@@ -722,6 +737,7 @@ class TestExplicitModeSelection:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
# Should raise ValueError with clear message
@@ -747,6 +763,7 @@ class TestExplicitModeSelection:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
mode = detect_auth_mode(settings)
@@ -765,6 +782,7 @@ class TestExplicitModeSelection:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
mode = detect_auth_mode(settings)
@@ -782,6 +800,7 @@ class TestExplicitModeSelection:
):
from nextcloud_mcp_server.config import get_settings
_reload_config()
settings = get_settings()
mode = detect_auth_mode(settings)