ADR-0004: SSH host key verification is always enforced¶
Status: accepted Date: 2026-09-11
Context¶
Cloning over SSH means verifying the remote host is who it claims to
be, the same real risk any SSH client faces — a compromised or
spoofed git host is exactly the kind of failure host key checking
exists to catch, and it's tempting (and common, in throwaway
automation) to disable it entirely (StrictHostKeyChecking=no) to
avoid dealing with known_hosts management in a backend service with
no human ever available to answer an interactive host-key prompt.
Decision¶
Host key verification (StrictHostKeyChecking=yes) is always on
for every SSH clone this service performs — there is no configuration
path, request field, or CLI flag that disables it. What's configurable
is only how known_hosts gets populated, via the deployment-wide
SSH_HOST_KEY_POLICY (withSshKeyEnv in build.ts):
tofu(trust-on-first-use, the default) — a realssh-keyscanat clone time, trusting whatever key the host presents right now. Real protection against a wholesale host substitution; no protection against a key that changes between one clone and the next.pinned— the operator supplies the exact expected host key (pinnedHostKey) per credential entry, with no scan at all. A request whose resolved credential has no pin under this policy fails closed immediately (BuildRequestError, before any network call) — never silently falls back to TOFU.
BatchMode=yes is set unconditionally alongside this, so a host key
that genuinely fails verification under either policy produces a real,
fast SSH failure rather than an invisible hang on an interactive prompt
(no TTY is ever attached). See
Credential handling
for the full mechanics.
Consequences¶
- Easier:
tofuneeds zero operator setup to get real (if weaker) host verification working immediately against any new SSH host. - Easier:
pinnedgives a real, auditable guarantee — the exact key an operator expects, checked every time, with a loud failure the moment it's missing rather than a silent downgrade. - Harder:
tofuhas a real, accepted gap — a host key that changes between two clones of the same host (a real key rotation, or a real MITM) is trusted on the second clone exactly as readily as the first, since nothing persists a previously-scanned key across requests. Operators who need real protection against that specific gap needpinned, nottofu. - A real, accepted constraint: there is deliberately no "insecure"
escape hatch (no
StrictHostKeyChecking=noequivalent reachable from any request field or config source) — a caller/operator who wants to skip host verification entirely has no way to do so through this service.