Skip to content

feat(remote): direct SSH targets without a gateway or scheduler - #18

Merged
ligon merged 1 commit into
mainfrom
feat/direct-ssh-target
Sep 12, 2026
Merged

ligon merged 1 commit into
mainfrom
feat/direct-ssh-target

Conversation

@ligon

@ligon ligon commented Sep 12, 2026

Copy link
Copy Markdown
Owner

What

Adds a remote.host target so an ordinary Linux box can be a SuCoder target — no gateway hop, no DTN, no Slurm. Execution, Git transport, tunnels, and attach all ride the configured host or ~/.ssh/config alias, including after a connection expires.

targets:
  workstation:
    host: workstation.example.org  # or an existing ~/.ssh/config alias
    remote_user: ligon
    mirror_root: ~/mirrors

Notable design points

  • Connection identity is resolved, not assumed. ssh -G evaluates the destination before a ControlMaster socket is chosen, so editing an alias or an Include file can't reuse a master still connected to the previous account or host. Resolution failure fails closed rather than falling back to a stale socket, and is deliberately uncached since SSH config can change between commands.
  • remote_user wins over any User option, regardless of capitalization.
  • host is mutually exclusive with gateway, transfer_host, slurm, and the BRC-specific cert_file; validation also rejects empty, whitespace-bearing, and --prefixed values (option injection).
  • --node is refused consistently by collaborate, attach, and tunnel forward. A direct target has one host and no scheduler; _direct_control clears compute_node on connect, so a pin would silently vanish rather than take effect.
  • release remains Slurm-only, and tunnel up warms the single connection without writing cluster aliases to ~/.ssh/config.

Testing

791 tests pass (763 pre-existing + 28 new). New coverage: config validation and mutual exclusion, socket identity separation by user/port/alias-resolution, Git transport option preservation, the full set of tunnel subcommands, and the --node refusal. The --node test is mutation-verified — it fails without the guard.

Reviewer notes — please read

  • detect_changes reports CRITICAL risk: 34 symbols across 8 files, 44 affected execution flows (Collaborate, Attach, Tunnel_down, Push, Agents_clone). This is driven by breadth, not a detected defect — the feature necessarily touches every tunnel entry point. Every direct-target branch is gated on remote.host, which is None for all cluster targets. The one genuinely shared edit is executor.py's if self.control_socket_path or not self.gateway:; not self.gateway is always False for cluster targets because the parser requires a non-empty gateway.
  • Not smoke-tested against a real SSH host. All coverage is mocked. Given the PR fix: harden startup and Slurm timer supervision #13 lesson — "the suite passed while the thing it checked was broken" — a manual sucoder -T <host> collaborate against a real box is worth doing before merge.
  • ssh -G runs once per ssh_control_kwargs() call (local-only, 10s timeout). The fail-closed reasoning justifies it, but it is per-invocation rather than per-session.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AGhbys9tXLm9kDHGhxqLN6

A `remote.host` target connects straight to one Linux box: no gateway
hop, no DTN, no Slurm. Execution, Git transport, tunnels, and attach all
ride the configured host or ~/.ssh/config alias, as does reconnecting
after a connection expires.

Resolve the destination with `ssh -G` before choosing a ControlMaster
socket, so editing an alias or an Include file can never reuse a master
connected to the previous account or host; fail closed when resolution
fails rather than falling back to a stale socket. An explicit
`remote_user` overrides any `User` option regardless of capitalization.

`host` cannot be combined with gateway, transfer_host, slurm, or the
BRC-specific cert_file. `--node` is refused by collaborate, attach, and
tunnel forward alike: a direct target has one host and no scheduler to
request a node from, and `_direct_control` clears `compute_node` on
connect, so a pin would silently vanish rather than take effect.

Tests: 791 pass (27 new covering validation, socket identity, Git
transport, tunnel commands, and the --node refusal).

GitNexus detect-changes reports critical risk, driven by the breadth of
the change (34 symbols, 44 execution flows) rather than a defect: every
direct-target branch is gated on `remote.host`, which is None for all
cluster targets. The one shared edit, executor.py's `or not
self.gateway`, is inert when gateway is non-empty, which the parser
requires for cluster targets.

Not yet smoke-tested against a real SSH host; all coverage is mocked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGhbys9tXLm9kDHGhxqLN6
@ligon
ligon merged commit 0d0b082 into main Sep 12, 2026
4 checks passed
@ligon
ligon deleted the feat/direct-ssh-target branch September 12, 2026 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant