Skip to content

bug(slm): ssh key checks crash with PermissionError when key dir unreadable — Path(SSH_KEY_PATH).exists() at 7 sites #11793

Closed

Description

@mrveiss

Observed gap

The SLM ssh helpers gate the optional -i <key> flag on Path(SSH_KEY_PATH).exists(). pathlib.Path.exists() only swallows ENOENT/ENOTDIR-class errnos — EACCES propagates, so when the key's parent directory is unreadable by the SLM process the whole call chain crashes with an unhandled PermissionError instead of degrading to the default ssh identity.

Baseline evidence (surfaced while repairing #11737 — real SyncOrchestrator under test on a box where /home/autobot/.ssh is another user's dir):

tests/services/test_sync_orchestrator_ssh.py:63: in test_build_ssh_command_port_and_target
    cmd = _orchestrator()._build_ssh_command(2222, "u", "h")
services/sync_orchestrator.py:122: in _build_ssh_command
    if Path(SSH_KEY_PATH).exists():
/usr/lib/python3.10/pathlib.py:1097: in stat
    return self._accessor.stat(self, follow_symlinks=follow_symlinks)
E   PermissionError: [Errno 13] Permission denied: '/home/autobot/.ssh/autobot_key'

Affected sites (7)

  • autobot-slm-backend/services/sync_orchestrator.py:105, :122, :296, :342
  • autobot-slm-backend/services/code_distributor.py:150, :391
  • autobot-slm-backend/api/nodes_execution.py:588

In production this means a permissions misconfiguration on /home/autobot/.ssh turns every role-sync / code-distribution / node-exec ssh build into a hard 500 instead of an actionable "key not usable" degradation.

Proposed fix

Replace Path(KEY).exists() with os.access(KEY, os.R_OK) at all 7 sites: returns False for both missing AND unreadable keys (an unreadable key cannot be used by ssh anyway), never raises. os is already imported in all three modules.

This is a deliberate behavior change in security-relevant ssh plumbing, so it was NOT bundled into the #11737 test-repair PR — filing for an owner-approved fast-follow instead. The #11737 tests pin SSH_KEY_PATH to a guaranteed-absent path so they stay deterministic either way.

Related: #11737, #10277.

Activity

  1. mrveiss commented on Jul 16, 2026

    @mrveiss
    OwnerAuthor

    Owner decision (2026-07-16): one safe helper, degrade + warn — canonical _ssh_key_usable() in a shared module catching PermissionError/OSError, logging a WARNING once, returning False → fall back to default ssh identity; all 7 sites migrate to it. Implementing now.

  2. mrveiss commented on Jul 16, 2026

    @mrveiss
    OwnerAuthor

    Closed — merged to Dev_new_gui. Commit: 6c51fa8 (PR #11804). Owner decision implemented: canonical services/ssh_utils.py::_ssh_key_usable — missing key quiet-False (old behavior), unreadable/OSError → False + one actionable WARNING per path → default ssh identity; 9 sites migrated (7 filed + api/nodes.py:2740 + api/code_sync.py:2550). Adjacent bug fixed: stray duplicate -o token in code_distributor ssh argv (#10277 class), regression-guarded. Evidence: tests/services 321/1/0 (8 new helper tests incl. the exact filed traceback site degrading cleanly); nodes_execution 149 passed; independent re-run identical; conftest real-loads the new module so stubs can't silently re-add -i.

  3. github-actions commented on Jul 16, 2026

    @github-actions
    Contributor

    PR #11804 (merged to Dev_new_gui) references this issue with a close keyword.

    fix(slm): _ssh_key_usable helper — degrade to default identity on unreadable key, warn once (#11793)

    If this issue is fully resolved, close it manually. If work remains, no action is needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions