Files
alkssh/tasks/implementation/w1-host-key-policy.md
T
glm-5.3-flash 0b1bc284fa docs(plans): add wave-based implementation plan; decompose wave 1
- docs/plans/implementation.md: five-wave decomposition of the
  architecture (foundations -> server stack -> server mappings ||
  client direction -> validation & release), following the alkgit
  sibling pattern (decompose-implement-gate rhythm, per-wave
  decomposition records, review gates at wave boundaries)
- scope authority: v0.1.0 publishes the crate; assembly wiring stays
  out; sftp decline placeholder is shipped behavior
- wave 1 decomposed into eight task files under tasks/implementation/
  (manifest, error model, key sources, host-key policy, fingerprint,
  config surface, test doubles, review gate) with recorded
  interpretations flagged for the gate

Verification: taskgraph validate (12 tasks, no cycles); cargo test,
clippy -D warnings, fmt --check green
2026-10-28 06:13:26 +00:00

2.5 KiB

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
w1-host-key-policy Wave 1 — the HostKeyPolicy seam (OQ-05, policy-blind) pending
w1-manifest
narrow low project implementation

Description

Land the client-side host-key policy seam (auth.md §Host-key policy, OQ-05 resolution) — the trust-decision contract the dial surface calls:

  • The HostKeyPolicy trait — the crate surfaces the presented host key (host, port, fingerprint) to an assembly-provided policy that decides accept/reject. The two OQ-05 cases are the implementor's: case-1 pins (known beforehand — hard-decline on mismatch) and case-2 policies (unknown beforehand — prompt-and-record, learn-and-record, provider-metadata match, accept-and-continue for ephemeral fleets). The crate is policy-blind: it never decides trust, never hard-codes a trust model.
  • The crate default is fail-closed: reject unknown (russh's own reject-all default, kept as the built-in default policy). No accept-all built-in crate option — a permissive case-2 policy is the assembly's to write.
  • The trait receives the fingerprint string (the wave-1 fingerprint computation is the caller's input path, wave-4 dial); the exact decision type (bool vs a richer verdict carrying a reason) is the task's to pin against the russh check_server_key hook shape at this pin — flagged for the wave-1 gate.
  • The russh client-handler consumption (check_server_key wiring) is wave-4 dial-surface material — this task lands the seam and its default only.

Acceptance Criteria

  • HostKeyPolicy trait in place; the presented-key context (host, port, fingerprint) is the decision input
  • Built-in default policy rejects unknown keys (fail-closed); no accept-all option exists in the crate
  • Doc comments carry the two-case model and the policy-blind rule
  • Unit tests: default policy rejects; a custom policy's verdict is honored
  • cargo test, cargo clippy --all-targets -- -D warnings, cargo fmt --check pass

References

  • docs/architecture/auth.md §Host-key policy (OQ-05 resolution)
  • docs/architecture/client.md §The dial surface, §What the crate does not include (trust decisions)
  • docs/architecture/decisions/005-at-rest-key-custody.md (decision 6 — the client host-pin is public config, never vault material)
  • docs/research/auth-bridge.md §Host keys and check_server_key

Notes

To be filled by implementation agent

Summary

To be filled on completion