feat(host-key): land the HostKeyPolicy seam (OQ-05, policy-blind)

- HostKeyPolicy trait: async, dyn-compatible (Arc<dyn> handle, the
  alkcall injected-handle pattern) — decide(&self, &PresentedHostKey)
  -> bool with host/port/fingerprint as the decision input
- Verdict type pinned to the russh 0.65 check_server_key shape:
  bool is the trust decision; decline reasons stay with the policy
  (declines are dispositions, not errors). Flagged for the wave-1 gate
- Built-in default RejectAll: fail-closed reject-all (russh's default,
  kept); no accept-all option exists in the crate
- async-trait 0.1 added for the dyn-compatible async handle
  (alkcall-precedented; tree-deduped). Flagged for the wave-1 gate
- Tests: default rejects; custom verdict honored; both through the dyn
  handle; the whole presented context reaches the policy

Verified: cargo test (14), cargo test --all-features, cargo clippy
--all-targets -- -D warnings, cargo fmt --check, taskgraph validate
This commit is contained in:
glm-5.3-flash committed 2026-10-28 06:40:40 +00:00
1 parent 22b82af517
commit 149f11d4b2
5 files changed
+248 -8

No files matched your search

+4
View File
@@ -36,6 +36,10 @@ tunnel = []
sftp = []
[dependencies]
# async-trait (the alkcall precedent) makes the injected handles
# dyn-compatible (`Arc<dyn ...>`) — the HostKeyPolicy dial handle needs
# that, and native AFIT traits are not object-safe at this toolchain.
async-trait = "0.1"
# ADR-002: aws-lc-rs only; default features off — no flate2, no rsa
# (ed25519-only; the tree stays RC-free except the ssh-key pin riding the
# russh keys path). Never enable russh's `des`/`dsa` features.