Files
alkssh/CHANGELOG.md
T
glm-5.3-flash ab5236ebbb docs(release): wave 5 release readiness — crate docs, README, CHANGELOG, matrix, dry-run (w5-release-readiness)
- resolve the rustdoc warning set (9 incl. private-link class in
  client_ops.rs + redundant explicit links + a duplicated tty_map
  paragraph): cargo doc warning-free on default and --all-features
- docs honesty: the five recorded limits ride the published
  crate-root rustdoc (§Known limits: write_all no-deadline, PTY
  rule-5, port-0-only mint echo, no-reconnect policy, no-accept-all);
  crate docs state the feature graph + the fail-closed invariant
- two no_run usage doctests (server mount + dial) — the README
  examples stay compile-checked in every matrix build
- README.md lands (the door, feature graph, examples, custody
  posture, license); CHANGELOG.md carries the 0.1.0 founding entry
- feature matrix green (6 test builds, clippy x2 -D warnings, fmt,
  doc) + the fuzz corpus gate (11 invariants)
- cargo publish --dry-run --allow-dirty clean (76 files packaged +
  verified; file list checked against the package policy; manifest
  sanity recorded); the freeze inventory recorded for the gate

Verification: scripts/matrix.sh (all builds), fuzz corpus gate,
taskgraph validate
2026-10-30 19:29:23 +00:00

7.7 KiB
Raw Blame History

Changelog

All notable changes to this crate are documented here. The format is based on Keep a Changelog, and this crate adheres to Semantic Versioning.

[0.1.0] - 2026-10-30

The founding entry — the crate's first release. alkssh is the alk family's SSH adapter (family ADR-003): a thin wrapper around russh 0.65 terminating the vanilla-ssh wire and bridging to/from alkcall channels — the two-direction door for vanilla clients. The wire is russh's; the crate's substance is the channel-type mappings (session/pty → alktty, direct/forwarded-tcpip → alktunnels, git exec → alkgit), each behind its cargo feature in a flat, independent graph (ADR-003): a default build has no capabilities and serves nothing but clean declines — every unfeatured or unimplemented request is declined fail-closed, never half-served or silently fallen back, and never advertised. Identity is the family's: a verified key's fingerprint → alkcall IdentityProvider; keys the crate holds come from alkvault-backed sources, encrypted at rest, decrypted at use, never env vars (ADR-005). The crate is a door, not a backend — no binary, no deployment policy; a downstream app embeds it, enables features, and brings identity/ACL configuration.

Added

Phase 0/1 — research and architecture (the contract the implementation lands):

  • SDD process, phase 0 research set (docs/research/), and the three passed POCs (auth bridge, vault keys, mapping bake-off; findings in poc-1..3 + reverse-runner.md; POC source never merged).
  • Phase 1 architecture under docs/architecture/: the spec docs and ADRs 001–006 (Accepted) — the alk/ssh ALPN pin; the russh 0.65.0 pin (aws-lc-rs, no compression, rsa off); the capability feature graph; auth dispositions; vault-key custody; the mapping/bridge/ dispatch decisions.

Wave 1 — foundations:

  • The manifest: the russh 0.65 pin (aws-lc-rs, default features off), the flat feature graph (session / git / tunnel / sftp, default = []).
  • The fail-closed error taxonomy (thiserror): AdapterError, DialError, KeySourceError, OpError, OpenDeclineReason — declines are dispositions, never panics; no unwrap outside tests.
  • Vault-backed key custody in code: the KeySource / HostKeySource seams and the ADR-005 implementations (VaultKeySource, VaultHostKeySource) — decrypt-at-use / decrypt-at-construction, the Zeroizing seam, one decode_secret_key conversion.
  • The HostKeyPolicy seam (OQ-05, policy-blind) with the fail-closed default RejectAll — no accept-all built-in exists in the crate.
  • The contract-invariant fingerprint computation (the crate's single fingerprint path, the SHA256: format both the auth bridge and the host-key policy consume).
  • The config surface: ServeConfig, DialConfig, Limits (the bounded-resources budget model — wall clock always set, channel caps, keepalive posture) — unset fields decline at request time (OQ-08), construction never validates.

Wave 2 — the server stack:

  • SshAdapter — the mount point: SshAdapter::new(serve) builds the russh server from the config (fail-closed on key-source failure); adapter.handle(stream) serves one connection.
  • The auth bridge: russh auth hooks → ADR-004 dispositions — verified-key fingerprint → IdentityProvider::resolve_from_fingerprint, fail-closed on every path; bounded auth attempts.
  • Parse-only dispatch + the fail-closed decline core: every unroutable or unfeatured request answers a clean, channel-scoped decline; the spawned serving-path shapes (channel_failure then close).
  • Spawn-and-return plumbing (ADR-006 decision 4): serving paths run spawned (russh handlers return fast at this pin), with the exit-status-before-close mechanics.
  • Bounded resources at the handler surface: per-connection channel caps (refuse-never-queue) and listener caps.
  • The in-process loopback harness (the contract-test vehicle).

Wave 3 — the server mappings (the spine):

  • Per-feature seam handles (SessionSeam, GitSeam, TunnelListenSeam): unset seam → decline even with the feature on.
  • Decline-path tracing (tracing events on every decline class).
  • The git mapping (exec-only, ADR-006): the full exec grammar — git-{upload,receive}-pack '/<repo>' parsed and dispatched to alkgit; a subsystem request can never carry the repository and declines; 1 is honestly reported for push ng.
  • The session mapping: pty/shell/exec through the alktty seam over a translation bridge (chunk-framed both directions), OQ-44's reserved ttymodes JSON, the exit-chunk → SSH exit derivation (rules 1–6), control rows (window-change, signal) on a bounded per-channel surface.
  • Tunnel leg 1: the route-1 bridge — direct-tcpip / direct-streamlocal opens ride the assembly's TunnelSession over the family fabric; fabric failure is a clean ConnectFailed reject.
  • Tunnel leg 2: the -R listen flow — tcpip_forward / streamlocal_forward dial the fabric, arrivals correlate through the token router (miss → teardown-at-birth), the data leg opens forwarded-tcpip/forwarded-streamlocal back toward the client, port-0 mints echo the actually-bound port.

Wave 4 — the client direction:

  • The dial surface: dial(DialConfig) — key load (decrypt-at-dial), bounded russh client config, the host-key policy call, exactly one publickey attempt; SshConnection the handle.
  • The op rows: exec / pty_exec / shell (the alktty chunk plane), tunnel_direct / tunnel_direct_unix (byte duplex), git_service (pack duplex + consumed exit) — plus the sftp decline row (always declines, every build).
  • The -R leg: reverse_listen / reverse_listen_unix + the AcceptorRegistry (refuse-never-replace) and the acceptor traits — the hub asks the vanilla server to listen and serves the accepted channels.
  • Lifecycle primitives (OQ-12): explicitly cancellable listener handles, clean close() (Disconnect::ByApplication) — drop is never the clean path at this pin; no reconnect/restore policy (the crate ships primitives, the assembly composes).
  • Hardening riders: the git row's status-before-close by construction, the channel-not-held guard wire rows, tty control-row coverage, the ListenRouter token-collision pre-check.

Wave 5 — validation and release:

  • The decline-matrix contract suite: every mapping-decline row × every build it can appear in × both directions (the matrix runner scripts/matrix.sh — one command over all feature builds).
  • Real-tool e2e both directions: OpenSSH (pty/shell/exec, -L, -R, -D + curl), git clone and push through the door, and a real sshd against the client direction (exec, direct-tcpip dial, -R listen + acceptor) — check-gated, skipped rows carry reasons.
  • The fuzz/ sidecar: the ingress surfaces (exec parse grammar, fingerprint format, key decode, TerminalParamsWire) with the committed-seed corpus gate (cargo test --manifest-path fuzz/shared/Cargo.toml).
  • Release readiness: warning-free crate docs with the known-limits records riding the published rustdoc, this README, and the publish dry-run posture.

Notes

  • sftp is a feature of decline: enabling it adds no capability — the sftp subsystem request still declines in every build until the alkfs mapping lands (OQ-13; the decline stays contract territory).
  • The env request declines unconditionally (OQ-09): session cwd/env are assembly-supplied, never wire-derived.
  • The russh pin (0.65, aws-lc-rs, des/dsa never enabled) is a wire-relevant one-way door: bumps are deliberate, tested, and recorded (ADR-002).