diff --git a/tests/tools/test_parse_env_var.py b/tests/tools/test_parse_env_var.py index cffee7c9af..8cbbce6985 100644 --- a/tests/tools/test_parse_env_var.py +++ b/tests/tools/test_parse_env_var.py @@ -1,5 +1,6 @@ """Tests for _parse_env_var and _get_env_config env-var validation.""" +import importlib import json from unittest.mock import patch @@ -84,3 +85,23 @@ class TestParseEnvVar: with patch.dict("os.environ", {"TERMINAL_DOCKER_VOLUMES": "not json"}): with pytest.raises(ValueError, match="valid JSON"): _parse_env_var("TERMINAL_DOCKER_VOLUMES", "[]", json.loads, "valid JSON") + + +class TestImportTimeEnvParsing: + """Module-level env parsing should never make terminal_tool unimportable.""" + + def test_invalid_foreground_timeout_falls_back_to_default(self): + try: + with patch.dict("os.environ", {"TERMINAL_MAX_FOREGROUND_TIMEOUT": "5m"}, clear=False): + mod = importlib.reload(_tt_mod) + assert mod.FOREGROUND_MAX_TIMEOUT == 600 + finally: + importlib.reload(_tt_mod) + + def test_invalid_disk_warning_threshold_falls_back_to_default(self): + try: + with patch.dict("os.environ", {"TERMINAL_DISK_WARNING_GB": "huge"}, clear=False): + mod = importlib.reload(_tt_mod) + assert mod.DISK_USAGE_WARNING_THRESHOLD_GB == 500.0 + finally: + importlib.reload(_tt_mod) diff --git a/tools/terminal_tool.py b/tools/terminal_tool.py index 4a2a5fc0be..8fbffadc94 100644 --- a/tools/terminal_tool.py +++ b/tools/terminal_tool.py @@ -72,11 +72,48 @@ from tools.tool_backend_helpers import ( ) +def _safe_parse_import_env( + name: str, + default: Any, + converter, + type_label: str, +): + """Parse module-level numeric env vars without breaking import. + + Terminal tool is imported by CLI, ACP, tests, and tool discovery. A single + malformed env var must not make the whole module unloadable at import time. + """ + raw = os.getenv(name) + if raw is None or raw == "": + return default + try: + return converter(raw) + except (TypeError, ValueError): + logger.warning( + "Invalid value for %s: %r (expected %s). Falling back to %r.", + name, + raw, + type_label, + default, + ) + return default + + # Hard cap on foreground timeout; override via TERMINAL_MAX_FOREGROUND_TIMEOUT env var. -FOREGROUND_MAX_TIMEOUT = int(os.getenv("TERMINAL_MAX_FOREGROUND_TIMEOUT", "600")) +FOREGROUND_MAX_TIMEOUT = _safe_parse_import_env( + "TERMINAL_MAX_FOREGROUND_TIMEOUT", + 600, + int, + "integer", +) # Disk usage warning threshold (in GB) -DISK_USAGE_WARNING_THRESHOLD_GB = float(os.getenv("TERMINAL_DISK_WARNING_GB", "500")) +DISK_USAGE_WARNING_THRESHOLD_GB = _safe_parse_import_env( + "TERMINAL_DISK_WARNING_GB", + 500.0, + float, + "number", +) def _check_disk_usage_warning():