From 44df52005a1b59ae2c8439c4e68e7696851b7035 Mon Sep 17 00:00:00 2001 From: liuhao1024 Date: Fri, 29 May 2026 11:35:39 +0800 Subject: [PATCH] fix(tools): guard Path.home() against PermissionError in has_direct_modal_credentials (#33528) When HOME=/root (Docker containers) and the process runs as unprivileged user (hermes, uid 10000), Path.home() / '.modal.toml' raises PermissionError because /root/ is inaccessible. This crashes the dashboard /api/skills endpoint. Catch PermissionError/OSError and treat as 'no config file'. Env vars still take priority (tested). Fixes #33525 --- tests/tools/test_tool_backend_helpers.py | 14 ++++++++++++++ tools/tool_backend_helpers.py | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/tools/test_tool_backend_helpers.py b/tests/tools/test_tool_backend_helpers.py index e3d6cf0711c..03bb7f20d7a 100644 --- a/tests/tools/test_tool_backend_helpers.py +++ b/tests/tools/test_tool_backend_helpers.py @@ -242,6 +242,20 @@ class TestHasDirectModalCredentials: with patch.object(Path, "home", return_value=tmp_path): assert has_direct_modal_credentials() is True + def test_home_dir_permission_denied(self, monkeypatch): + """PermissionError on Path.home() should not crash (issue #33525).""" + monkeypatch.delenv("MODAL_TOKEN_ID", raising=False) + monkeypatch.delenv("MODAL_TOKEN_SECRET", raising=False) + with patch.object(Path, "home", side_effect=PermissionError("denied")): + assert has_direct_modal_credentials() is False + + def test_home_dir_permission_denied_with_env_vars(self, monkeypatch): + """PermissionError on Path.home() should not prevent env var detection.""" + monkeypatch.setenv("MODAL_TOKEN_ID", "id-123") + monkeypatch.setenv("MODAL_TOKEN_SECRET", "sec-456") + with patch.object(Path, "home", side_effect=PermissionError("denied")): + assert has_direct_modal_credentials() is True + # --------------------------------------------------------------------------- # prefers_gateway diff --git a/tools/tool_backend_helpers.py b/tools/tool_backend_helpers.py index c4320c68432..b1e0f834c7e 100644 --- a/tools/tool_backend_helpers.py +++ b/tools/tool_backend_helpers.py @@ -84,9 +84,13 @@ def normalize_modal_mode(value: object | None) -> str: def has_direct_modal_credentials() -> bool: """Return True when direct Modal credentials/config are available.""" + try: + modal_file_exists = (Path.home() / ".modal.toml").exists() + except (PermissionError, OSError): + modal_file_exists = False return bool( (os.getenv("MODAL_TOKEN_ID") and os.getenv("MODAL_TOKEN_SECRET")) - or (Path.home() / ".modal.toml").exists() + or modal_file_exists )