This commit is contained in:
Ben Younes 2026-11-05 17:01:23 -03:00 • committed by GitHub
commit 46b993d16f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 90 additions and 0 deletions

View file

@ -25,6 +25,14 @@ from strix.utils.api_spec import detect_spec_format
logger = logging.getLogger(__name__)
DOCKER_PERMISSION_ERROR_MARKERS = ("permission denied", "operation not permitted")
DOCKER_LOCAL_SOCKET_SCHEME = "unix://"
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 = {
@ -1598,6 +1606,24 @@ def clone_repository(repo_url: str, run_name: str, dest_name: str | None = None)
) from e
def _is_docker_permission_error(exc: BaseException) -> bool:
message = str(exc).lower()
return any(marker in message for marker in DOCKER_PERMISSION_ERROR_MARKERS)
def _is_docker_socket_permission_error(exc: Any) -> bool:
"""A permission error against the *local* Docker socket.
The docker-group remedy only applies to a Unix-socket daemon. A permission
failure against a remote DOCKER_HOST (TCP/SSH) endpoint is not fixed by
group membership, so the socket hint must not be shown for it.
"""
if not _is_docker_permission_error(exc):
return False
host = exc.endpoint.host
return host is None or host.startswith(DOCKER_LOCAL_SOCKET_SCHEME)
def check_docker_connection() -> Any:
from strix.runtime.docker_connection import DockerConnectionError, connect_docker
@ -1611,6 +1637,8 @@ def check_docker_connection() -> Any:
error_text.append("\n\n", style="white")
error_text.append(f"Cannot connect to Docker at {exc.endpoint.label}.\n", style="white")
error_text.append(f"{exc.detail}\n\n", style="dim red")
if _is_docker_socket_permission_error(exc):
error_text.append(DOCKER_SOCKET_ACCESS_HINT, style="white")
error_text.append(
"Make sure Docker is running. If `docker info` works in this shell, strix uses "
"the same daemon. Otherwise set DOCKER_HOST.\n",

View file

@ -0,0 +1,62 @@
from __future__ import annotations
import io
import pytest
from docker.errors import DockerException
from rich.console import Console
from strix.interface import utils
from strix.runtime import docker_connection
from strix.runtime.docker_connection import DockerConnectionError, DockerEndpoint
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_connect() -> None:
endpoint = DockerEndpoint(None, "default socket")
raise DockerConnectionError(endpoint, DockerException(DOCKER_PERMISSION_ERROR))
monkeypatch.setattr(utils, "Console", fake_console)
monkeypatch.setattr(docker_connection, "connect_docker", fail_connect)
with pytest.raises(SystemExit):
utils.check_docker_connection()
rendered = output.getvalue()
assert DOCKER_SOCKET_HINT in rendered
assert DOCKER_GROUP_HINT in rendered
def test_docker_connection_permission_error_on_remote_host_skips_socket_hint(
monkeypatch: pytest.MonkeyPatch,
) -> None:
output = io.StringIO()
def fake_console() -> Console:
return Console(file=output, color_system=None, force_terminal=False)
def fail_connect() -> None:
endpoint = DockerEndpoint("tcp://10.0.0.5:2376", "DOCKER_HOST")
raise DockerConnectionError(endpoint, DockerException(DOCKER_PERMISSION_ERROR))
monkeypatch.setattr(utils, "Console", fake_console)
monkeypatch.setattr(docker_connection, "connect_docker", fail_connect)
with pytest.raises(SystemExit):
utils.check_docker_connection()
rendered = output.getvalue()
assert DOCKER_SOCKET_HINT not in rendered
assert DOCKER_GROUP_HINT not in rendered