Renames the written-usage rule into practice across the contract surface: docs/ (architecture, research, plans, sdd), tasks/ (all 43 task files, taskgraph validate passes), AGENTS.md, README.md, CHANGELOG.md, and the .opencode/agents/ prompts. Every replacement is a sense-preserving rewrite (colons, semicolons, commas, parentheses, sentence splits, varied), never a mechanical swap; no spaced hyphens were substituted. Enum fields, frontmatter, tables, wire data, and cited identifiers survive verbatim; en dashes inside numeric ranges keep their meaning. Verification: taskgraph validate (43 tasks), repo grep clean (single exempt hit: the verification command's own search pattern in AGENTS.md), cargo test, clippy --all-targets -D warnings, fmt --check, doc all green.
6.2 KiB
status, last_updated
| status | last_updated |
|---|---|
| reviewed | 2026-10-28 |
ADR-002: The russh pin (0.65.0, aws-lc-rs, no compression, ed25519-only)
Status
Accepted (2026-10-26). A one-way door in practice (SSH negotiation
behavior crosses crate boundaries; bumps are deliberate, tested, and
recorded per the repo's wire-stability convention). Amended same day
after review: the earlier enabling of the rsa feature is reverted
(rsa off). Amended 2026-10-27 (review pass): the key-algorithm
position is ed25519-only; the family's posture is the binding
constraint, not fleet compatibility (decision 4).
Context
russh.md documents the crate inventory and the pin questions; the
2026-10-26 re-verification section carries the current facts. The POCs
validated against 0.64.1 (then-newest) with the ring backend; since
then 0.65.0 has been published (2026-10-25) with six security
fixes, three of them in classes an internet-facing SSH door cares
about (client EXT_INFO unbounded allocation, peer zero-max-packet-size
channel stall, pre-auth nested-certificate stack exhaustion), and two
breaking changes confined to handler-signature shapes
(PublicKeyOffer / VerifiedPublicKey; async-trait feature
removed).
The family's crypto-posture context: alktls, alkhttp, and
alknet all standardize on rustls with the aws_lc_rs feature;
no family crate links ring. The provider choice matters only as
binary-composition hygiene (when alkforge's binary links alkssh
and the family's rustls stack, the goal is one shared primitive
library) and has nothing to do with TLS on the SSH wire.
Decision
- Pin
russh = "0.65"(caret-compatible within 0.65.x, matching the family's"0.10"-style convention; russh minors have broken API before, so the caret stops at the minor). 0.65.0 over 0.64.1: current published + the three security fixes above; the breaking changes land inside the handler surface alkssh implements anyway. POC evidence transfers (wire behavior unchanged); the implementation phase re-verifies the POC-1 decline matrix against 0.65 as contract tests. - Crypto backend:
aws-lc-rs. Family-confirmed (alktls/alkhttp/alknetallrustls(aws_lc_rs); nothing in-family linksring) and it is russh's own default. Verified in-scratch: builds clean in ~50 s with no external provisioning (prebuilt bindings), treeaws-lc-rs 1.18.2/aws-lc-sys 0.46.0. The POCs'ringbuild is recorded as the fallback if a target platform ever fails to provision aws-lc, a deliberate, recorded deviation, never drift. - No compression (
flate2off). The POCs already ran compression-free and vanilla OpenSSH was untroubled; SSH compression is largely pointless at modern link layers and is the CRIME-adjacent attack surface OpenSSH itself defaults off. Bounded-resources and surface-reduction posture agree. - ed25519-only (
rsaoff, and no other scheme is supported). Amended 2026-10-27 from the earlier "ed25519-first" wording after review: the position is ed25519-only. One key algorithm carries the family's identity: the same ed25519 keys serve alktls's self-signed TLS certificates and iroh, and the downstream alknet rewrite rides ssh + ed25519, tcp + tls, quic + tls, and iroh, the same ed25519 identity. The legacy/alternative SSH key schemes (rsa, dsa; ecdsa variants and hardware-token sk variants share the defect) are issued, stored, or derived nowhere in the family, so supporting them here would be a wart backed by nothing else. Enablingrsawould additionally have pulled two RC-pinned deps and made alkssh the family's only RSA-holding crate. Concretely: the tree dropsrsa =0.10.0-rc.18andpkcs1 =0.8.0-rc.4entirely (verified: the["aws-lc-rs"]-only build is clean and RC-free exceptssh-key =0.7.0-rc.11, which russh exact-pins on therussh::keyspath). Wire behavior is honest and fail-closed: a client presenting a non-ed25519 key gets a cleanUSERAUTH_FAILURE, never a half-open session. Operational shape: alkssh implements no other scheme; an assembly registers ed25519 fingerprints only; andauth_publickeydeclines non-ed25519 keys explicitly (ADR-004's explicit-over-inherited pattern applied to the algorithm position, so the posture survives a pin bump that might otherwise accept more schemes). If a scheme ever matters, the amendment is one feature flag plus this ADR. des/dsanever. russh's own "Danger: insecure" features, which no alkssh configuration may enable.- Manifest lands with the dependency:
rust-version = "1.89"(russh's MSRV; supersedes the current 1.88) and, with it, the edition-2024 bump the POCs compiled under.
Consequences
- Positive: the pin is current, carries the security fixes, and
matches the family crypto posture; the tree is fully inventoried,
and with
rsaoff it is RC-free exceptssh-key =0.7.0-rc.11(unavoidable: russh exact-pins it on therussh::keyspath); MSRV/licensing are explicit. - Negative: clients presenting non-ed25519 keys (RSA among them)
decline outright (clean
USERAUTH_FAILURE), recorded as intentional;ssh-key's RC pin rides the russh keys path until russh moves off it; aws-lc-rs is the heavier build (proven acceptable here, withringas the recorded fallback). - Neutral: at 0.65.0 the key arrives as
VerifiedPublicKey.public_keywith the client's signature.algorithmexposed; the ed25519-only posture (decision 4) acts on the key-algorithm fact atauth_publickey, and the.algorithmfield remains available for further hardening if ever wanted. ADR-004 carries the matching amendment note; its other dispositions are unchanged.
References
docs/research/russh.md(inventory + the 2026-10-26 re-verification section with the scratch-build record)docs/research/poc-1-auth-bridge.md(the 0.64.1 wire evidence; backend note),docs/research/poc-2-vault-keys.md,docs/research/poc-3-mapping-bakeoff.md(0.64.1 runtime facts)- ADR-001 (the pin context), ADR-003 (feature graph the russh features compose under), ADR-004 (auth dispositions on this surface)
- Family:
alktls/alkhttp/alknetmanifests (the aws-lc-rs posture), family ADR-002 decision 5