mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-23 12:39:24 -07:00
fix(security): path traversal, timing-safe auth, stale credential bindings
Security: - Remove /mnt/ from _ALLOWED_LOG_PREFIXES to prevent Unraid share exposure - Add early .. detection for disk/logs and live/log_tail path validation - Add /boot/ prefix restriction for flash_backup source_path - Use hmac.compare_digest for timing-safe API key verification in server.py - Gate include_traceback on DEBUG log level (no tracebacks in production) Correctness: - Re-raise CredentialsNotConfiguredError in health check instead of swallowing - Fix ups_device query (remove non-existent nominalPower/currentPower fields) Best practices (BP-01, BP-05, BP-06): - Add # noqa: ASYNC109 to timeout params in _handle_live and unraid() - Fix start_array* → start_array in docstring (not in ARRAY_DESTRUCTIVE) - Remove from __future__ import annotations from snapshot.py - Replace import-time UNRAID_API_KEY/URL bindings with _settings.ATTR pattern in manager.py, snapshot.py, utils.py, diagnostics.py — fixes stale binding after apply_runtime_config() post-elicitation (BP-05) CI/CD: - Add .github/workflows/ci.yml (5-job pipeline: lint, typecheck, test, version-sync, audit) - Add fail_under = 80 to [tool.coverage.report] - Add version sync check to scripts/validate-marketplace.sh Documentation: - Sync plugin.json version 1.1.1 → 1.1.2 with pyproject.toml - Update CLAUDE.md: 3 tools, system domain count 18, scripts comment fix - Update README.md: 3 tools, security notes - Update docs/AUTHENTICATION.md: H1 title fix - Add UNRAID_CREDENTIALS_DIR to .env.example Bump: 1.1.1 → 1.1.2 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -8,9 +8,10 @@ from unraid_mcp.server import _build_google_auth
|
||||
|
||||
def test_build_google_auth_returns_none_when_unconfigured(monkeypatch):
|
||||
"""Returns None when Google OAuth env vars are absent."""
|
||||
monkeypatch.delenv("GOOGLE_CLIENT_ID", raising=False)
|
||||
monkeypatch.delenv("GOOGLE_CLIENT_SECRET", raising=False)
|
||||
monkeypatch.delenv("UNRAID_MCP_BASE_URL", raising=False)
|
||||
# Use explicit empty values so dotenv reload cannot re-inject from ~/.unraid-mcp/.env.
|
||||
monkeypatch.setenv("GOOGLE_CLIENT_ID", "")
|
||||
monkeypatch.setenv("GOOGLE_CLIENT_SECRET", "")
|
||||
monkeypatch.setenv("UNRAID_MCP_BASE_URL", "")
|
||||
|
||||
import unraid_mcp.config.settings as s
|
||||
|
||||
@@ -42,6 +43,8 @@ def test_build_google_auth_returns_provider_when_configured(monkeypatch):
|
||||
client_id="test-id.apps.googleusercontent.com",
|
||||
client_secret="GOCSPX-test-secret",
|
||||
base_url="http://10.1.0.2:6970",
|
||||
extra_authorize_params={"access_type": "online", "prompt": "consent"},
|
||||
require_authorization_consent=False,
|
||||
jwt_signing_key="x" * 32,
|
||||
)
|
||||
|
||||
@@ -95,7 +98,7 @@ def test_mcp_instance_has_no_auth_by_default():
|
||||
import os
|
||||
|
||||
for var in ("GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "UNRAID_MCP_BASE_URL"):
|
||||
os.environ.pop(var, None)
|
||||
os.environ[var] = ""
|
||||
|
||||
import importlib
|
||||
|
||||
|
||||
Reference in New Issue
Block a user