fix(terminal): validate env var types with clear error messages
This commit is contained in:
parent
f524aed23e
commit
4523cc09cf
1 changed files with 24 additions and 7 deletions
|
|
@ -434,6 +434,23 @@ def clear_task_env_overrides(task_id: str):
|
||||||
_task_env_overrides.pop(task_id, None)
|
_task_env_overrides.pop(task_id, None)
|
||||||
|
|
||||||
# Configuration from environment variables
|
# Configuration from environment variables
|
||||||
|
|
||||||
|
def _parse_env_var(name: str, default: str, converter=int, type_label: str = "integer"):
|
||||||
|
"""Parse an environment variable with *converter*, raising a clear error on bad values.
|
||||||
|
|
||||||
|
Without this wrapper, a single malformed env var (e.g. TERMINAL_TIMEOUT=5m)
|
||||||
|
causes an unhandled ValueError that kills every terminal command.
|
||||||
|
"""
|
||||||
|
raw = os.getenv(name, default)
|
||||||
|
try:
|
||||||
|
return converter(raw)
|
||||||
|
except (ValueError, json.JSONDecodeError):
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid value for {name}: {raw!r} (expected {type_label}). "
|
||||||
|
f"Check ~/.hermes/.env or environment variables."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _get_env_config() -> Dict[str, Any]:
|
def _get_env_config() -> Dict[str, Any]:
|
||||||
"""Get terminal environment configuration from environment variables."""
|
"""Get terminal environment configuration from environment variables."""
|
||||||
# Default image with Python and Node.js for maximum compatibility
|
# Default image with Python and Node.js for maximum compatibility
|
||||||
|
|
@ -470,19 +487,19 @@ def _get_env_config() -> Dict[str, Any]:
|
||||||
"modal_image": os.getenv("TERMINAL_MODAL_IMAGE", default_image),
|
"modal_image": os.getenv("TERMINAL_MODAL_IMAGE", default_image),
|
||||||
"daytona_image": os.getenv("TERMINAL_DAYTONA_IMAGE", default_image),
|
"daytona_image": os.getenv("TERMINAL_DAYTONA_IMAGE", default_image),
|
||||||
"cwd": cwd,
|
"cwd": cwd,
|
||||||
"timeout": int(os.getenv("TERMINAL_TIMEOUT", "180")),
|
"timeout": _parse_env_var("TERMINAL_TIMEOUT", "180"),
|
||||||
"lifetime_seconds": int(os.getenv("TERMINAL_LIFETIME_SECONDS", "300")),
|
"lifetime_seconds": _parse_env_var("TERMINAL_LIFETIME_SECONDS", "300"),
|
||||||
# SSH-specific config
|
# SSH-specific config
|
||||||
"ssh_host": os.getenv("TERMINAL_SSH_HOST", ""),
|
"ssh_host": os.getenv("TERMINAL_SSH_HOST", ""),
|
||||||
"ssh_user": os.getenv("TERMINAL_SSH_USER", ""),
|
"ssh_user": os.getenv("TERMINAL_SSH_USER", ""),
|
||||||
"ssh_port": int(os.getenv("TERMINAL_SSH_PORT", "22")),
|
"ssh_port": _parse_env_var("TERMINAL_SSH_PORT", "22"),
|
||||||
"ssh_key": os.getenv("TERMINAL_SSH_KEY", ""),
|
"ssh_key": os.getenv("TERMINAL_SSH_KEY", ""),
|
||||||
# Container resource config (applies to docker, singularity, modal, daytona -- ignored for local/ssh)
|
# Container resource config (applies to docker, singularity, modal, daytona -- ignored for local/ssh)
|
||||||
"container_cpu": float(os.getenv("TERMINAL_CONTAINER_CPU", "1")),
|
"container_cpu": _parse_env_var("TERMINAL_CONTAINER_CPU", "1", float, "number"),
|
||||||
"container_memory": int(os.getenv("TERMINAL_CONTAINER_MEMORY", "5120")), # MB (default 5GB)
|
"container_memory": _parse_env_var("TERMINAL_CONTAINER_MEMORY", "5120"), # MB (default 5GB)
|
||||||
"container_disk": int(os.getenv("TERMINAL_CONTAINER_DISK", "51200")), # MB (default 50GB)
|
"container_disk": _parse_env_var("TERMINAL_CONTAINER_DISK", "51200"), # MB (default 50GB)
|
||||||
"container_persistent": os.getenv("TERMINAL_CONTAINER_PERSISTENT", "true").lower() in ("true", "1", "yes"),
|
"container_persistent": os.getenv("TERMINAL_CONTAINER_PERSISTENT", "true").lower() in ("true", "1", "yes"),
|
||||||
"docker_volumes": json.loads(os.getenv("TERMINAL_DOCKER_VOLUMES", "[]")),
|
"docker_volumes": _parse_env_var("TERMINAL_DOCKER_VOLUMES", "[]", json.loads, "valid JSON"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue