Skip to content

fix(ssh,docker): make the SSH and Docker backends build on Windows - #182

Merged
zoza1982 merged 3 commits into
mainfrom
fix/windows-portability-ssh-docker
Jul 15, 2026
Merged

fix(ssh,docker): make the SSH and Docker backends build on Windows#182
zoza1982 merged 3 commits into
mainfrom
fix/windows-portability-ssh-docker

Conversation

@zoza1982

Copy link
Copy Markdown
Owner

What

Cairn did not compile on Windows with the full backend stack (--features all-backends): the SSH
and 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 E0599 compile errors on x86_64-pc-windows-msvc (surfaced when building a Windows test
binary; CI never caught them — see below):

  1. SSHrussh::keys::agent::client::AgentClient::connect_env() (reads $SSH_AUTH_SOCK) is
    #[cfg(unix)] in russh. Used for public-key agent auth.
  2. Dockerbollard::Docker::connect_with_unix() is #[cfg(unix)] in bollard. Used for an
    explicit socket path (rootless Docker / Podman).

Fix

  • SSH (crates/cairn-backend-ssh/src/connect.rs): split the agent pubkey-auth loop into a
    generic helper `agent_publickey_auth(…, AgentClient) where S: AsyncRead + AsyncWrite + Unpin
    • Send(the bound mirrors russh'sSigner for AgentClient`), then connect per platform:
    • Unix: connect_env()unchanged behavior.
    • Windows: the OpenSSH named-pipe agent (\\.\pipe\openssh-ssh-agent), falling back to Pageant.
  • Docker (crates/cairn-backend-docker/src/real.rs): use bollard's cross-platform
    connect_with_socket() (Unix socket on Unix, named pipe on Windows; bollard's pipe feature is
    on 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.yml deliberately built only the lean default feature set on Windows/macOS (heavy backends
Linux-only for fast PR feedback), so the transport backends were never compiled on Windows. Added a
windows-portability job: cargo check -p cairn --features ssh,containers on windows-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 was
rewritten 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)

  • On Windows the Docker named-pipe arm now compiles but is not yet reachable through Cairn's own
    discovery (which only probes $XDG_RUNTIME_DIR, unset on Windows); Docker Desktop's default pipe
    is handled by connect_with_local_defaults. Wiring genuine Windows named-pipe/rootless discovery
    is a separate feature.
  • The full all-backends Windows release build (aws-lc/cloud + k8s codegen) is still exercised
    only 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-review gates run on the diff.

🤖 Generated with Claude Code

zoza1982 and others added 3 commits July 14, 2026 20:07
…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
zoza1982 force-pushed the fix/windows-portability-ssh-docker branch from 6d63aa3 to 8f67b2e Compare July 15, 2026 01:07
@zoza1982
zoza1982 merged commit 161b0fe into main Jul 15, 2026
14 checks passed
@zoza1982
zoza1982 deleted the fix/windows-portability-ssh-docker branch July 15, 2026 01:13
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