From d826fc76d63bb601e61dbfe4d128abbeaf579df4 Mon Sep 17 00:00:00 2001 From: Ousama Ben Younes Date: Thu, 23 Jul 2026 23:10:15 +0000 Subject: [PATCH] fix(cli): clarify Docker socket access errors --- strix/interface/utils.py | 16 ++++++++++- tests/test_docker_connection_message.py | 36 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/test_docker_connection_message.py diff --git a/strix/interface/utils.py b/strix/interface/utils.py index ece8c6af..bb7f3c0d 100644 --- a/strix/interface/utils.py +++ b/strix/interface/utils.py @@ -26,6 +26,13 @@ from strix.utils.api_spec import detect_spec_format logger = logging.getLogger(__name__) +DOCKER_PERMISSION_ERROR_MARKERS = ("permission denied", "operation not permitted") +DOCKER_SOCKET_ACCESS_HINT = ( + "Docker is installed, but Strix cannot access the Docker socket. " + "Run Strix with a user that can access Docker, or add your user to the docker group " + "and restart your shell before trying again.\n" +) + def get_severity_color(severity: str) -> str: severity_colors = { @@ -1577,15 +1584,22 @@ def clone_repository(repo_url: str, run_name: str, dest_name: str | None = None) ) from e +def _is_docker_permission_error(exc: DockerException) -> bool: + message = str(exc).lower() + return any(marker in message for marker in DOCKER_PERMISSION_ERROR_MARKERS) + + def check_docker_connection() -> Any: try: return docker.from_env() - except DockerException: + except DockerException as exc: console = Console() error_text = Text() error_text.append("DOCKER NOT AVAILABLE", style="bold red") error_text.append("\n\n", style="white") error_text.append("Cannot connect to Docker daemon.\n", style="white") + if _is_docker_permission_error(exc): + error_text.append(DOCKER_SOCKET_ACCESS_HINT, style="white") error_text.append( "Please ensure Docker Desktop is installed and running, and try running strix again.\n", style="white", diff --git a/tests/test_docker_connection_message.py b/tests/test_docker_connection_message.py new file mode 100644 index 00000000..1bf8ae52 --- /dev/null +++ b/tests/test_docker_connection_message.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +import io + +import pytest +from docker.errors import DockerException +from rich.console import Console + +from strix.interface import utils + + +DOCKER_PERMISSION_ERROR = "permission denied while trying to connect to the Docker daemon socket" +DOCKER_SOCKET_HINT = "Docker socket" +DOCKER_GROUP_HINT = "docker group" + + +def test_docker_connection_permission_error_mentions_socket_access( + monkeypatch: pytest.MonkeyPatch, +) -> None: + output = io.StringIO() + + def fake_console() -> Console: + return Console(file=output, color_system=None, force_terminal=False) + + def fail_from_env() -> None: + raise DockerException(DOCKER_PERMISSION_ERROR) + + monkeypatch.setattr(utils, "Console", fake_console) + monkeypatch.setattr(utils.docker, "from_env", fail_from_env) + + with pytest.raises(RuntimeError, match="Docker not available"): + utils.check_docker_connection() + + rendered = output.getvalue() + assert DOCKER_SOCKET_HINT in rendered + assert DOCKER_GROUP_HINT in rendered