fix(ssh,docker): make the SSH and Docker backends build on Windows - #182
Merged
Conversation
…s builds Two backends called Unix-only APIs unconditionally, so an all-backends build did not compile on Windows (E0599) — there was no full-feature Windows binary. - ssh: `AgentClient::connect_env` (SSH_AUTH_SOCK) is cfg(unix)-only in russh. Split the pubkey-agent auth loop into a generic helper over the agent stream (`AsyncRead + AsyncWrite + Unpin + Send`, matching russh's `Signer for AgentClient<S>`), and connect per-platform: Unix keeps `connect_env`; Windows tries the OpenSSH named-pipe agent (`\\.\pipe\openssh-ssh-agent`) then Pageant. - docker: `Docker::connect_with_unix` is cfg(unix)-only in bollard. Use bollard's cross-platform `connect_with_socket`, which picks the Unix socket or the Windows named pipe internally (bollard's `pipe` feature, on by default). Behavior on Unix is unchanged except it now errors early if the socket path doesn't exist. CHANGELOG updated. CI Windows all-backends gate added in a follow-up commit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… notes Add a `windows-portability` job to ci.yml: `cargo check -p cairn --features ssh,containers` on windows-latest (NASM installed for russh's aws-lc-rs). This is the compile-only gate that would have caught the russh/bollard Unix-only calls — the lean Windows `test` job never compiled the transport backends. Cloud SDKs (s3/gcs/azure) are excluded: they're cross-platform and already built on Windows by release.yml. Rewrote the ci.yml policy comment to sanction this one exception. Also correct a stale note in both files: aws-lc-rs is pulled by the SSH backend (russh's default crypto) too, not only the S3 backend. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…but keyless Review fix (network-engineer, bug-bot): the Windows fallback returned as soon as the OpenSSH named-pipe agent *connected*, even on Ok(false) — so if that agent is running but empty (common; other tools auto-start it) and the user's key lives in Pageant, Pageant was never tried and auth failed. Now only a real success (Ok(true)) short-circuits; a reachable-but-keyless pipe (or a mid-auth error) falls through to Pageant. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
zoza1982
force-pushed
the
fix/windows-portability-ssh-docker
branch
from
July 15, 2026 01:07
6d63aa3 to
8f67b2e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Cairn did not compile on Windows with the full backend stack (
--features all-backends): the SSHand Docker backends each called a Unix-only API unconditionally, so there was no complete
Windows binary. This fixes both and adds a CI gate so it can't regress.
Root cause
Two
E0599compile errors onx86_64-pc-windows-msvc(surfaced when building a Windows testbinary; CI never caught them — see below):
russh::keys::agent::client::AgentClient::connect_env()(reads$SSH_AUTH_SOCK) is#[cfg(unix)]in russh. Used for public-key agent auth.bollard::Docker::connect_with_unix()is#[cfg(unix)]in bollard. Used for anexplicit socket path (rootless Docker / Podman).
Fix
crates/cairn-backend-ssh/src/connect.rs): split the agent pubkey-auth loop into ageneric helper `agent_publickey_auth
(…, AgentClient) where S: AsyncRead + AsyncWrite + Unpin- Send
- Unix:
- Windows: the OpenSSH named-pipe agent (
(the bound mirrors russh'sSigner for AgentClient`), then connect per platform:connect_env()— unchanged behavior.\\.\pipe\openssh-ssh-agent), falling back to Pageant.crates/cairn-backend-docker/src/real.rs): use bollard's cross-platformconnect_with_socket()(Unix socket on Unix, named pipe on Windows; bollard'spipefeature ison by default). Unix behavior is unchanged — bollard's old and new paths both do the same
eager socket-exists check.
CI: why this was never caught, and the gate added
ci.ymldeliberately built only the lean default feature set on Windows/macOS (heavy backendsLinux-only for fast PR feedback), so the transport backends were never compiled on Windows. Added a
windows-portabilityjob:cargo check -p cairn --features ssh,containersonwindows-latest(compile-only; NASM installed because russh's default crypto is aws-lc-rs). It transitively checks
the SSH, Docker, and K8s backends on Windows. The cloud SDKs (s3/gcs/azure) are excluded — they are
cross-platform and already built on Windows by
release.yml. The lean-Windows policy comment wasrewritten to sanction this single exception, and a stale note (aws-lc-rs is pulled by russh too, not
only S3) was corrected in both workflow files.
Scope / follow-ups (noted, not in this PR)
discovery (which only probes
$XDG_RUNTIME_DIR, unset on Windows); Docker Desktop's default pipeis handled by
connect_with_local_defaults. Wiring genuine Windows named-pipe/rootless discoveryis a separate feature.
all-backendsWindows release build (aws-lc/cloud + k8s codegen) is still exercisedonly in
release.yml; the PR gate is compile-only and transport-only by design.Review
Consulted
network-engineer(SSH agent fallback),container-backend-engineer(Docker connect),and
devops-engineer(CI strategy).bug-bot+code-reviewgates run on the diff.🤖 Generated with Claude Code