diff --git a/tests/test_setup.py b/tests/test_setup.py index 07e19b0..9adbf7c 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -1,3 +1,4 @@ +from pathlib import Path from unittest.mock import patch import pytest @@ -213,3 +214,45 @@ async def test_auto_elicitation_triggered_on_credentials_not_configured(): mock_elicit.assert_called_once_with(mock_ctx) assert result is not None + + +import os # noqa: E402 — needed for reload-based tests below + + +def test_credentials_dir_defaults_to_home_unraid_mcp(): + """CREDENTIALS_DIR defaults to ~/.unraid-mcp when env var is not set.""" + import importlib + + import unraid_mcp.config.settings as s + + os.environ.pop("UNRAID_CREDENTIALS_DIR", None) + try: + with patch.dict(os.environ, {}, clear=False): + os.environ.pop("UNRAID_CREDENTIALS_DIR", None) + importlib.reload(s) + assert Path.home() / ".unraid-mcp" == s.CREDENTIALS_DIR + finally: + importlib.reload(s) # Restore module state + + +def test_credentials_dir_env_var_override(): + """UNRAID_CREDENTIALS_DIR env var overrides the default.""" + import importlib + + import unraid_mcp.config.settings as s + + custom = "/tmp/custom-creds" + try: + with patch.dict(os.environ, {"UNRAID_CREDENTIALS_DIR": custom}): + importlib.reload(s) + assert Path(custom) == s.CREDENTIALS_DIR + finally: + # Reload without the custom env var to restore original state + os.environ.pop("UNRAID_CREDENTIALS_DIR", None) + importlib.reload(s) + + +def test_credentials_env_path_is_dot_env_inside_credentials_dir(): + import unraid_mcp.config.settings as s + + assert s.CREDENTIALS_ENV_PATH == s.CREDENTIALS_DIR / ".env" diff --git a/unraid_mcp/config/settings.py b/unraid_mcp/config/settings.py index 19a8acf..9075ec9 100644 --- a/unraid_mcp/config/settings.py +++ b/unraid_mcp/config/settings.py @@ -18,13 +18,20 @@ SCRIPT_DIR = Path(__file__).parent # /home/user/code/unraid-mcp/unraid_mcp/conf UNRAID_MCP_DIR = SCRIPT_DIR.parent # /home/user/code/unraid-mcp/unraid_mcp/ PROJECT_ROOT = UNRAID_MCP_DIR.parent # /home/user/code/unraid-mcp/ +# Canonical credentials directory — version-agnostic, survives plugin version bumps. +# Override with UNRAID_CREDENTIALS_DIR env var (useful for containers). +CREDENTIALS_DIR = Path(os.getenv("UNRAID_CREDENTIALS_DIR", str(Path.home() / ".unraid-mcp"))) +CREDENTIALS_ENV_PATH = CREDENTIALS_DIR / ".env" + # Load environment variables from .env file -# In container: First try /app/.env.local (mounted), then project root .env +# Priority: canonical ~/.unraid-mcp/.env first, then dev/container fallbacks. dotenv_paths = [ - Path("/app/.env.local"), # Container mount point - PROJECT_ROOT / ".env.local", # Project root .env.local - PROJECT_ROOT / ".env", # Project root .env - UNRAID_MCP_DIR / ".env", # Local .env in unraid_mcp/ + CREDENTIALS_ENV_PATH, # primary — ~/.unraid-mcp/.env (all runtimes) + CREDENTIALS_DIR / ".env.local", # only used if ~/.unraid-mcp/.env absent + Path("/app/.env.local"), # Docker compat mount + PROJECT_ROOT / ".env.local", # dev overrides + PROJECT_ROOT / ".env", # dev fallback + UNRAID_MCP_DIR / ".env", # last resort ] for dotenv_path in dotenv_paths: