diff --git a/Cargo.toml b/Cargo.toml index 20945a0..ce862a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ # Single-crate protocol/door crate (the alktty template). No workspace: -# the composition story is deferred — alkssh's substance is the mappings -# (family ADR-003). The `fuzz/` sidecar is its own workspace (excluded — +# the composition story is deferred: alkssh's substance is the mappings +# (family ADR-003). The `fuzz/` sidecar is its own workspace (excluded: # it pins its own nightly toolchain and never rides the root's). [workspace] members = ["."] @@ -12,14 +12,14 @@ version = "0.2.0" edition = "2024" rust-version = "1.89" license = "MIT OR Apache-2.0" -description = "SSH adapter for the alk family: russh-wrapped vanilla-ssh termination bridged to/from alkcall channels — session/pty, tunnels, git exec — with every capability mapping a fail-closed cargo feature (no features: no capabilities)" +description = "SSH adapter for the alk family: russh-wrapped vanilla-ssh termination bridged to/from alkcall channels (session/pty, tunnels, git exec), with every capability mapping a fail-closed cargo feature (no features: no capabilities)" repository = "https://git.alk.dev/alkdev/alkssh" keywords = ["ssh", "russh", "protocol", "alkcall", "network"] categories = ["network-programming", "asynchronous"] # The package policy (the sibling crates' convention): the published crate # ships the architecture docs (the authoritative contract) but not the -# process surface — reviews, research, plans, task files, the working -# agents' config, AGENTS.md — and not the `fuzz/` sidecar (its own +# process surface: reviews, research, plans, task files, the working +# agents' config, AGENTS.md; and not the `fuzz/` sidecar (its own # workspace; never a root dep, never a shipped surface). exclude = [".opencode/", "AGENTS.md", "docs/reviews/", "docs/plans/", "docs/research/", "docs/sdd_process.md", "tasks/", "fuzz/"] @@ -27,12 +27,12 @@ exclude = [".opencode/", "AGENTS.md", "docs/reviews/", "docs/plans/", "docs/rese name = "alkssh" [features] -# ADR-003: flat and independent — no feature implies another; `default = []` +# ADR-003: flat and independent, no feature implies another; `default = []` # by design (a default build has no capabilities; every unfeatured open # declines fail-closed). The wave-2 decline core is the first `cfg` # consumer; the wave-3 seam-config handles are the second (each optional # sibling dep is gated feature-to-dep so a git-build never compiles -# alktty and vice versa — the wave-1 manifest rule: per-feature sibling +# alktty and vice versa, per the wave-1 manifest rule: per-feature sibling # deps land with their first consuming wave, which for alktty/alkgit is # the wave-3 config fields and for alktunnels `w3-tunnel-direct`, the # route-1 bridge). @@ -44,28 +44,28 @@ sftp = [] [dependencies] # async-trait (the alkcall precedent) makes the injected handles -# dyn-compatible (`Arc`) — the HostKeyPolicy dial handle needs +# dyn-compatible (`Arc`); 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 +# ADR-002: aws-lc-rs only; default features off, meaning no flate2 and +# 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. russh = { version = "0.65", default-features = false, features = ["aws-lc-rs"] } alkcall = "0.10" # alkvault 0.2 (breaking req bump, 0.1 -> 0.2, 2026-11-04): `decrypt` -# returns `Zeroizing` (alkvault review 001's resolution — the +# returns `Zeroizing` (alkvault review 001's resolution; the # pre-wrap plaintext window ADR-005 decision 3 recorded is closed # upstream); the adapter-side wrap is dropped. Pin re-verified against # crates.io: MIT OR Apache-2.0. alkvault = "0.2" # Wave-3 seam-handle types (`config.rs`'s `SessionSeam`/`GitSeam`). # Pins verified against crates.io (2026-11-04): alktty 0.8.2 (0.1.0's -# 0.8.1 pin refreshed — 0.8.2 is the PTY exit-signal-fidelity fix, +# 0.8.1 pin refreshed; 0.8.2 is the PTY exit-signal-fidelity fix, # patch-level, API/wire unchanged; alkssh consumes negative exit # codes verbatim so the derivation contract needed no change), alkgit -# 0.1.0 — both MIT OR Apache-2.0, both rust_version ≤ our 1.89, +# 0.1.0: both MIT OR Apache-2.0, both rust_version ≤ our 1.89, # both over alkcall ^0.10 (shared with our `alkcall = "0.10"` → -# 0.10.1 resolution). alktty's `local` feature stays off — alkssh +# 0.10.1 resolution). alktty's `local` feature stays off; alkssh # never touches a real backend; the `local` shapes stay alktty-side. alktty = { version = "0.8.2", default-features = false, optional = true } alkgit = { version = "0.1.0", default-features = false, optional = true } @@ -73,13 +73,13 @@ alkgit = { version = "0.1.0", default-features = false, optional = true } # open_direct`/`take_halves`, `SubstrateAddr`/`Substrate`) + the # forwarded serving surface's establisher shape # (`register_tunnel_forwarded_openable_with_establisher` + -# `ForwardedGate` — the review-003 W2 adoption, ADR-008 Amendment 2's +# `ForwardedGate`, the review-003 W2 adoption, ADR-008 Amendment 2's # recommended shape). Pin re-verified against crates.io (2026-11-04): # 0.5.0 is newest_version, additive API only over 0.4.1 (the wire # delta is empty, the base registration is byte-for-byte), MIT OR # Apache-2.0, rust_version 1.88 ≤ our 1.89, alkcall ^0.10.1 pinned # exactly (single-versioned against our `alkcall = "0.10"`). The -# `local` feature stays off — the dial seam is injected (`DialFn`); +# `local` feature stays off (the dial seam is injected `DialFn`); # the real dial/backends belong to the assembly, and the tests # hand-roll their own dial/dial-fail seams (`tests/tunnel_mapping.rs`). alktunnels = { version = "0.5.0", default-features = false, optional = true } @@ -87,7 +87,7 @@ alktunnels = { version = "0.5.0", default-features = false, optional = true } # and the exit-chunk / negotiation-error-frame JSON reads in `tty_map.rs`. # Same pin alktty carries (crate resolution stays single-versioned). serde_json = { version = "1", optional = true } -# session-only: the alktty chunk plane is `bytes`-based (`Chunk.bytes`) — +# session-only: the alktty chunk plane is `bytes`-based (`Chunk.bytes`), # the bridge builds sentinel/ctrl chunks with it. Same pin russh/alktty # carry (crate resolution stays single-versioned). bytes = { version = "1", optional = true } @@ -99,20 +99,20 @@ zeroize = "1.9" [dev-dependencies] # The git-seam test doubles name `GitPackGen`'s `gix_hash::ObjectId` -# parameters and alkgit does not re-export them — test-graph only, +# parameters and alkgit does not re-export them (test-graph only), # version matched to alkgit's `^0.28` req (same crate in the lockfile). gix-hash = { version = "0.28", features = ["sha1"] } # The session shim's scripted stdout/stderr streams ride tokio's -# `ReceiverStream` — test-graph only (the crate proper hand-rolls no +# `ReceiverStream`, test-graph only (the crate proper hand-rolls no # streams). tokio-stream = "0.1" # The leg-2 fabric double's establisher/params serialization -# (`w3-tunnel-listen`) — test-graph only (the door's own lib code +# (`w3-tunnel-listen`), test-graph only (the door's own lib code # stays serde-free under the `tunnel` feature; the double's # dynamic-bind producer serializes params/reply fields). serde_json = "1" # The real-tool pty smoke (`w3-tty-session`): alktty's `local` backend -# composition — the dev-dep `features = ["local"]` unification applies +# composition: the dev-dep `features = ["local"]` unification applies # to the TEST graph only (feature unification folds `local` into the # optional alktty dep in test builds; the published lib never enables # it and `src/` never names a local shape). Same 0.8.2 pin. diff --git a/fuzz/README.md b/fuzz/README.md index 2a2a702..71e6754 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -1,16 +1,16 @@ # alkssh fuzzing -libFuzzer targets for alkssh's ingress surfaces — the family standing +libFuzzer targets for alkssh's ingress surfaces: the family standing rule (anything worth fuzzing gets fuzzed), landed per the plan's wave-5 -charter and the alkgit convention: the JSON schema gate itself is +charter and the alkgit convention. The JSON schema gate itself is alkcall's surface, family-fuzzed there; SSH framing, key exchange, and -the channel multiplexer are russh's wire (family ADR-003) — the +the channel multiplexer are russh's wire (family ADR-003); the alkssh-owned post-framing ingress is what fuzzes here. ## Layout -- `fuzz_targets/` — one binary per target; thin `fuzz_target!` wrappers. -- `shared/` — the invariant logic, as a plain library so normal +- `fuzz_targets/`: one binary per target; thin `fuzz_target!` wrappers. +- `shared/`: the invariant logic, as a plain library so normal `cargo test` (stable toolchain) can replay the committed corpora through the same invariants (`#[cfg(test)]` modules; quinn's CI pattern). The fuzz binaries are nightly-only; the shared crate is @@ -18,34 +18,34 @@ alkssh-owned post-framing ingress is what fuzzes here. `#[doc(hidden)]` fuzz-visible exposures: the exec-grammar parse path in `src/dispatch.rs`, the key-decode arm `decode_key_arm` in `src/key_source.rs`, and the `terminal_params` conversion in - `src/tty_map.rs` — the recorded exposure decisions: the ingresses are + `src/tty_map.rs`; the recorded exposure decisions: the ingresses are production-private, so the exposures are the production surfaces themselves, never forks; the fingerprint ingress is fully public API) and must never become a dependency of the root crate. -- `corpus//` — committed hand-made seeds (regenerate with - `python3 fuzz/gen_fuzz_seeds.py` from the repo root — must be a no-op - diff on the committed set). Only `seed-*` files are tracked; grown +- `corpus//`: committed hand-made seeds (regenerate with + `python3 fuzz/gen_fuzz_seeds.py` from the repo root; the result must + be a no-op diff on the committed set). Only `seed-*` files are tracked; grown corpora (SHA-named units), artifacts, and coverage output are gitignored and are **not** merged back into the committed seeds. -- `run-detached.sh` — mandatory runner for agent sessions: wraps +- `run-detached.sh`: the mandatory runner for agent sessions. It wraps `cargo fuzz run` in `setsid` + `nohup` + log redirection so an OOM in a target can never take down the agent host. -- `gen_fuzz_seeds.py` — deterministic seed generator (quiche pattern). +- `gen_fuzz_seeds.py`: deterministic seed generator (quiche pattern). ## Targets | Target | Drives | Invariants | |---|---|---| -| `exec_parse` | the production exec-grammar parse (`parse_exec`, `src/dispatch.rs` — the handler's ingress shape: byte string → `from_utf8` fallback `""` → parse; the pre-parse `max_exec_command_len` cap and the git row's `invalid-repo-id` gate are the root contract rows' territory, the parse is everything behind them) | no-panic on any byte string (any length behind the cap); the typed routing classes (git-parseable → the git row, non-git → the session pipe path, service-only → decline-with-reason) agree with a from-spec grammar oracle (the differential pair) and are stable per input; for `Git` routes the repo-id gate classification is deterministic | -| `fingerprint` | the crate's single fingerprint path ([`alkssh::fingerprint`] over `russh::keys::parse_public_key_base64` — ADR-004 decision 1) | no-panic on arbitrary key blobs (a non-blob is the parse's typed refusal); every accepted key's fingerprint is exactly the `SHA256:` + unpadded-standard-base64 contract shape (43-char body, canonical alphabet, decodes to a 32-byte digest, re-encodes canonically); determinism; the committed `ssh-keygen -lf` parity vectors still agree (the corpus-gate test row) | -| `key_decode` | the decrypt-at-use chain's decode arm (`decode_key_arm`, `src/key_source.rs` — the production `decrypt_and_decode` conversion exposed `#[doc(hidden)]`) + the underlying `decode_secret_key` passphrase arm (robustness drive — the production chain always passes `None`) | no-panic on arbitrary plaintext shapes (the vault's `String` shape, lossy from arbitrary bytes) and passphrase shapes; every failure on the production arm is exactly the typed `KeySourceError::Decode` class — never a catch-all, never a panic; the failure text never carries the plaintext; the `Zeroizing` posture rides the drive (the wrap is what the adapter seam applies); determinism | -| `terminal_params` | the `pty_request` args → `TerminalParamsWire` conversion (`terminal_params`, `src/tty_map.rs` — OQ-44's SSH modes → reserved-modes `{}` JSON) | no-panic on arbitrary term strings, u32 dimensions, and mode blobs (the modes are never parsed — reserved); the dimension clamp is exactly the recorded cap (`min(value, 65535)`, never a magnitude truncation); `term` preserved verbatim; the reserved-modes JSON is always exactly `{}`; the full serialized wire shape is deterministic per input | +| `exec_parse` | the production exec-grammar parse (`parse_exec`, `src/dispatch.rs`, the handler's ingress shape: byte string → `from_utf8` fallback `""` → parse; the pre-parse `max_exec_command_len` cap and the git row's `invalid-repo-id` gate are the root contract rows' territory, the parse is everything behind them) | no-panic on any byte string (any length behind the cap); the typed routing classes (git-parseable → the git row, non-git → the session pipe path, service-only → decline-with-reason) agree with a from-spec grammar oracle (the differential pair) and are stable per input; for `Git` routes the repo-id gate classification is deterministic | +| `fingerprint` | the crate's single fingerprint path ([`alkssh::fingerprint`] over `russh::keys::parse_public_key_base64`, ADR-004 decision 1) | no-panic on arbitrary key blobs (a non-blob is the parse's typed refusal); every accepted key's fingerprint is exactly the `SHA256:` + unpadded-standard-base64 contract shape (43-char body, canonical alphabet, decodes to a 32-byte digest, re-encodes canonically); determinism; the committed `ssh-keygen -lf` parity vectors still agree (the corpus-gate test row) | +| `key_decode` | the decrypt-at-use chain's decode arm (`decode_key_arm`, `src/key_source.rs`, the production `decrypt_and_decode` conversion exposed `#[doc(hidden)]`) + the underlying `decode_secret_key` passphrase arm (a robustness drive; the production chain always passes `None`) | no-panic on arbitrary plaintext shapes (the vault's `String` shape, lossy from arbitrary bytes) and passphrase shapes; every failure on the production arm is exactly the typed `KeySourceError::Decode` class, never a catch-all, never a panic; the failure text never carries the plaintext; the `Zeroizing` posture rides the drive (the wrap is what the adapter seam applies); determinism | +| `terminal_params` | the `pty_request` args → `TerminalParamsWire` conversion (`terminal_params`, `src/tty_map.rs`, OQ-44's SSH modes → reserved-modes `{}` JSON) | no-panic on arbitrary term strings, u32 dimensions, and mode blobs (the modes are never parsed; they are reserved); the dimension clamp is exactly the recorded cap (`min(value, 65535)`, never a magnitude truncation); `term` preserved verbatim; the reserved-modes JSON is always exactly `{}`; the full serialized wire shape is deterministic per input | ## Commands `cargo fuzz build` and `cargo fuzz run` must be executed with `fuzz/` (or deeper) as the working directory so rustup selects the pinned -nightly toolchain — the detached runner handles that itself. +nightly toolchain; the detached runner handles that itself. ```sh # build (nightly, pinned by rust-toolchain.toml inside fuzz/; run from fuzz/) diff --git a/fuzz/fuzz_targets/exec_parse.rs b/fuzz/fuzz_targets/exec_parse.rs index 7ecdf94..1a40135 100644 --- a/fuzz/fuzz_targets/exec_parse.rs +++ b/fuzz/fuzz_targets/exec_parse.rs @@ -1,7 +1,7 @@ #![no_main] -//! The exec-grammar target (`mapping.md` §Session-channel dispatch — -//! the git-parseable exec grammar + the dispatch parse path) — thin +//! The exec-grammar target (`mapping.md` §Session-channel dispatch, +//! the git-parseable exec grammar + the dispatch parse path): a thin //! wrapper over the shared invariant battery. use libfuzzer_sys::fuzz_target; diff --git a/fuzz/fuzz_targets/fingerprint.rs b/fuzz/fuzz_targets/fingerprint.rs index 24d660e..d0accc9 100644 --- a/fuzz/fuzz_targets/fingerprint.rs +++ b/fuzz/fuzz_targets/fingerprint.rs @@ -1,7 +1,7 @@ #![no_main] -//! The fingerprint-format target (ADR-004 decision 1 — the `SHA256:` + -//! unpadded base64 path) — thin wrapper over the shared invariant +//! The fingerprint-format target (ADR-004 decision 1, the `SHA256:` + +//! unpadded base64 path): a thin wrapper over the shared invariant //! battery. use libfuzzer_sys::fuzz_target; diff --git a/fuzz/fuzz_targets/key_decode.rs b/fuzz/fuzz_targets/key_decode.rs index 72e50cf..e4ce00d 100644 --- a/fuzz/fuzz_targets/key_decode.rs +++ b/fuzz/fuzz_targets/key_decode.rs @@ -1,7 +1,7 @@ #![no_main] -//! The key-decode target (ADR-005 decision 2 — the decrypt-at-use -//! chain's `decode_secret_key` seam) — thin wrapper over the shared +//! The key-decode target (ADR-005 decision 2, the decrypt-at-use +//! chain's `decode_secret_key` seam): a thin wrapper over the shared //! invariant battery. use libfuzzer_sys::fuzz_target; diff --git a/fuzz/fuzz_targets/terminal_params.rs b/fuzz/fuzz_targets/terminal_params.rs index 8c28149..5a863ec 100644 --- a/fuzz/fuzz_targets/terminal_params.rs +++ b/fuzz/fuzz_targets/terminal_params.rs @@ -1,8 +1,8 @@ #![no_main] -//! The terminal-parameters target (`tty_map.rs` — the `pty_request` +//! The terminal-parameters target (`tty_map.rs`, the `pty_request` //! args → `TerminalParamsWire` conversion, the SSH modes → reserved -//! modes JSON) — thin wrapper over the shared invariant battery. +//! modes JSON): a thin wrapper over the shared invariant battery. use libfuzzer_sys::fuzz_target; diff --git a/fuzz/shared/src/corpus.rs b/fuzz/shared/src/corpus.rs index 62c167e..24d491c 100644 --- a/fuzz/shared/src/corpus.rs +++ b/fuzz/shared/src/corpus.rs @@ -1,7 +1,7 @@ //! The corpus-replay plumbing: the committed seeds replay through the //! invariant batteries on the stable toolchain (`cargo test //! --manifest-path fuzz/shared/Cargo.toml` runs this in -//! `#[cfg(test)]` modules across the ingress units — the quinn CI +//! `#[cfg(test)]` modules across the ingress units, the quinn CI //! pattern), so the gate never needs a fuzzing session. pub fn read_corpus(target: &str) -> Vec> { diff --git a/fuzz/shared/src/exec_parse.rs b/fuzz/shared/src/exec_parse.rs index d9ede07..7771fba 100644 --- a/fuzz/shared/src/exec_parse.rs +++ b/fuzz/shared/src/exec_parse.rs @@ -1,10 +1,10 @@ //! The exec-grammar ingress (`mapping.md` §Session-channel dispatch, //! `dispatch.rs`): the production `parse_exec` path driven on arbitrary -//! command strings — no-panic, typed routing classes, and agreement +//! command strings: no-panic, typed routing classes, and agreement //! with a from-spec re-derivation of the grammar. The production //! ingress shape is the handler's: the per-length cap //! (`Limits::max_exec_command_len`) is enforced *before* the parse -//! (decline first, alloc never — the cap's pre-parse placement is +//! (decline first, alloc never; the cap's pre-parse placement is //! pinned by the root's contract rows in `tests/dispatch_core.rs`); //! everything behind the cap is this battery: a byte string → //! `std::str::from_utf8(..).unwrap_or("")` → the parse (invalid UTF-8 @@ -43,7 +43,7 @@ pub fn fuzz_exec_parse(data: &[u8]) { /// The from-spec oracle: the grammar re-derived from the dispatch /// module's documented rules, sharing no code with the -/// implementation — the differential pair (the repo_id target's +/// implementation, the differential pair (the repo_id target's /// oracle pattern). fn spec_parse(command: &str) -> ExecRoute { let (token, argument) = match command.split_once(' ') { @@ -64,7 +64,7 @@ fn spec_parse(command: &str) -> ExecRoute { } /// The serving-service arm of the oracle: a serving token must carry -/// a non-empty, path-shaped argument (SSH exec must carry the repo — +/// a non-empty, path-shaped argument (SSH exec must carry the repo; /// service-only is the decline-with-reason class; anything else /// unparseable is the pipe row). fn spec_serving(service: GitServiceRoute, argument: Option<&str>) -> ExecRoute { @@ -78,9 +78,9 @@ fn spec_serving(service: GitServiceRoute, argument: Option<&str>) -> ExecRoute { } } -/// The argument grammar re-derived: a path-shaped argument — fully -/// single-quote-wrapped (a non-empty inner ending in a quote) or -/// unquoted absolute — normalized by stripping the quotes, one +/// The argument grammar re-derived: a path-shaped argument, either +/// fully single-quote-wrapped (a non-empty inner ending in a quote) or +/// unquoted absolute, normalized by stripping the quotes, one /// leading `/`, and one trailing `.git` suffix (an empty-after-strip /// prefix keeps the suffix; the git row's validation declines the /// empties, never a silent emptying). diff --git a/fuzz/shared/src/fingerprint.rs b/fuzz/shared/src/fingerprint.rs index fab3e31..e5eb02a 100644 --- a/fuzz/shared/src/fingerprint.rs +++ b/fuzz/shared/src/fingerprint.rs @@ -1,9 +1,9 @@ //! The fingerprint format ingress (ADR-004 decision 1, //! `fingerprint.rs`): arbitrary key blobs through the crate's single -//! fingerprint path — the composition of russh's public OpenSSH blob +//! fingerprint path: the composition of russh's public OpenSSH blob //! parse (`russh::keys::parse_public_key_base64`, the same re-export //! the crate's surface rides) and the crate's public -//! [`alkssh::fingerprint`]. The ingress is fully public API — the +//! [`alkssh::fingerprint`]. The ingress is fully public API; the //! recorded exposure decision needs no `#[doc(hidden)]` surface. //! //! Invariants: no-panic on any byte string (a non-blob is the parse's @@ -11,7 +11,7 @@ //! accepted key's fingerprint is exactly the `SHA256:` + unpadded //! standard base64 contract shape (one `:` separator, 43-char body, //! canonical alphabet, 32-byte digest decoded exactly); determinism -//! (same key, same string — and the same string re-parses to the same +//! (same key, same string; the same string re-parses to the same //! verdict). The committed `ssh-keygen -lf` parity vectors //! (`tests/vectors/`) are replayed by the corpus-gate tests below. @@ -98,7 +98,7 @@ fn decode_unpadded(body: &str) -> Option> { Some(out) } -/// A from-spec unpadded standard-base64 encoder — the re-encode half. +/// A from-spec unpadded standard-base64 encoder: the re-encode half. fn encode_unpadded(bytes: &[u8]) -> String { const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; let mut out = Vec::new(); diff --git a/fuzz/shared/src/key_decode.rs b/fuzz/shared/src/key_decode.rs index e1420d3..57cb909 100644 --- a/fuzz/shared/src/key_decode.rs +++ b/fuzz/shared/src/key_decode.rs @@ -1,30 +1,30 @@ //! The key-decode ingress (ADR-005 decision 2, `key_source.rs`): the -//! decrypt-at-use chain's one-time `decode_secret_key` conversion — +//! decrypt-at-use chain's one-time `decode_secret_key` conversion, //! driven through the production arm itself //! ([`alkssh::decode_key_arm`], the `#[doc(hidden)]` exposure that is //! `decrypt_and_decode`'s exact decode stage, not a fork). //! //! Invariants: no-panic on arbitrary plaintext shapes (the production -//! plaintext is the vault's `Zeroizing` — valid UTF-8 by +//! plaintext is the vault's `Zeroizing`, valid UTF-8 by //! return type; the battery shapes arbitrary bytes into that form via //! the lossy conversion and drives it through the same zeroized //! wrap the vault's `decrypt` return applies, alkssh 0.2.0 seam) and //! arbitrary passphrase shapes (the -//! underlying decode's passphrase arm — the production chain always +//! underlying decode's passphrase arm; the production chain always //! passes `None`; the `Some` arm is robustness drive only); every -//! failure is the typed [`KeySourceError::Decode`] class — never a +//! failure is the typed [`KeySourceError::Decode`] class, never a //! catch-all, never another variant on this arm, never a panic; the //! failure text never carries the plaintext (the assertable half of -//! the Zeroizing posture — the plaintext exists solely inside the -//! call, dropped zeroized; no retention, no static cache — and the +//! the Zeroizing posture: the plaintext exists solely inside the +//! call, dropped zeroized, with no retention and no static cache; the //! typed error's only payload is the decode machinery's message //! class, never the plaintext). //! //! The no-echo invariant's assertable form is *the bounded-message //! pair* (reshaped in-task after the first campaign's finding): the -//! failure text is a bounded fixed message (≤ 256 bytes — the decode +//! failure text is a bounded fixed message (≤ 256 bytes; the decode //! machinery's vocabulary, never a growable echo), and no 256-byte -//! contiguous plaintext run appears in it — which, given the bound, +//! contiguous plaintext run appears in it, which, given the bound, //! cannot false-fire (a string shorter than 256 bytes cannot contain a //! 256-byte run). A plaintext-`contains`-message check in the other //! direction was unsound: an attacker-chosen plaintext can be a @@ -70,7 +70,7 @@ fn fingerprint(key: &russh::keys::PrivateKey) -> String { } /// The typed-class invariant: `Ok` or exactly -/// [`KeySourceError::Decode`] — the decode arm's only failure shape — +/// [`KeySourceError::Decode`] (the decode arm's only failure shape), /// and the Decode text is the bounded fixed-message pair (see the /// module docs; the two assertions are jointly airtight). fn typed_decode_class(outcome: &Result, plaintext: &str) { @@ -123,7 +123,7 @@ mod invariants { } /// A plaintext that is not OpenSSH-PEM key material is a - /// [`KeySourceError::Decode`] refusal (the inner-format contract — + /// [`KeySourceError::Decode`] refusal (the inner-format contract: /// decision 1, never a fallback). #[test] fn non_key_plaintext_is_the_typed_decode_refusal() { diff --git a/fuzz/shared/src/terminal_params.rs b/fuzz/shared/src/terminal_params.rs index d7f98aa..7a2a145 100644 --- a/fuzz/shared/src/terminal_params.rs +++ b/fuzz/shared/src/terminal_params.rs @@ -1,22 +1,22 @@ //! The terminal-parameters ingress (`tty_map.rs`, OQ-44's reserved //! modes): the `pty_request` args → `TerminalParamsWire` conversion //! driven through the production [terminal_params] surface (the -//! `#[doc(hidden)]` exposure — `handler.rs`'s `pty_request` row +//! `#[doc(hidden)]` exposure: `handler.rs`'s `pty_request` row //! constructs the stored params with exactly this function). //! //! The harness's framed feed (deterministic, seed-friendly): //! `term_len` (u32 LE, bounded to the remaining input) + the term //! bytes + four u32 LE dimensions (`cols`/`rows`/pixel width/height, //! zero-defaulted when the input runs out) + an arbitrary trailing -//! mode blob. The mode blob is *never parsed* — the SSH ttymodes ride -//! the reserved `{}` JSON (OQ-44, backends ignore modes in v1) — so +//! mode blob. The mode blob is *never parsed*; the SSH ttymodes ride +//! the reserved `{}` JSON (OQ-44, backends ignore modes in v1), so //! the battery's totality over arbitrary mode blobs is by //! construction; the framing demonstrates it (the conversion's //! outcome never varies with the blob). //! //! Invariants: no-panic on any term string (empty, unicode, control //! characters) and any u32 dimensions; the dimension clamp is the -//! recorded cap (`min(value, 65535)` — a dimension beyond 65535 is +//! recorded cap (`min(value, 65535)`; a dimension beyond 65535 is //! nonsense on both papers) computed exactly, never a magnitude //! truncation; `term` is preserved verbatim; the reserved-modes JSON //! is always exactly the empty object; the full wire shape is @@ -89,7 +89,7 @@ pub fn fuzz_terminal_params(data: &[u8]) { } } -/// The cursor's u32 (zero-defaulted when the framed field is absent — +/// The cursor's u32 (zero-defaulted when the framed field is absent; /// the feed is total over any input). fn take_u32(cursor: &mut &[u8]) -> u32 { if cursor.len() >= 4 { diff --git a/scripts/matrix.sh b/scripts/matrix.sh index b6b6145..6fdd3cc 100755 --- a/scripts/matrix.sh +++ b/scripts/matrix.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # The decline-matrix runner (tasks/implementation/w5-decline-matrix.md): -# the per-build verification set as one command — `cargo test` per +# the per-build verification set as one command: `cargo test` per # feature build (none / git / session / tunnel / sftp-only / # --all-features; the sftp-only run is the no-op-feature fact itself # verified), clippy ×2 (-D warnings, with and without diff --git a/src/adapter.rs b/src/adapter.rs index 0a9664f..6dce0b6 100644 --- a/src/adapter.rs +++ b/src/adapter.rs @@ -1,8 +1,8 @@ -//! The server-direction mount point (ADR-001) — [`SshAdapter`], the +//! The server-direction mount point (ADR-001): [`SshAdapter`], the //! constructed russh server stack every mapping composes into. //! //! Construction ([`SshAdapter::new`], ADR-005 decision 6): the -//! injected [`HostKeySource`] loads **decrypt-at-construction** — a +//! injected [`HostKeySource`] loads **decrypt-at-construction**; a //! locked / absent / decryption-failed / unknown-version / undecodable //! load means **no server is constructed**: the error surfaces as //! [`AdapterError::Construction`] with the original [`KeySourceError`] @@ -11,34 +11,35 @@ //! host-key source contract's [`KeySourceError::Absent`] shape). //! //! The russh server `Config` (ADR-002 surface notes; ADR-004 decision -//! 4): `methods` is `{publickey}` **exactly** (honest advertisement — +//! 4): `methods` is `{publickey}` **exactly** (honest advertisement: //! `MethodSet::from(&[MethodKind::PublicKey][..])`, never russh's //! `server_supported()`), the loaded host keys ride `Config::keys`, //! and the [`Limits`] knobs map one-for-one: //! `window_size` / `maximum_packet_size` / `channel_buffer_size` / //! `max_auth_attempts` verbatim, `inactivity_timeout` as **always -//! `Some`** — the bounded-resources posture (the crate never +//! `Some`**, the bounded-resources posture (the crate never //! constructs a session with no wall clock). Everything else stays at //! russh 0.65's own default posture (`Config::default()`, left //! un-touched deliberately): the rekey `Limits` stay russh-enforced at //! their RFC-4253 §9 defaults, `auth_rejection_time` stays russh's //! constant-rejection knob, and the preferred-algorithm set stays -//! russh's — the ed25519-only key-algorithm posture holds by the +//! russh's; the ed25519-only key-algorithm posture holds by the //! loaded key set itself (ADR-002 decision 4) and by the auth bridge's //! explicit non-ed25519 decline (`w2-auth-bridge`). //! //! The mount ([`SshAdapter::handle`], ADR-001's contract): a generic //! byte-duplex stream in, the full russh server stack per stream via -//! [`russh::server::run_stream`], returned **run to completion** — +//! [`russh::server::run_stream`], returned **run to completion**; //! the edge-termination shape only, no ALPN code, no relay leg (the //! `alk/ssh` pin is a ledger entry; nothing here speaks it). The //! in-flight framing is the alkhttp door precedent: `handle` is an //! async per-stream call whose completion is the session's end, so the -//! assembly's accept loop mounts per stream via `tokio::spawn` — the -//! serving loop itself stays spawned inside russh (ADR-006 decision 4, -//! which `run_stream` already satisfies: the session's packet loop -//! leaves on its own task), and the mount's return type stays -//! `Result<(), AdapterError>` — no russh type rides the signature. +//! assembly's accept loop mounts per stream via `tokio::spawn`, and +//! the serving loop itself stays spawned inside russh (ADR-006 +//! decision 4, which `run_stream` already satisfies: the session's +//! packet loop leaves on its own task), and the mount's return type +//! stays `Result<(), AdapterError>` (no russh type rides the +//! signature). use std::sync::Arc; @@ -53,7 +54,7 @@ use crate::handler::SessionHandler; #[cfg(feature = "tunnel")] use crate::tunnel_map; -/// The constructed server stack — the substrate every channel-type +/// The constructed server stack, the substrate every channel-type /// mapping composes into (ADR-001's `SshAdapter`). /// /// Built by [`SshAdapter::new`] from the assembly-supplied @@ -67,8 +68,8 @@ pub struct SshAdapter { } impl SshAdapter { - /// Constructs the adapter — decrypt-at-construction of the host - /// key set (ADR-005 decision 6): a failed or empty load is no + /// Constructs the adapter: decrypt-at-construction of the host + /// key set (ADR-005 decision 6); a failed or empty load is no /// server, with the [`KeySourceError`] refused through /// [`AdapterError::Construction`]. pub async fn new(serve: ServeConfig) -> Result { @@ -98,7 +99,7 @@ impl SshAdapter { }) } - /// The mounted russh server `Config` — in-crate inspection for the + /// The mounted russh server `Config`, in-crate inspection for the /// contract tests (advertisement and knob mapping); not public /// surface: the mount's behavior is observable on the wire, never /// through a russh type leak. @@ -108,7 +109,7 @@ impl SshAdapter { } /// The mount (ADR-001): mounts the full russh server stack on one - /// generic duplex byte stream and runs it to completion — an + /// generic duplex byte stream and runs it to completion; an /// accepted vanilla-SSH transport is authenticated and served on /// this call's task; the assembly's accept loop mounts per stream /// with `tokio::spawn(adapter.handle(stream))`. @@ -126,7 +127,7 @@ impl SshAdapter { } } -/// The adapter's own `Config` construction from the serve-config — the +/// The adapter's own `Config` construction from the serve-config: the /// documented subset mapped one-for-one, everything else at russh's /// default posture (see the module docs; ADR-002 surface notes). fn build_server_config(serve: &ServeConfig, keys: Vec) -> russh::server::Config { @@ -160,7 +161,7 @@ mod tests { const NOOP: alkcall::core::auth::NoopIdentityProvider = alkcall::core::auth::NoopIdentityProvider; - /// The committed test-key fixtures — the wave-1 fixture set, read + /// The committed test-key fixtures (the wave-1 fixture set), read /// through `include_str!` per the wave-1 convention (the /// `tests/common` double module is the tests/-side owner; src-unit /// tests read the fixture files, never its exports). diff --git a/src/channel_cap.rs b/src/channel_cap.rs index b453901..88cb72c 100644 --- a/src/channel_cap.rs +++ b/src/channel_cap.rs @@ -1,9 +1,9 @@ -//! The in-crate concurrent-channel cap (`w2-bounded-resources`) — the +//! The in-crate concurrent-channel cap (`w2-bounded-resources`): the //! bound itself, carried by the per-connection handler //! ([`crate::handler`]) and enforced at every `channel_open_*` accept //! path (`overview.md` §Bounded-resources policy: "concurrent channels -//! per session — ours (in-crate) + per-identity policy when bridged"; -//! AGENTS.md convention 9 — SSH servers are internet-facing; unbounded +//! per session (ours, in-crate) + per-identity policy when bridged"; +//! AGENTS.md convention 9: SSH servers are internet-facing; unbounded //! loops and unbounded buffers are bugs). //! //! ## Shape @@ -11,12 +11,12 @@ //! [`ChannelCap`] is a per-session count of active channels. Admission //! ([`ChannelCap::admit`]) is the check-and-increment the accept paths //! call: room under the cap admits (the count rises), otherwise the -//! open is refused — a clean decline, **never queued, never half-open** +//! open is refused: a clean decline, **never queued, never half-open** //! (the fail-closed posture; the refusal reason is //! [`crate::dispatch::cap_exceeded_open_decline`]). Release //! ([`ChannelCap::release`]) fires from the `channel_close` hook for -//! established channels — and, since `w3-tunnel-direct`, from a -//! spawned route-1 bridge task on a fabric-open failure — and, since +//! established channels, and, since `w3-tunnel-direct`, from a +//! spawned route-1 bridge task on a fabric-open failure, and, since //! `w3-tunnel-listen`, from the spawned `-R` arrival pumps on the //! never-established paths (client-rejected open, dead session): see //! the release-sites section. @@ -27,36 +27,36 @@ //! Every admission has exactly one release, and the paths are //! disjoint by the wire shape: //! -//! 1. **The established-channel close** — the `channel_close` hook. +//! 1. **The established-channel close**: the `channel_close` hook. //! russh routes `CHANNEL_CLOSE` only for channels it considers //! established; a declined open never established one, and a close //! is consumed at most once (russh removes the channel before the //! hook). -//! 2. **The admitted-but-rejected bridge** — the route-1 bridge's +//! 2. **The admitted-but-rejected bridge**: the route-1 bridge's //! failure path (`w3-tunnel-direct`). The open hook admits and //! holds the count across the fabric open; on fabric failure the //! open is rejected with the explicit `ConnectFailed` //! (ADR-006 decision 1: accept only after the fabric open //! succeeds), the channel never establishes, and *no -//! `channel_close` can ever fire* — so the count must be released +//! `channel_close` can ever fire*, so the count must be released //! from where the failure is known: inside the spawned bridge //! task, **before** the reject is answered (the very next open -//! then observes the recovered budget — pinned by wire test). A +//! then observes the recovered budget; pinned by wire test). A //! success never releases there (its close rides path 1). //! 3. **The `-R` arrival pumps** (`w3-tunnel-listen`): a fabric //! arrival is admitted into the owning route's count and opens the //! SSH `forwarded-tcpip`/`forwarded-streamlocal` channel toward -//! the vanilla client through the session handle. A rejected open — -//! the client's own refusal, or a dead session's send failure — +//! the vanilla client through the session handle. A rejected open +//! (the client's own refusal, or a dead session's send failure) //! never establishes the channel, so the count releases inside the //! arrival task exactly once (an established channel's release is //! path 1's). These are the mirror of site 2 on the server-initiated -//! open direction — the acceptor vocabulary's cap rows. +//! open direction, the acceptor vocabulary's cap rows. //! //! ## Why the mutex (the single-writer reasoning, updated twice) //! //! The wave-2 shape was a bare `usize` field written only by the -//! session's packet loop — sound because every hook runs inline on +//! session's packet loop, sound because every hook runs inline on //! that loop with exclusive `&mut self` access. The bridge release //! (`w3-tunnel-direct`) and the arrival admission (`w3-tunnel-listen`) //! both break the single-writer property: those tasks are alkcall @@ -66,12 +66,12 @@ //! critical sections are single integer ops (no await inside the //! lock), and all sites saturating. Channels never closed before //! session teardown stay counted until the handler dies with the -//! session — per-session state, gone with the connection. +//! session (per-session state, gone with the connection). use parking_lot::Mutex; /// The per-session active-channel count for the in-crate -/// concurrent-channel cap — see the module docs for the shape, the +/// concurrent-channel cap; see the module docs for the shape, the /// release sites, and the writer/soundness reasoning. Shared with the /// spawned route-1 bridge tasks ([`Arc`]) exactly so the /// fabric-failure release can fire from the task that knows it. @@ -82,13 +82,13 @@ pub(crate) struct ChannelCap { impl ChannelCap { /// The accept-path admission decision: room under `cap` increments - /// the count and admits; otherwise refuses (fail-closed — the + /// the count and admits; otherwise refuses (fail-closed: the /// caller answers the open with a clean decline). `cap == 0` /// refuses every open. Call sites: the packet loop's open hooks - /// `w2`-style, and — since `w3-tunnel-listen` — the `-R` arrival + /// `w2`-style, and, since `w3-tunnel-listen`, the `-R` arrival /// tasks (the door's forwarded-arrival admission: an arrival is /// admitted on the owning route's count inside the spawned - /// arrival pump — see the module doc's updated single-writer + /// arrival pump; see the module doc's updated single-writer /// reasoning). The mutex makes both sound. pub(crate) fn admit(&self, cap: usize) -> bool { let mut active = self.active.lock(); @@ -110,7 +110,7 @@ impl ChannelCap { *active = active.saturating_sub(1); } - /// The active count — in-crate inspection for the unit rows. + /// The active count, in-crate inspection for the unit rows. #[cfg(test)] pub(crate) fn active(&self) -> usize { *self.active.lock() @@ -136,7 +136,7 @@ mod tests { } /// - *Contract stamp:* the task's cap mechanics (a close recovers - /// the cap — the count decrements on close). + /// the cap; the count decrements on close). #[test] fn release_recovers_the_cap() { let cap = ChannelCap::default(); @@ -150,7 +150,7 @@ mod tests { } /// - *Contract stamp:* the fail-closed cap posture (`cap == 0` is - /// a valid, assembly-tunable refusal of every open — never a + /// a valid, assembly-tunable refusal of every open, never a /// bypass). #[test] fn zero_cap_refuses_every_open() { @@ -177,9 +177,9 @@ mod tests { /// - *Contract stamp:* `w3-tunnel-direct`'s recorded release /// mechanism (the admitted-but-rejected bridge releases inside - /// the spawned task): the cap is shared safely — admission from + /// the spawned task): the cap is shared safely (admission from /// the packet-loop site, release from anywhere that holds the - /// `Arc` — and disjoint releases never double-count. + /// `Arc`), and disjoint releases never double-count. #[test] fn the_cap_is_shareable_between_the_loop_and_bridge_tasks() { let cap = std::sync::Arc::new(ChannelCap::default()); diff --git a/src/client.rs b/src/client.rs index 9ca5622..051eda9 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,4 +1,4 @@ -//! The dial surface (`w4-dial`) — the door *outward* (`client.md` +//! The dial surface (`w4-dial`), the door *outward* (`client.md` //! §The dial surface), the client-direction mirror of //! [`crate::adapter`]'s mount: the russh client stack every wave-4 op //! row composes into. @@ -7,7 +7,7 @@ //! whole authenticated-dial sequence, **fail-closed at every step**: //! //! 1. **The decrypt-at-dial key load** (ADR-005 decision 2): the -//! injected [`KeySource::load`] runs *here and nowhere else* — +//! injected [`KeySource::load`] runs *here and nowhere else*: //! locked / absent / decryption / unknown-version / decode are all //! **no-dial outcomes** ([`DialError::KeySource`], the variant //! preserved). The decoded key lives for this dial; the vault is @@ -15,18 +15,18 @@ //! established connections streaming, POC-2 §2). //! 2. **The bounded russh client `Config`** ([`russh_client_config`]) //! from the [`Limits`]: the keepalive 15 s / 3 posture -//! (`reverse-runner.md` lesson 3 — OpenSSH +//! (`reverse-runner.md` lesson 3, OpenSSH //! `ServerAliveInterval=15`/`CountMax=3` parity), the wall clock -//! **always `Some`** (`inactivity_timeout` — the crate never +//! **always `Some`** (`inactivity_timeout`, the crate never //! constructs a session with no clock), and the window/packet/ //! channel-buffer knobs verbatim. Everything else stays russh's //! own default posture (the ADR-002 surface notes, mirrored from //! [`crate::adapter`]'s server mapping: rekey `Limits` -//! russh-enforced, preferred algorithms russh's — the ed25519-only +//! russh-enforced, preferred algorithms russh's; the ed25519-only //! posture holds by the loaded key set itself). No client-side //! auth-attempt knob exists at this pin and none is needed: the //! family contract is exactly **one publickey attempt**. -//! 3. **The policy call at `check_server_key`** (OQ-05) — the +//! 3. **The policy call at `check_server_key`** (OQ-05), the //! wave-1 [`HostKeyPolicy`](crate::HostKeyPolicy) seam consumed by //! the handler ([`crate::client_handler`]): the crate default //! [`RejectAll`](crate::RejectAll) connects to nothing; a @@ -34,23 +34,23 @@ //! Declines surface as [`DialError::HostKeyRejected`]. //! 4. **Publickey-only authentication** (the family contract): //! exactly one `authenticate_publickey` attempt from the loaded -//! key — no password, no keyboard-interactive, no cert, no retry, +//! key (no password, no keyboard-interactive, no cert, no retry, //! no fallback method (russh's handle methods for those are never -//! exposed through [`SshConnection`]); a refusal is +//! exposed through [`SshConnection`])); a refusal is //! [`DialError::AuthRejected`] and the attempt is closed cleanly. //! //! **The connection handle** ([`SshConnection`]) is the type //! everything else in the wave rides (the op rows open channels on -//! it; the `-R` leg installs the acceptor registry over it) — the +//! it; the `-R` leg installs the acceptor registry over it), the //! russh `client::Handle` wrapped with the crate's surface, the //! policy, limits and endpoint labels carried. The connection handle's //! clean-close path is [`SshConnection::close`]; the listener handles' //! surface is [`crate::client_accept`]'s. //! -//! ## Lifecycle posture (`w4-lifecycle` — the OQ-12 resolution in code) +//! ## Lifecycle posture (`w4-lifecycle`, the OQ-12 resolution in code) //! //! The handle surface is **primitives, not policy** (reverse-runner -//! fact 4): reconnect-and-restore (rebinding persisted tunnel ports — +//! fact 4): reconnect-and-restore (rebinding persisted tunnel ports, //! the alkminer flow) is *assembly* composition over these //! primitives; the crate provides bound ports, handles, cancellation, //! clean close, and never owns a reconnect/restore policy. Two @@ -58,18 +58,18 @@ //! //! - **Drop is never the clean path.** At this russh pin dropping the //! last wire-stack handle ends the runner and the transport goes -//! down **abruptly** — the peer observes a broken session (its +//! down **abruptly**: the peer observes a broken session (its //! serving outcome is an error wire class), never the clean //! disconnect message. So the surface never relies on drop timing //! for clean state: only [`SshConnection::close`] sends -//! `Disconnect::ByApplication` — the peer observes a clean +//! `Disconnect::ByApplication`, the peer observes a clean //! disconnect, no half-open channels (row-pinned through the //! server double, both directions of the boundary: abrupt-on-drop, //! clean-on-close). -//! And a cancellation is async — it cannot hide inside a sync +//! And a cancellation is async; it cannot hide inside a sync //! `Drop` hook, so no handle hides a `Drop` side effect: the //! listener handles' drop frees *nothing* on their wire state. -//! - **Every listener/handle is explicitly cancellable** — the `-R` +//! - **Every listener/handle is explicitly cancellable**: the `-R` //! listens return the [`ReverseListener`](crate::client_accept:: //! ReverseListener) handles (the actually-bound endpoint carried; //! `cancel()` the wire-honest teardown), the connection handle @@ -84,7 +84,7 @@ //! [`russh_client_config`] (the bounded-knob mapping, asserted //! verbatim) and [`ClientHandler`](crate::client_handler::ClientHandler) //! (the handler skeleton; `client_handler.rs`). The wire vehicle is -//! the in-process fake `sshd` in `tests/common/sshd_double.rs` — the +//! the in-process fake `sshd` in `tests/common/sshd_double.rs`: the //! client direction dials vanilla servers, so the loopback harness //! (the *server*-direction vehicle) only hosts the crate-to-crate //! smoke (see the task's smoke-posture record). @@ -102,7 +102,7 @@ use crate::client_handler::ClientHandler; use crate::config::{DialConfig, Limits}; use crate::error::DialError; -/// The authenticated dial — the client direction's entry point +/// The authenticated dial, the client direction's entry point /// (`client.md` §The dial surface): see the module docs for the /// four-step sequence and their fail-closed outcomes. pub async fn dial(config: DialConfig) -> Result { @@ -149,7 +149,7 @@ pub async fn dial(config: DialConfig) -> Result { }) } -/// Parses the dial address into its endpoint labels — the +/// Parses the dial address into its endpoint labels, the /// [`PresentedHostKey`](crate::host_key::PresentedHostKey)'s /// `host`/`port` decision context. Malformed targets refuse before /// any connection ([`DialError::Address`]): plain `host:port` and the @@ -177,7 +177,7 @@ fn parse_dial_address(address: &str) -> Result<(String, u16), DialError> { Ok((host.to_string(), port)) } -/// The [`Limits`] → russh client `Config` mapping — the bounded knobs +/// The [`Limits`] → russh client `Config` mapping: the bounded knobs /// verbatim, the wall clock always on, everything else at russh's own /// default posture (see the module docs). The mapping is the dial /// task's `bounded-config wiring observable`; @@ -199,15 +199,15 @@ pub fn russh_client_config(limits: &Limits) -> russh::client::Config { build_client_config(limits) } -/// The authenticated connection handle — the type every later +/// The authenticated connection handle, the type every later /// wave-4 op rides (`client.md`: "the authenticated connection /// handle"): the russh `client::Handle` wrapped with the crate's /// surface. The remote end is authenticated (publickey-only, single -/// attempt); the dial key is gone (its lifetime is the dial's — +/// attempt); the dial key is gone (its lifetime is the dial's; /// everything after rides the wire, never the key). /// /// The russh handle, budgets and registry ride one shared inner -/// (behind the `Arc`) — the sharing the `client_accept` module's +/// (behind the `Arc`), the sharing the `client_accept` module's /// listener handles need for their independent `cancel()` calls; the /// wire-visible teardowns stay explicit calls on top of that shared /// stack (the module docs' §Lifecycle posture: drop is never a @@ -216,13 +216,13 @@ pub struct SshConnection { shared: Arc, } -/// The connection handle's internals — the one behind the +/// The connection handle's internals, the one behind the /// [`SshConnection`]'s `Arc`, every field private to the crate: the /// wire surface is the wrapped methods, never the russh stack itself /// (`serve.rs`'s wrapped-surface pattern mirrored client-side). /// /// The arc's meaning for the lifecycle boundary: the russh stack -/// (the runner) lives while *any* handle holds the arc — the +/// (the runner) lives while *any* handle holds the arc; the /// connection handle's drop is the abrupt teardown only when it is /// the last holder (row-pinned), and a live `ReverseListener` (its /// `cancel()` composes on this stack) keeps the wire serving until @@ -231,18 +231,18 @@ pub struct SshConnection { pub(crate) struct ConnectionShared { /// The russh handle the connection and the listener handles /// compose into (its own request methods take `&self` at this - /// pin — the shared arc is the concurrent-sharing shape). + /// pin, the shared arc is the concurrent-sharing shape). pub(crate) handle: russh::client::Handle, pub(crate) limits: Limits, pub(crate) address: String, pub(crate) username: String, /// The `-R` leg's acceptor registry (the dial constructs it empty; - /// the assembly installs/uninstalls across the live connection — + /// the assembly installs/uninstalls across the live connection; /// see [`SshConnection::acceptors`] and /// [`crate::client_accept`]`'s recorded decisions. #[cfg(feature = "tunnel")] pub(crate) acceptors: Arc, - /// The reverse-listen count's dedicated bound — admitted at the + /// The reverse-listen count's dedicated bound, admitted at the /// listen rows, released at the confirmed cancels and the refused/ /// wire-error paths (the cap relation recorded in /// [`crate::client_accept`]; [`crate::channel_cap`]'s mutex makes @@ -271,7 +271,7 @@ impl SshConnection { /// The `-R` leg's acceptor registry (the /// `w4-reverse-listen` surface, `client_accept`'s module docs - /// carry the recorded decisions) — install/uninstall the + /// carry the recorded decisions); install/uninstall the /// per-type acceptors across the live connection (the /// late-install dynamic). The dial constructs it empty: nothing /// server-initiated is served until a slot holds, fail-closed at @@ -281,14 +281,14 @@ impl SshConnection { &self.shared.acceptors } - /// The reverse-listen count's shared handle — the op rows - /// ([`crate::client_accept`]) read it; private to the crate. + /// The reverse-listen count's shared handle, which the op rows + /// ([`crate::client_accept`]) read; private to the crate. #[cfg(feature = "tunnel")] pub(crate) fn listener_budget(&self) -> &ChannelCap { &self.shared.listener_budget } - /// The shared inner — the listener handles' compose-into point + /// The shared inner, the listener handles' compose-into point /// (their cancels run against the same russh stack); private to /// the crate. #[cfg(feature = "tunnel")] @@ -296,7 +296,7 @@ impl SshConnection { &self.shared } - /// The russh handle the op rows compose into (`w4-op-rows` — the + /// The russh handle the op rows compose into (`w4-op-rows`; the /// method bodies live in [`crate::client_ops`], a sibling module, /// so the field stays private to this module). #[cfg(any(feature = "session", feature = "git", feature = "tunnel"))] @@ -306,7 +306,7 @@ impl SshConnection { &self.shared.handle } - /// The dial's bounded-resource budget, verbatim — the op rows + /// The dial's bounded-resource budget, verbatim; the op rows /// read the knobs they consume (the exec-command length cap /// drives the command-carrying rows' client-mirror gate). #[cfg(any(feature = "session", feature = "git"))] @@ -320,12 +320,12 @@ impl SshConnection { } /// The explicit clean-close path (the lifecycle primitive, - /// [`russh::Disconnect::ByApplication`] — the honest close): the - /// peer observes a clean disconnect, no half-open channels — + /// [`russh::Disconnect::ByApplication`], the honest close): the + /// peer observes a clean disconnect, no half-open channels; /// every open channel is torn down with the session (row-pinned /// through the server double). **Drop is not this path** (the /// module docs' §Lifecycle posture): a dropped handle releases - /// nothing on the wire — the connection outlives the handle + /// nothing on the wire; the connection outlives the handle /// until the peer or the wall clock ends it. pub async fn close(self) { let _ = self @@ -373,7 +373,7 @@ mod tests { } /// - *Contract stamp:* `client.md` §Correctness facts (the - /// keepalive posture) + `overview.md` §Bounded-resources table — + /// keepalive posture) + `overview.md` §Bounded-resources table; /// the defaults land in the russh mapping verbatim. #[test] fn bounded_config_mapping_carries_the_default_postures() { @@ -385,7 +385,7 @@ mod tests { assert_eq!( config.inactivity_timeout, Some(crate::config::DEFAULT_INACTIVITY_TIMEOUT), - "the wall clock is always set — no unbounded session" + "the wall clock is always set, never an unbounded session" ); assert_eq!( config.keepalive_interval, diff --git a/src/client_accept.rs b/src/client_accept.rs index 563a393..aac5168 100644 --- a/src/client_accept.rs +++ b/src/client_accept.rs @@ -1,28 +1,28 @@ -//! The `-R` leg's client half (`w4-reverse-listen` — `client.md` +//! The `-R` leg's client half (`w4-reverse-listen`, `client.md` //! §op rows row 4 + §The acceptor): the hub's reverse direction in //! family types. Two surfaces, the acceptor registry first: //! -//! 1. **The forward request rows** — [`SshConnection::reverse_listen`] +//! 1. **The forward request rows**: [`SshConnection::reverse_listen`] //! / [`SshConnection::reverse_listen_cancel`] / the unix pair //! (`reverse_listen_unix` / `reverse_listen_unix_cancel`): the //! vanilla-server listen requests, the lifecycle primitives //! (`client.md` §Lifecycle). The listens return the -//! **[`ReverseListener`] handles** (`w4-lifecycle` — the handles' +//! **[`ReverseListener`] handles** (`w4-lifecycle`, the handles' //! surface: the actually-bound endpoint carried, the explicit //! `cancel()`); the stateless wire cancel forms ride beside them //! (sshd's global-request cancels mirrored 1:1). -//! 2. **The acceptor registry** ([`AcceptorRegistry`]) — the +//! 2. **The acceptor registry** ([`AcceptorRegistry`]): the //! assembly-mutable, per-channel-type registry the dial surface's //! russh handler routes **server-initiated `forwarded-*` opens** //! through. Served only under a registered acceptor for that type //! and under the `tunnel` feature; unregistered/unfeatured accepted -//! opens **decline cleanly** — never russh's accept-and-drop +//! opens **decline cleanly**, never russh's accept-and-drop //! default (ADR-003 §4, the client-side fail-closed acceptor; the //! reverse-runner fact 1 disposition is ours). //! //! ## The recorded decisions (the task's decide + record items) //! -//! - **Registry shape: per-type fixed slots, not a typed map** — the +//! - **Registry shape: per-type fixed slots, not a typed map**: the //! client direction's registry-servable type set is closed and tiny //! (exactly the `-R` data leg's two: `forwarded-tcpip` / //! `forwarded-streamlocal`, both under `tunnel`); one trait per type @@ -35,70 +35,70 @@ //! `ForwardedAcceptor` vocabulary is grown, not forked: the payload //! fields are the same shapes (the open's originator fields + the //! channel duplex), the duplex now family-typed -//! ([`TunnelChannel`] — the `-L` rows' byte +//! ([`TunnelChannel`], the `-L` rows' byte //! duplex, one type both legs ride). //! - **Install is refuse-never-replace** ([`AcceptorRegistry:: //! install_tcpip`]'s held-slot error): the same posture recorded -//! server-side on the `ListenRouter` at `w4-router-collision` — +//! server-side on the `ListenRouter` at `w4-router-collision`: //! a same-slot second install is an assembly program error, declined //! never a quiet displacement of a live acceptor. Uninstall is //! explicit, 1:1 with the install. //! - **Late-install across a live connection** (the alkminer -//! `install_forward_sink` dynamic — reverse-runner fact 2): the +//! `install_forward_sink` dynamic, reverse-runner fact 2): the //! registry rides the connected [`SshConnection`] -//! ([`SshConnection::acceptors`]) — the dial constructs it empty, +//! ([`SshConnection::acceptors`]): the dial constructs it empty, //! the assembly installs/uninstalls whenever it decides. The open //! hooks read the slot **at arrival time**, fail-closed: an open //! arriving before its acceptor installs (or after an uninstall) -//! is **declined at arrival, never buffered** — no unclaimed-open +//! is **declined at arrival, never buffered**; no unclaimed-open //! queue exists anywhere in this module's posture (an unclaimed //! open's bytes would have to be buffered unboundedly to accept- //! then-route; the decline is the clean, bounded answer). -//! - **The listen rows gate on the registered acceptor** — the +//! - **The listen rows gate on the registered acceptor**, the //! *issuing*-side disposition: a listen whose data leg cannot serve //! is a half-capability (the peer stays bound, every arrival //! declines), so a `reverse_listen` with no registered acceptor for //! the type answers //! [`OpError::NoAcceptor`](crate::OpError) **before any wire op** //! (install-first is the recorded order; the rows never buffer an -//! outstanding listen against a later install — re-issuing is the +//! outstanding listen against a later install; re-issuing is the //! assembly's retry, the listen rows are stateless global requests). -//! - **Bounded bookkeeping (AGENTS.md convention 9) — the cap +//! - **Bounded bookkeeping (AGENTS.md convention 9): the cap //! relation** (the server-side listener-counter posture as the //! template): the registry is bounded by construction (two fixed //! slots). The per-connection **listener count** is a dedicated //! in-crate counter admitting at the listen rows and releasing at -//! the confirmed cancels and the failed/wire-error paths — bounded +//! the confirmed cancels and the failed/wire-error paths, bounded //! against the *same* `Limits::max_concurrent_channels` ceiling the //! server direction's listener counter uses (independent counts, one -//! ceiling — never a map: the outstanding listens live at the peer; +//! ceiling, never a map: the outstanding listens live at the peer; //! the counter exists so a dial cannot mint an unbounded listener //! set the registry would have to serve). The per-connection //! **accepted-open handoff count** is the second dedicated counter //! against the same ceiling (admitted in the dial handler's open //! hook, accepted-with-the-count-held, released when the handoff -//! task ends — the acceptor's `accept` completing *or the task +//! task ends: the acceptor's `accept` completing *or the task //! unwinding* ([`HandoffCapGuard`]: a panicking assembly acceptor -//! can never strand a held slot) — no accepted-open ledger anywhere +//! can never strand a held slot); no accepted-open ledger anywhere //! else: the pump is the acceptor's from the handoff on, the //! channel's transport bounds are russh's windows, and the slot read //! is the arrival admission). -//! - **The listener handles (`w4-lifecycle` — the handles' +//! - **The listener handles (`w4-lifecycle`, the handles' //! surface)**: the listen rows return **[`ReverseListener`]** -//! handles — the endpoint (the actually-bound values, the cancel +//! handles: the endpoint (the actually-bound values, the cancel //! match keys) carried, the explicit `cancel()` the wire-honest //! teardown. Decisions recorded: -//! (a) **no `Drop` hides a wire op** — a cancellation is async and +//! (a) **no `Drop` hides a wire op**: a cancellation is async and //! cannot run in a sync `Drop`, so no `Drop` hook exists: the //! listen **outlives a dropped handle until an explicit cancel or -//! the connection's end** (no drop-timing-only wire state — +//! the connection's end** (no drop-timing-only wire state, //! row-pinned); //! (b) the handle **shares the connection's inner stack** (the -//! `SshConnection`'s `Arc`-held internals — the russh request +//! `SshConnection`'s `Arc`-held internals; the russh request //! methods take `&self` at this pin), so the handle's cancel is the //! same wire op the stateless forms issue; //! (c) the **stateless cancel forms ride beside** the handles -//! (sshd's global-request cancels are stateless — a cancel by the +//! (sshd's global-request cancels are stateless: a cancel by the //! raw strings works from anywhere); every form releases the //! listener count exactly once on a confirmed cancel (the wire //! state machine governs: the second cancel is the unknown-listener @@ -107,37 +107,37 @@ //! *listen* rows (`reverse_listen_unix` / `reverse_listen_unix_cancel`) //! compile everywhere and //! decline off-Unix before any wire op (the bind is the -//! platform-bound operation — the door puts nothing on the wire it +//! platform-bound operation; the door puts nothing on the wire it //! cannot track). The `forwarded-streamlocal` *open* hook is -//! universal: ingestion is platform-neutral byte pumping — the +//! universal: ingestion is platform-neutral byte pumping; the //! unix-socket leg's socket is the peer-side's. -//! - **`OpError::ListenRefused`** — the peer's `RequestDenied` on +//! - **`OpError::ListenRefused`**: the peer's `RequestDenied` on //! every form's decline (a denied listen, a cancel of an unknown -//! listener) — channel-scoped honesty: the connection stays usable +//! listener), channel-scoped honesty: the connection stays usable //! (the `From` mapping's recorded producer, `error.rs`). //! //! ## The data leg //! //! Per accepted open: the hook accepts the channel and hands the -//! assembly the open — the [`TunnelChannel`] +//! assembly the open, the [`TunnelChannel`] //! duplex + the open's echo/originator fields (the payload types -//! below) — on a spawned task (the spawn-and-return rule's client +//! below), on a spawned task (the spawn-and-return rule's client //! mirror: the hook runs in the packet loop and returns fast). The -//! pump is the acceptor's from the handoff — the family handler shape +//! pump is the acceptor's from the handoff, the family handler shape //! (alktunnels' `ForwardedHandler` recipe, POC-3 §C.4); dropping the //! duplex is wire-clean (russh closes the channel). //! //! ## Test surface //! //! The wire vehicle is the fake `sshd` double grown with the -//! server-initiated-forward surfaces (`tests/common/sshd_double.rs`) — +//! server-initiated-forward surfaces (`tests/common/sshd_double.rs`); //! the double binds **real** sockets for its script accepts, opens the //! forwarded channels toward the client per accepted connection, and //! pumps them (a real `ssh -R`-shaped round trip in-process, the task's //! recorded smoke posture). The full-circle alkssh-client ↔ //! alkssh-server-direction smoke (both `-R` legs through the alkcall //! fabric, the composition the assembly makes) rides the fabric -//! doubles in `tests/tunnel_mapping.rs` — the same doubles the +//! doubles in `tests/tunnel_mapping.rs`, the same doubles the //! server-side `-R` rows use; real-`sshd` `-R` is wave-5 e2e //! territory, never silently dropped. //! @@ -163,24 +163,24 @@ use crate::client::SshConnection; use crate::error::OpError; use crate::observe; -/// An accepted server-initiated `forwarded-tcpip` open — the acceptor +/// An accepted server-initiated `forwarded-tcpip` open: the acceptor /// registry's payload for the /// [`TcpipForwardedAcceptor::accept`] call: the open's echo fields -/// (the listen endpoint the arrival belongs to — the assembly's +/// (the listen endpoint the arrival belongs to, the assembly's /// routing key; the OpenSSH matcher parity verbatim) + the originator /// (the arrival's peer, as the wire carried it) + the channel duplex. pub struct ForwardedTcpip { - /// The connected address the open echoed — the `reverse_listen` + /// The connected address the open echoed, the `reverse_listen` /// wire string (sshd parity). pub connected_address: String, - /// The actually-bound port of the minted listener — for a + /// The actually-bound port of the minted listener; for a /// `port = 0` mint this is the server-picked number, never `0`. pub connected_port: u32, /// The arrival's peer address (the wire originator). pub originator_address: String, /// The arrival's peer port (the wire originator). pub originator_port: u32, - /// The accepted channel's byte duplex — the acceptor owns the + /// The accepted channel's byte duplex; the acceptor owns the /// pump from the handoff on (dropping it is wire-clean). pub stream: TunnelChannel, } @@ -196,14 +196,14 @@ impl std::fmt::Debug for ForwardedTcpip { } } -/// An accepted server-initiated `forwarded-streamlocal` open — the +/// An accepted server-initiated `forwarded-streamlocal` open: the /// streamlocal acceptor's payload (the echoed socket path + the /// channel duplex). pub struct ForwardedStreamlocal { - /// The socket path the open echoed — the `reverse_listen_unix` + /// The socket path the open echoed, the `reverse_listen_unix` /// wire string (sshd parity). pub socket_path: String, - /// The accepted channel's byte duplex — the acceptor owns the + /// The accepted channel's byte duplex; the acceptor owns the /// pump from the handoff on (dropping it is wire-clean). pub stream: TunnelChannel, } @@ -216,34 +216,34 @@ impl std::fmt::Debug for ForwardedStreamlocal { } } -/// The `forwarded-tcpip` acceptor — the registry's per-type slot +/// The `forwarded-tcpip` acceptor: the registry's per-type slot /// trait. `accept` runs on the spawned handoff task (never the /// packet loop): the assembly's pump/home of the open lives inside /// it; the crate releases its handoff counter when the handoff task -/// ends — the call returning *or the task unwinding* -/// (`HandoffCapGuard`) — so the family shape (hand off to a queue, +/// ends (the call returning *or the task unwinding* +/// `HandoffCapGuard`), so the family shape (hand off to a queue, /// return) keeps the counter's meaning "open accepted, handoff in /// flight". #[async_trait] pub trait TcpipForwardedAcceptor: Send + Sync { /// Serves one accepted open. Never invoked for an unregistered /// type (the registry gate is first); the open is already accepted - /// on the wire — refusing one from here is a *data-plane* choice + /// on the wire; refusing one from here is a *data-plane* choice /// (drop the duplex; the channel closes on it), never a wire /// open-decline. async fn accept(&self, open: ForwardedTcpip); } -/// The `forwarded-streamlocal` acceptor — the unix slot's trait +/// The `forwarded-streamlocal` acceptor: the unix slot's trait /// (see [`TcpipForwardedAcceptor`] for the call-shape contract). #[async_trait] pub trait StreamlocalForwardedAcceptor: Send + Sync { - /// Serves one accepted open (platform-neutral pumping — see the + /// Serves one accepted open (platform-neutral pumping; see the /// module docs' unix-gate record). async fn accept(&self, open: ForwardedStreamlocal); } -/// The held-slot refusal (`AcceptorRegistry::install_*`) — the +/// The held-slot refusal (`AcceptorRegistry::install_*`): the /// refuse-never-replace posture (the server-side `ListenRouter`'s /// recorded sibling): the slot already holds a live acceptor; a second /// install is the assembly's program error, declined, never a quiet @@ -252,7 +252,7 @@ pub trait StreamlocalForwardedAcceptor: Send + Sync { #[error("an acceptor is already registered for this channel type")] pub struct AcceptorHeld; -/// The assembly-mutable, per-channel-type acceptor registry — the +/// The assembly-mutable, per-channel-type acceptor registry: the /// `-R` data leg's fail-closed gate (see the module docs for the /// recorded decisions). Constructed empty at the dial /// ([`SshConnection::acceptors`], the live-connection accessor); @@ -263,7 +263,7 @@ pub struct AcceptorRegistry { } impl AcceptorRegistry { - /// The empty registry — the dial's construct (nothing is served + /// The empty registry, the dial's construct (nothing is served /// until an acceptor installs; ADR-003 §4's fail-closed default). pub fn new() -> Self { Self { @@ -273,7 +273,7 @@ impl AcceptorRegistry { } /// Installs the `forwarded-tcpip` acceptor. Refuse-never-replace: - /// a held slot declines ([`AcceptorHeld`]) — uninstall first if a + /// a held slot declines ([`AcceptorHeld`]); uninstall first if a /// replacement is meant (the late-install toggle's other half). pub fn install_tcpip( &self, @@ -287,7 +287,7 @@ impl AcceptorRegistry { Ok(()) } - /// Uninstalls the `forwarded-tcpip` acceptor — `true` when one was + /// Uninstalls the `forwarded-tcpip` acceptor: `true` when one was /// held (the toggle's honest report). In-flight opens already /// accepted keep pumping (their handoff happened); arrivals after /// this decline at arrival time (fail-closed, no buffering). @@ -315,7 +315,7 @@ impl AcceptorRegistry { self.streamlocal.lock().take().is_some() } - /// The arrival-time slot reads (the open hooks' gates) — cloned + /// The arrival-time slot reads (the open hooks' gates), cloned /// out so the spawned handoff task owns its acceptor handle. pub(crate) fn tcpip_acceptor(&self) -> Option> { self.tcpip.lock().clone() @@ -345,7 +345,7 @@ impl std::fmt::Debug for AcceptorRegistry { // The server-initiated opens' handoff (the dial handler's routed paths) // --------------------------------------------------------------------------- -/// The handoff counter's panic-safe release — the accepted open's count +/// The handoff counter's panic-safe release: the accepted open's count /// releases exactly at the handoff task's end, on *completion or /// unwind*: a panicking assembly acceptor (or any panic in the handoff /// body) can never strand a held slot past the task. Saturating under @@ -358,14 +358,14 @@ impl Drop for HandoffCapGuard { } } -/// The accepted `forwarded-tcpip` open's handoff task — the +/// The accepted `forwarded-tcpip` open's handoff task: the /// spawn-and-return rule's client mirror (ADR-006 decision 4; the /// hook runs in the packet loop and returns fast): accepts the open on /// the wire, converts the channel to the family duplex, delivers the /// payload to the assembly's acceptor, and releases the handoff -/// counter when the handoff task ends — the acceptor's `accept` +/// counter when the handoff task ends: the acceptor's `accept` /// completing *or the task unwinding* ([`HandoffCapGuard`]; the -/// recorded release site — the count's meaning is "accepted, handoff +/// recorded release site; the count's meaning is "accepted, handoff /// in flight"). #[cfg_attr(feature = "tunnel", allow(clippy::too_many_arguments))] pub(crate) async fn handoff_forwarded_tcpip( @@ -396,7 +396,7 @@ pub(crate) async fn handoff_forwarded_tcpip( observe::serving_path_ended("forwarded-tcpip", channel_number, None); } -/// The accepted `forwarded-streamlocal` open's handoff task — the +/// The accepted `forwarded-streamlocal` open's handoff task: the /// unix slot's mirror of [`handoff_forwarded_tcpip`]. pub(crate) async fn handoff_forwarded_streamlocal( acceptor: Arc, @@ -421,10 +421,10 @@ pub(crate) async fn handoff_forwarded_streamlocal( } // --------------------------------------------------------------------------- -// The listener handles (w4-lifecycle — the handles' surface) +// The listener handles (w4-lifecycle, the handles' surface) // --------------------------------------------------------------------------- -/// The endpoint a reverse listener is bound to — what a +/// The endpoint a reverse listener is bound to: what a /// [`ReverseListener`] carries for its assembly-side use (the /// alkminer restore flow: the *actually bound* values to persist and /// rebind) and the cancel forms' raw wire match key (sshd parity: a @@ -439,8 +439,8 @@ pub enum ReverseEndpoint { } impl ReverseEndpoint { - /// The actually-bound port — the tcp shape's; `None` for the unix - /// shape (no port semantics — the cancel matches by the path). + /// The actually-bound port, the tcp shape's; `None` for the unix + /// shape (no port semantics; the cancel matches by the path). pub fn bound_port(&self) -> Option { match self { Self::Tcp { port, .. } => Some(*port), @@ -449,14 +449,14 @@ impl ReverseEndpoint { } } -/// A returned forward listener — the `-R` leg's **listener handle** +/// A returned forward listener: the `-R` leg's **listener handle** /// (the lifecycle primitive: every listener explicitly cancellable): /// the bound endpoint carried (see [`ReverseEndpoint`]; the -/// assembly's own record for a restore/rebind policy — the crate +/// assembly's own record for a restore/rebind policy; the crate /// ships none, OQ-12), and the explicit `cancel()`. /// /// **Drop frees nothing on the wire** (the recorded decision in this -/// module's docs): there is no `Drop` hook — a dropped handle leaves +/// module's docs): there is no `Drop` hook, so a dropped handle leaves /// the peer's listen serving until an explicit `cancel()` or the /// connection's end removes it. The handle does not borrow the /// connection: the cancel composes on the shared wire stack (the @@ -469,18 +469,18 @@ pub struct ReverseListener { } impl ReverseListener { - /// The bound endpoint — the actually-bound address/port or socket + /// The bound endpoint, the actually-bound address/port or socket /// path (never the requested `0` for a mint: the peer's answer is /// the surfaced number). pub fn endpoint(&self) -> &ReverseEndpoint { &self.endpoint } - /// The explicit cancellation — the wire teardown: the peer + /// The explicit cancellation, the wire teardown: the peer /// removes the matching listen (the endpoint's raw wire strings, /// sshd parity; the accept loop ends, the bound port frees) and /// the confirmed cancel releases the connection's listener count. - /// The peer's refusal (an unknown listener — e.g. the already- + /// The peer's refusal (an unknown listener, e.g. the already- /// cancelled, or a cancelled by the connection's end itself) is /// [`OpError::ListenRefused`](crate::OpError). The handle is /// consumed (one cancel through it); a later cancel by the same @@ -511,10 +511,10 @@ impl std::fmt::Debug for ReverseListener { } } -/// The tcp cancel's shared path — the stateless wire form and the +/// The tcp cancel's shared path: the stateless wire form and the /// listener handle's `cancel` compose into it: the wire op, then the /// confirmed release (exactly once: a second cancel hits the wire's -/// unknown-listener refusal, no release — budget-safe by the wire's +/// unknown-listener refusal, no release; budget-safe by the wire's /// own state machine). async fn cancel_reverse_tcp( shared: &crate::client::ConnectionShared, @@ -531,7 +531,7 @@ async fn cancel_reverse_tcp( } /// The unix cancel's shared path (the twin; the runtime-Unix gate -/// answers before the wire — see the module docs' gate record). +/// answers before the wire; see the module docs' gate record). #[cfg(unix)] async fn cancel_reverse_unix( shared: &crate::client::ConnectionShared, @@ -552,28 +552,28 @@ async fn cancel_reverse_unix( impl SshConnection { /// The reverse-listen row (`-R`): asks the vanilla server to listen - /// on (address, port) and returns the **actually-bound port** — + /// on (address, port) and returns the **actually-bound port**; /// for `port = 0` this is the peer-picked number (`client.md` /// §Lifecycle: the bound-port primitive, the port-0 mint); for an /// explicit port the wire's success reply carries no number (russh/ - /// sshd parity — the reply's data only exists for mints) and the + /// sshd parity; the reply's data only exists for mints) and the /// bound port *is* the requested one, which the row surfaces. /// /// Gates, both **before any wire op**: the `forwarded-tcpip` /// acceptor must be registered - /// ([`OpError::NoAcceptor`](crate::OpError) — a listen whose data + /// ([`OpError::NoAcceptor`](crate::OpError), a listen whose data /// leg cannot serve is a half-capability) and the connection's /// listener count must have room - /// ([`OpError::ListenCapExceeded`](crate::OpError) — the + /// ([`OpError::ListenCapExceeded`](crate::OpError), the /// dedicated counter sharing /// [`Limits::max_concurrent_channels`](crate::Limits); see the /// module docs' cap relation). The peer's refusal is /// [`OpError::ListenRefused`](crate::OpError) (the wire's /// `RequestDenied`) and releases the count; the connection stays /// usable after every refusal class. The listener is explicitly - /// cancellable — the returned [`ReverseListener`] handle's + /// cancellable, via the returned [`ReverseListener`] handle's /// `cancel()` (the wire-honest teardown; a cancel is never - /// triggered by a drop — the module docs' recorded decision). + /// triggered by a drop; the module docs' recorded decision). pub async fn reverse_listen( &self, address: impl Into, @@ -608,10 +608,10 @@ impl SshConnection { /// The reverse-listen cancel row (`-R` teardown): the explicit /// cancellation of one bound listener by the raw wire strings - /// (sshd parity) — the **stateless** wire form beside the + /// (sshd parity), the **stateless** wire form beside the /// [`ReverseListener`] handles' `cancel()` (compose into the same - /// shared path; a confirmed cancel releases the listener count — - /// never twice, the wire's unknown-listener refusal governs the + /// shared path; a confirmed cancel releases the listener count + /// (never twice; the wire's unknown-listener refusal governs the /// repeats). The peer's refusal (unknown listener) is /// [`OpError::ListenRefused`](crate::OpError). pub async fn reverse_listen_cancel( @@ -630,7 +630,7 @@ impl SshConnection { /// [`SshConnection::reverse_listen`] for the /// `forwarded-streamlocal` slot, plus the **runtime-Unix gate** /// (OQ-11: off-Unix, [`OpError::UnixUnavailable`](crate::OpError) - /// before any wire op — the bind is the platform-bound operation; + /// before any wire op; the bind is the platform-bound operation, /// the channel ingestion is platform-neutral). #[cfg_attr(not(unix), allow(unused_variables))] pub async fn reverse_listen_unix( @@ -667,7 +667,7 @@ impl SshConnection { } /// The streamlocal cancel row (matches by the socket path, sshd - /// parity — see [`SshConnection::reverse_listen_cancel`]; composes + /// parity, see [`SshConnection::reverse_listen_cancel`]; composes /// into the same shared path as the unix handles' `cancel()`). #[cfg_attr(not(unix), allow(unused_variables))] pub async fn reverse_listen_unix_cancel( @@ -708,7 +708,7 @@ mod tests { async fn accept(&self, _open: ForwardedStreamlocal) {} } - /// - *Contract stamp:* the recorded refuse-never-replace posture — + /// - *Contract stamp:* the recorded refuse-never-replace posture: /// a held slot declines the second install (never a quiet /// displacement of a live acceptor); uninstall frees it. #[test] @@ -736,7 +736,7 @@ mod tests { } /// - *Contract stamp:* the two slots are independent (the - /// per-type-registry decision) — the empty streamlocal slot + /// per-type-registry decision); the empty streamlocal slot /// stays unfeatured while the tcpip slot serves. #[test] fn the_slots_are_independent() { @@ -789,7 +789,7 @@ mod tests { } /// - *Contract stamp:* the handoff counter's panic-safe release - /// (the bounded-bookkeeping cap relation) — the + /// (the bounded-bookkeeping cap relation); the /// [`HandoffCapGuard`] releases on unwind, so a panicking /// assembly acceptor can never strand a held slot past the /// handoff task. diff --git a/src/client_handler.rs b/src/client_handler.rs index f6fc959..1093eea 100644 --- a/src/client_handler.rs +++ b/src/client_handler.rs @@ -1,4 +1,4 @@ -//! The per-connection **client** handler — the dial surface's russh +//! The per-connection **client** handler, the dial surface's russh //! `client::Handler` impl (`w4-dial`), the mirror of //! [`crate::handler`]'s server-direction handler. //! @@ -9,46 +9,46 @@ //! the crate's single fingerprint path ([`crate::fingerprint`]), //! labels it with the dial target (host + port, parsed from the //! dial address), and hands the whole [`PresentedHostKey`] to the -//! injected [`HostKeyPolicy`] — the verdict rides straight through -//! (`Ok(policy.decide(..).await)`). The crate is policy-blind; the +//! injected [`HostKeyPolicy`], and the verdict rides straight +//! through (`Ok(policy.decide(..).await)`). The crate is policy-blind; the //! built-in [`RejectAll`](crate::RejectAll) verdict makes every dial //! refuse; a `false` verdict is the decline disposition russh //! surfaces as its `UnknownKey` wire class -//! ([`DialError::HostKeyRejected`](crate::DialError) -//! — never an accept, never a retry). +//! ([`DialError::HostKeyRejected`](crate::DialError)), +//! never an accept, never a retry). //! 2. **Server-initiated channel opens declined cleanly** (ADR-003 §4, //! the client-side symmetry rule): russh's default posture for every -//! `server_channel_open_*` hook is accept-and-drop — a +//! `server_channel_open_*` hook is accept-and-drop, a //! half-capability the family forbids. Every hook is overridden //! explicit-over-inherited. The `forwarded-tcpip` / //! `forwarded-streamlocal` hooks (the `-R` data leg's types) route -//! through the **acceptor registry** ([`crate::client_accept`] — +//! through the **acceptor registry** ([`crate::client_accept`], //! the `w4-reverse-listen` surface): served only under a registered //! acceptor for that type and under the `tunnel` feature (the //! [`with_tunnel_surface`]'s tunnel surface -//! wiring; a build without `tunnel` has no registry — every hook +//! wiring; a build without `tunnel` has no registry, so every hook //! declines); unregistered/unfeatured opens answer -//! [`ChannelOpenFailure::AdministrativelyProhibited`] — a clean +//! [`ChannelOpenFailure::AdministrativelyProhibited`], a clean //! wire-visible refusal the peer observes as an //! unconfirmed open, never an accepted-then-dropped channel. The //! accepted open's handoff spawns (the spawn-and-return rule's //! client mirror): the hook accepts and returns fast, the duplex + //! the open's fields ride the payload to the assembly's acceptor -//! call on its own task. Every other type has no registry slot — +//! call on its own task. Every other type has no registry slot: //! the unknown-type gate //! ([`Handler::should_accept_unknown_server_channel`]) answers //! `false` (the hook's reject-before-open form; its `_unknown` -//! sibling stays a defensive reject — wire-reachable only if that +//! sibling stays a defensive reject, wire-reachable only if that //! gate ever changed, also fail-closed), and the never-feature rows //! (x11, agent) decline at any configuration. //! //! The accepted-open handoff carries a **bounded bookkeeping** //! counter (`AGENTS.md` convention 9, the cap relation recorded in -//! [`crate::client_accept`]): a dedicated per-connection counter — -//! sharing the dial's `Limits::max_concurrent_channels` ceiling the -//! server direction's per-session cap uses — admitted in the hook +//! [`crate::client_accept`]): a dedicated per-connection counter +//! (sharing the dial's `Limits::max_concurrent_channels` ceiling the +//! server direction's per-session cap uses), admitted in the hook //! before the accept, released when the handoff task ends (the -//! acceptor's call completing *or the task unwinding* — +//! acceptor's call completing *or the task unwinding*; //! [`crate::client_accept`]'s `HandoffCapGuard` panic-safety); a full //! counter declines the arrival cleanly //! (`cap-exceeded`). @@ -79,7 +79,7 @@ use crate::{DialError, fingerprint}; /// the two forwarded hooks route through, plus the accepted-open /// handoff counter and its ceiling (the dial's /// `Limits::max_concurrent_channels`; released when the handoff task -/// ends — completion or unwind, `HandoffCapGuard`'s panic-safety). +/// ends, completion or unwind, `HandoffCapGuard`'s panic-safety). #[cfg(feature = "tunnel")] pub(crate) struct TunnelSurface { acceptors: Arc, @@ -87,7 +87,7 @@ pub(crate) struct TunnelSurface { open_cap: std::sync::Arc, } -/// The per-connection client handler the dial surface constructs — +/// The per-connection client handler the dial surface constructs; /// see the module docs. Test surface /// (`#[doc(hidden)]` re-export from the crate root): the contract /// tests drive the bare hooks, exactly the @@ -96,7 +96,7 @@ pub struct ClientHandler { policy: std::sync::Arc, host: String, port: u16, - /// The `-R` surface under `tunnel` (`Some` — the dial wires it; + /// The `-R` surface under `tunnel` (`Some`, the dial wires it; /// the bare-hook tests construct without it to pin the decline-all /// default posture in the featured builds too). #[cfg(feature = "tunnel")] @@ -143,10 +143,10 @@ impl russh::client::Handler for ClientHandler { /// The host-key policy's hook (OQ-05): the presented key or /// certificate's fingerprint is computed on the crate's single - /// fingerprint path (certificates fingerprint their inner key — + /// fingerprint path (certificates fingerprint their inner key; /// the trust decision is the policy's either way) and the whole /// [`PresentedHostKey`] rides the policy; the verdict is passed - /// through untouched. `Ok(false)` — russh's decline — is the + /// through untouched. `Ok(false)`, russh's decline, is the /// disposition, never an error path; the policy's own record /// carries why. async fn check_server_key( @@ -186,7 +186,7 @@ impl russh::client::Handler for ClientHandler { } /// The `forwarded-tcpip` hook (the `-R` data leg's gate): the - /// registry's slot read at arrival time — registered + room → + /// registry's slot read at arrival time (registered + room → /// accept and hand the assembly the open on a spawned task; no /// acceptor / no room → the clean decline, never accept-and-drop. async fn server_channel_open_forwarded_tcpip( @@ -247,10 +247,10 @@ impl russh::client::Handler for ClientHandler { } } - /// The `forwarded-streamlocal` hook — the unix-slot's mirror of + /// The `forwarded-streamlocal` hook, the unix-slot's mirror of /// the tcpip gate (the ingestion is platform-neutral: no runtime - /// gate here; the listen rows carry the OQ-11 gate on the bind — - /// the recorded asymmetry, see [`crate::client_accept`]). + /// gate here; the listen rows carry the OQ-11 gate on the bind, + /// the recorded asymmetry (see [`crate::client_accept`]). async fn server_channel_open_forwarded_streamlocal( &mut self, channel: Channel, @@ -350,8 +350,8 @@ impl russh::client::Handler for ClientHandler { Ok(()) } - /// A never-feature row (ADR-003 §5): x11 has no family seam — the - /// decline is not even registry territory. + /// A never-feature row (ADR-003 §5): x11 has no family seam, so + /// the decline is not even registry territory. async fn server_channel_open_x11( &mut self, channel: Channel, @@ -368,7 +368,7 @@ impl russh::client::Handler for ClientHandler { } /// A never-feature row (ADR-003 §5): agent forwarding is the - /// anti-pattern of the vault custody model — always declined. + /// anti-pattern of the vault custody model, always declined. async fn server_channel_open_agent_forward( &mut self, channel: Channel, @@ -384,7 +384,7 @@ impl russh::client::Handler for ClientHandler { /// Wire-reachable only if /// [`russh::client::Handler::should_accept_unknown_server_channel`] - /// ever answers `true` (it does not — the skeleton's default is + /// ever answers `true` (it does not; the skeleton's default is /// fail-closed); the defensive reject keeps the posture honest /// even then. async fn server_channel_open_unknown( @@ -415,7 +415,7 @@ mod tests { /// - *Contract stamp:* ADR-004 decision 6 posture mirror (the /// client-side: the policy is injected, the handler never - /// decides trust), pinned at the dial wiring — here, that the + /// decides trust), pinned at the dial wiring; here, that the /// labels ride the construction so the policy sees /// `PresentedHostKey { host, port }` verbatim, and the /// fingerprint rides the crate's single fingerprint path. diff --git a/src/client_ops.rs b/src/client_ops.rs index 31ec29a..028784e 100644 --- a/src/client_ops.rs +++ b/src/client_ops.rs @@ -1,67 +1,67 @@ -//! The client op rows (`w4-op-rows`) — `client.md` §op rows in code: +//! The client op rows (`w4-op-rows`), `client.md` §op rows in code: //! the family op → vanilla translation the reverse-runner shape //! drives (the hub dialed [`SshConnection`](crate::SshConnection) and //! now opens every channel itself). **Type symmetry at the seam is //! the contract:** family-protocol types in, vanilla wire ops out, no -//! vanilla-concept leaks up — the rows' inputs are the mapped +//! vanilla-concept leaks up; the rows' inputs are the mapped //! sibling crates' types (the alktty session shapes for the exec/pty //! rows, alkgit's `Service` for the git row) and the surfaces are //! crate-owned (`RemoteSession` / `TunnelChannel` / `GitPackSession`), //! the failure taxonomy [`OpError`](crate::OpError). All rows share //! the russh 0.65 mechanics POC-3 §D.3 recorded: //! -//! - `Channel::exec()` — there is **no `request_exec` at this pin**. +//! - `Channel::exec()`: there is **no `request_exec` at this pin**. //! - A request's Success/Failure replies arrive **on the channel -//! queue via `wait()`**, not as `Err` from the request call — every +//! queue via `wait()`**, not as `Err` from the request call, so every //! request-carrying row drains until the expected message, //! `continue`-ing past the interleaved rest, and maps a `Failure` //! to [`OpError::RequestRefused`](crate::OpError). The drain is //! message-capped (bounded resources: a peer that never answers -//! cannot loop it unboundedly; the *connection's* wall clock — the -//! dial's always-set [`Limits::inactivity_timeout`](crate::Limits) — +//! cannot loop it unboundedly; the *connection's* wall clock, the +//! dial's always-set [`Limits::inactivity_timeout`](crate::Limits), //! bounds the idle waits). //! - **The typed opens resolve `Err` directly on a server reject** -//! (POC-1 §6) — [`OpError::OpenDeclined`](crate::OpError), family-mirrored +//! (POC-1 §6) to [`OpError::OpenDeclined`](crate::OpError), family-mirrored //! [`OpenDeclineReason`](crate::OpenDeclineReason), **and the //! connection stays usable after the decline** (row-pinned per //! decline class). //! - **No channel-queue consumption where a `into_stream()` conversion -//! follows** (POC-1 §6's fresh-`wait()` caveat) — the tunnel rows +//! follows** (POC-1 §6's fresh-`wait()` caveat): the tunnel rows //! (the only `into_stream` consumers) go typed-open → straight //! conversion, nothing between. The exit-**consuming** rows -//! (exec/pty, git) cannot ride `into_stream` at all — the +//! (exec/pty, git) cannot ride `into_stream` at all, since the //! conversion's reader side swallows every non-`Data` message, -//! which is exactly where `ExitStatus`/`ExitSignal` live — so they +//! which is exactly where `ExitStatus`/`ExitSignal` live, so they //! run the **split-halves wait-pump** (`Channel::split()` + a //! spawned task draining `wait()`), the shape the server //! direction's git row landed for the same reason //! (`w4-git-exit-close`). The exit-ride is the family plane's (§the //! session rows) or the consumed-report oneshot's (§the git row). //! - `window_change`/`signal` are fire-and-forget on the wire (no SSH -//! reply exists) — the pumps send and drop the outcome, never +//! reply exists); the pumps send and drop the outcome, never //! awaiting one. //! //! ## The family plane (the session rows) //! //! The exec/pty session's data plane is the **alktty chunk framing in -//! both directions** — the exact plane the server direction's session +//! both directions**, the exact plane the server direction's session //! bridge speaks ([`crate::tty_map`]), consumed not re-derived: //! stdin chunks (`STREAM_STDIN`) ride the wire `data` (the -//! zero-length sentinel = wire EOF, the bridge's decided translation — +//! zero-length sentinel = wire EOF, the bridge's decided translation, //! the session keeps pumping after it); `CTRL_IN` chunks translate to //! the wire request rows (`Resize` → `window_change` (the session -//! dimension clamp is not needed — the family plane is already +//! dimension clamp is not needed; the family plane is already //! `u16`), `Signal{name}` → `signal` through the shared table's //! name→`Sig` map, `Eof` → wire EOF); wire `data` → stdout chunks, //! wire `extended_data(1)` → stderr chunks; and the exit rides //! **in-band as the family's exit chunk** (`STREAM_CTRL_OUT`, -//! exit-chunk-is-last — alktty's ADR-004, mapping.md's contract): +//! exit-chunk-is-last, alktty's ADR-004, mapping.md's contract): //! wire `ExitStatus(N)` → code `N`, wire `ExitSignal(name)` → //! `−signum` through the shared table's inverse read -//! ([`crate::exit_code`] — the derivation contract's client arm; a +//! ([`crate::exit_code`], the derivation contract's client arm; a //! name with no table entry rides the `−1` sentinel, the mapping //! never invents). A session that ends with **no exit report** -//! delivers no exit chunk — the output half just ends (mapping.md's +//! delivers no exit chunk; the output half just ends (mapping.md's //! no-exit-chunk close family: "reports nothing"). The session's //! ttymodes never ride the wire pty request (the OQ-44 //! reserved-JSON posture mirrored: the door never invents wire @@ -78,30 +78,30 @@ //! | tunnel target (`-L`; the alksocks `DialFn`) | `tunnel` | `channel_open_direct_tcpip` | [`SshConnection::tunnel_direct`] | //! | the streamlocal twin | `tunnel` | `channel_open_direct_streamlocal`, runtime-Unix-gated | [`SshConnection::tunnel_direct_unix`] | //! | upstream git service | `git` | the shared grammar's command + `exec`; the pack duplex | [`SshConnection::git_service`] | -//! | sftp | *every build* | **none** — the OQ-13 decline placeholder | [`SshConnection::sftp`] | +//! | sftp | *every build* | **none**, the OQ-13 decline placeholder | [`SshConnection::sftp`] | //! //! The exec-command **length budget** applies identically to the //! command-carrying rows (the server direction's pre-parse cap -//! mirrored at the command-construction gate — bounded resources; +//! mirrored at the command-construction gate; bounded resources, //! an unbounded command buffer can never ride a dial): //! [`OpError::CommandTooLong`](crate::OpError) before any wire op. //! //! No client-side in-crate channel cap *admits* ops (the server //! direction's cap is a wire-battery defense; the client rows are -//! hub-driven — the family app chose the dial): bounded resources on +//! hub-driven (the family app chose the dial): bounded resources on //! this direction are the config's always-on wall clock/keepalives, //! the russh windows, the bounded duplexes/mpscs the pumps ride, and -//! the drain cap — every spawn bounded by its own task's end +//! the drain cap; every spawn bounded by its own task's end //! conditions. //! //! ## Spawn posture //! //! The op methods await their launch (typed open, requests, the -//! reply drains) on the *caller's* task — never the russh packet -//! loop's — so the server direction's spawn-and-return deadlock class +//! reply drains) on the *caller's* task, never the russh packet +//! loop's, so the server direction's spawn-and-return deadlock class //! does not exist here; the long-lived pumps spawn at launch and end //! on their terminal conditions (the exit chunk, the channel's end, -//! or the hub dropping the surface — a drop is wire-clean: the input +//! or the hub dropping the surface; a drop is wire-clean: the input //! pump's terminal path closes the channel, the pump pair reaping as //! their duplex halves drop). @@ -117,13 +117,13 @@ use crate::client::SshConnection; use crate::client_handler::ClientHandler; use crate::error::OpError; -/// The op-row pump duplex capacity — the crate's bridge-pair +/// The op-row pump duplex capacity, the crate's bridge-pair /// convention (the wave-2 loopback harness's per-direction capacity), /// keeping every pump's backpressure bounded. #[cfg(any(feature = "session", feature = "git"))] const OP_DUPLEX_CAPACITY: usize = 65_536; -/// The pump-side read buffer — the SSH-side granularity (per-chunk +/// The pump-side read buffer, the SSH-side granularity (per-chunk /// payloads are bounded by the dial's `maximum_packet_size`). #[cfg(feature = "git")] const PUMP_BUF: usize = 16 * 1024; @@ -137,14 +137,14 @@ const DRAIN_MESSAGE_CAP: usize = 1024; /// The originator label the door puts on the wire's `direct-tcpip` /// opens (the SSH originator fields are what a vanilla client fills /// in for its own local listener; this door's hub-driven dials carry -/// the door's label and no port — recorded decision: nothing +/// the door's label and no port, recorded decision: nothing /// invented, nothing leaked, the peer's logs name the door). #[cfg(feature = "tunnel")] const TUNNEL_ORIGINATOR: &str = "alk-ssh"; /// The wire exit status → the family `i32` exit-code convention: a /// code beyond the family `i32` range is unwritable as an exit-chunk -/// code; the clamp rides (defensive corner — vanilla command codes +/// code; the clamp rides (defensive corner, vanilla command codes /// are far below it; the mapping never invents a value, it narrows). #[cfg(any(feature = "session", feature = "git"))] fn family_exit_code(status: u32) -> i32 { @@ -155,7 +155,7 @@ fn family_exit_code(status: u32) -> i32 { /// op taxonomy (a channel-open failure → /// [`OpError::OpenDeclined`](crate::OpError::OpenDeclined), /// family-mirrored; everything else transparent). The russh level's -/// test observable (`POC-1 §6`'s `Err(ChannelOpenFailure)` — the +/// test observable (`POC-1 §6`'s `Err(ChannelOpenFailure)`, the /// awaiting typed call's resolution) rides this point; the /// connection stays usable after every decline (row-pinned). #[cfg(any(feature = "session", feature = "git", feature = "tunnel"))] @@ -165,7 +165,7 @@ fn open_error(error: russh::Error) -> OpError { /// The request-reply drain (the §module docs' recorded mechanics, /// shared by the exec/pty rows and the git row): Success/Failure via -/// `wait()` — never an `Err` from the request call — `continue` past +/// `wait()`, never an `Err` from the request call; `continue` past /// the interleaved rest (the POC-3 §D.3 break-on-first-message trap, /// not repeated), message-capped. `Failure` is the wire /// request-refusal class ([`OpError::RequestRefused`]); the @@ -197,28 +197,28 @@ async fn drain_launch_request(channel: &mut russh::Channel) -> Result<(), O } // --------------------------------------------------------------------------- -// The sftp placeholder — every build (OQ-13; no feature, no dep) +// The sftp placeholder, every build (OQ-13; no feature, no dep) // --------------------------------------------------------------------------- impl SshConnection { - /// The sftp op — the client-side half of the OQ-13 decline + /// The sftp op, the client-side half of the OQ-13 decline /// placeholder: **declines in every build, before any wire op** /// (never a half-opened subsystem channel). The feature exists /// and ships in the build string; the route does not, and arrives - /// with alkfs as its own ADR — both directions' placeholders are + /// with alkfs as its own ADR; both directions' placeholders are /// then replaced by real rows (`client.md` §What the crate does /// *not* include). Compiles feature-free; the `Ok` type is - /// `Infallible` by design — nothing can ever populate it here. + /// `Infallible` by design; nothing can ever populate it here. pub async fn sftp(&self) -> Result { Err(OpError::SftpNotServed) } } // --------------------------------------------------------------------------- -// The session rows — exec / pty (under `session`) +// The session rows: exec / pty (under `session`) // --------------------------------------------------------------------------- -/// A remote **session** — the family session plane over the runner +/// A remote **session**: the family session plane over the runner /// (the session rows' surface): the alktty chunk framing in both /// directions, exactly the plane the server direction's session /// bridge speaks (`tty_map`), reversed. Two duplex halves @@ -245,7 +245,7 @@ impl std::fmt::Debug for RemoteSession { } } -/// Which request launches a session — the family op's payload +/// Which request launches a session: the family op's payload /// (§the row inventory; pipe-mode exec vs the shell form). #[cfg(feature = "session")] enum LaunchRequest { @@ -255,11 +255,11 @@ enum LaunchRequest { #[cfg(feature = "session")] impl SshConnection { - /// The pipe-mode exec row: `ssh host "cmd"` in, family-typed — + /// The pipe-mode exec row: `ssh host "cmd"` in, family-typed; /// the session channel's open + the wire `exec` request, then the /// chunk-framed session (§the family plane; stderr separated). /// The command rides the wire verbatim (the remote end's shell - /// parses it — the vanilla exec grammar; never argv-split). + /// parses it, the vanilla exec grammar; never argv-split). pub async fn exec(&self, command: impl Into) -> Result { let command = command.into(); if command.len() > self.budgets().max_exec_command_len { @@ -272,7 +272,7 @@ impl SshConnection { /// carries the family /// [`alktty::negotiation::TerminalParamsWire`](alktty::negotiation:: /// TerminalParamsWire) first (its acceptance drained), then the - /// exec. **A refused pty refuses the whole row** — never a + /// exec. **A refused pty refuses the whole row**: never a /// half-capability, never a silent pty-less fall. pub async fn pty_exec( &self, @@ -292,8 +292,8 @@ impl SshConnection { } /// The shell row ("own a shell on the runner"): with - /// `params` — the pty mode (the interactive `ssh` shape); with - /// `None` — the pipe-mode shell (the `ssh -T` shape; a pty-less + /// `params`, this is the pty mode (the interactive `ssh` shape); with + /// `None`, the pipe-mode shell (the `ssh -T` shape; a pty-less /// shell request is legitimate vanilla and served, never declined, /// mirroring the server direction's decided parity). pub async fn shell( @@ -361,7 +361,7 @@ async fn open_remote_session( /// `CTRL_IN` `Eof` / the hub's input half dropping = the wire EOF /// *once*, then the idle-for-kill state (the session keeps pumping); /// the terminal kill (from the output pump's terminal paths) → the -/// wire `channel_close` — the session's drop is wire-clean. +/// wire `channel_close`; the session's drop is wire-clean. #[cfg(feature = "session")] async fn session_input_pump( write_half: russh::ChannelWriteHalf, @@ -432,12 +432,12 @@ async fn session_input_pump( } } -/// One frame read from the hub→door plane — the *no-disambiguation* +/// One frame read from the hub→door plane, in the *no-disambiguation* /// read direction: this plane's chunks are the family protocol's own /// (stdin `0` / `CTRL_IN` `3`); no negotiation-error frames exist /// toward the door, so the read is the protocol's direct /// [`ChunkReader::read_chunk`] (a `0x00`-leading frame here is a -/// zero-length stdin chunk — the sentinel — and reads as exactly +/// zero-length stdin chunk (the sentinel) and reads as exactly /// that). A rogue frame is the bounds-checked [`RawError`], mapped to /// the pump's [`HubFrame::Break`]. #[cfg(feature = "session")] @@ -459,7 +459,7 @@ async fn hub_frame(reader: &mut alktty::wire::ChunkReader'` — built through + /// (`git-{upload,receive}-pack '/'`, built through /// `crate::dispatch`'s construction arm, the parse arm's exact /// inverse; no forked grammar), pointed at the vanilla `sshd`: /// typed open + `exec`, the pack duplex pumped, the exit report @@ -695,9 +695,9 @@ impl SshConnection { /// [`OpError::InvalidRepoId`](crate::OpError); /// the constructed command is checked against the exec-length /// budget ([`crate::Limits::max_exec_command_len`]) → - /// [`OpError::CommandTooLong`](crate::OpError) — both **before any - /// wire op**. (The grammar's other decline classes — - /// `unknown-service` / `service-only` — are structurally + /// [`OpError::CommandTooLong`](crate::OpError), both **before any + /// wire op**. (The grammar's other decline classes, + /// `unknown-service` / `service-only`, are structurally /// unreachable here: the [`alkgit::Service`] input type carries /// only the two serving services; the construction arm can emit /// no other token.) @@ -793,7 +793,7 @@ async fn git_input_pump( /// The git row's **output pump**: the wire → the pack duplex + /// stderr; the exit report consumed here (the family code) and the -/// kill fired — then the input pump closes the wire. A channel end +/// kill fired, then the input pump closes the wire. A channel end /// with no report → no exit fired; the `exit` oneshot drops (the /// hub's receive reads the no-report mirror). #[cfg(feature = "git")] @@ -848,7 +848,7 @@ mod tests { use russh::ChannelOpenFailure; /// - *Contract stamp:* `client.md` §op rows (no vanilla-concept - /// leaks up) + POC-1 §6 — the typed open's decline mapping + /// leaks up) + POC-1 §6: the typed open's decline mapping /// preserves the wire class (`error.rs`'s mirror rows; this /// pins the op rows' own consumption point). #[test] @@ -870,7 +870,7 @@ mod tests { } /// - *Contract stamp:* the family exit-currency clamp (§the - /// family plane) — ordinary codes ride identity, beyond-range + /// family plane); ordinary codes ride identity, beyond-range /// ones narrow (never invent). #[cfg(any(feature = "session", feature = "git"))] #[test] diff --git a/src/config.rs b/src/config.rs index c935b66..e114e93 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,20 +1,20 @@ -//! The pure configuration surface — the shapes every later wave's +//! The pure configuration surface: the shapes every later wave's //! constructors take (serve-config, dial-config, [`Limits`]). Types //! only: russh `Config` construction is wave-2 material, dialing lands //! at wave 4; nothing here touches the wire or the vault. //! //! Two directions, one budget model (`overview.md` §Public surface): //! -//! - [`ServeConfig`] — the server direction's assembly-supplied serving +//! - [`ServeConfig`]: the server direction's assembly-supplied serving //! configuration: the OQ-08 fields ([`ServeConfig::shell_argv`] / //! [`ServeConfig::exec_wrapper_argv`]), the injected identity, //! host-key and tunnel handles, the per-feature family-seam handles -//! (the wave-3 extension — [`SessionSeam`] carries the alktty +//! (the wave-3 extension, where [`SessionSeam`] carries the alktty //! backends map + backend selector + ownership provider; //! [`GitSeam`] carries the alkgit backend quartet + the caller-owned //! pipeline + the push-options flag), the OQ-09 `cwd`/`env` values, //! and the [`Limits`]. -//! - [`DialConfig`] — the client direction's dial configuration +//! - [`DialConfig`]: the client direction's dial configuration //! (`client.md` §The dial surface): address, `username`, key source, //! host-key policy, and the bounded-resource knobs (carried by //! [`Limits`]). @@ -22,7 +22,7 @@ //! Crate rules this module encodes: //! //! - **Unset-declines, no crate defaults** (OQ-08): the OQ-08 fields -//! are `Option` and their unset semantics live in the type shape — +//! are `Option` and their unset semantics live in the type shape, //! an unset field makes its row decline with a clean error at //! request time (wave-2/3 consumption), never a fallback, never //! construction-time validation (`error.rs`'s no-config-error @@ -33,10 +33,10 @@ //! [`ServeConfig::git_seam`] unset → the git row declines even //! though `git` is on (the decline matrix's config-driven notes; //! the feature alone configures nothing). The tunnel branch carries -//! its flat `Option>` — an egress-only -//! (route-1-only) door needs no struct for leg 1 — and the `-R` +//! its flat `Option>`, because an egress-only +//! (route-1-only) door needs no struct for leg 1, and the `-R` //! listen leg's registration seam landed with `w3-tunnel-listen` -//! (`ServeConfig::tunnel_listen_seam` — the wave-3 seam-config's +//! (`ServeConfig::tunnel_listen_seam`, the wave-3 seam-config's //! second course-correction; the shape decision recorded on //! [`TunnelListenSeam`]: unset → the listen rows decline even with //! a fabric leg present, because the door-side inbound-op serving @@ -48,17 +48,17 @@ //! no vault lifecycle of its own. A git-only tunnel build simply //! leaves [`ServeConfig::channel_client`] absent. //! - **Bounded resources everywhere** (convention 9): every session -//! — both directions — carries a [`Limits`]; there is no +//! in both directions carries a [`Limits`]; there is no //! unbounded-loop or unbounded-buffer configuration shape the //! assembly can build from these types. //! //! Knob-name parity with the russh 0.65 pin (ADR-002): //! `window_size`, `maximum_packet_size`, `channel_buffer_size`, //! `inactivity_timeout`, `keepalive_interval`, `keepalive_max`, -//! `max_auth_attempts` — wave-2/wave-4 map these fields into the russh +//! `max_auth_attempts`; wave-2/wave-4 map these fields into the russh //! `Config` verbatim. russh's rekey `Limits` stay russh-enforced at -//! its own RFC-4253 §9 defaults (wave-2); they are not carried here — -//! this module's [`Limits`] is the crate's in-crate + mapped-knob +//! its own RFC-4253 §9 defaults (wave-2); they are not carried here, +//! since this module's [`Limits`] is the crate's in-crate + mapped-knob //! budget model. use std::collections::BTreeMap; @@ -84,15 +84,15 @@ use crate::key_source::{HostKeySource, KeySource}; /// The bounded-resources budget model (`overview.md` /// §Bounded-resources policy): the in-crate caps plus the russh-knob -/// mapping with the documented default postures. Every session — -/// server and client direction — carries one (`AGENTS.md` convention +/// mapping with the documented default postures. Every session, +/// server or client direction, carries one (`AGENTS.md` convention /// 9); there is no unbounded configuration shape. /// /// Carried by value (`Copy`): a [`Limits`] is plain tuning data, and /// wave-2/4 copies it into the russh `Config` construction. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Limits { - /// The crates' own cap on concurrent channels per session — + /// The crates' own cap on concurrent channels per session; /// opened channels beyond the cap are declined (fail-closed /// refuse, never queue). The per-identity policy layer (when the /// alkcall bridge carries it) is additional and comes with the @@ -102,39 +102,39 @@ pub struct Limits { pub max_concurrent_channels: usize, /// The parse-input cap for the wave-3 exec grammar: a wire exec /// command string longer than this declines before any parse or - /// resource allocation (decline-first, alloc-never — the ADR-006 + /// resource allocation (decline-first, alloc-never, the ADR-006 /// dispatch contract). Assembly-tunable. /// /// Default: `DEFAULT_MAX_EXEC_COMMAND_LEN`. pub max_exec_command_len: usize, - /// Maximal number of allowed authentication attempts — mapped to + /// Maximal number of allowed authentication attempts, mapped to /// russh's `max_auth_attempts` (server direction). Default `10` /// per ADR-004 decision 6: the OpenSSH counting `none`-probe /// consumes one attempt, so `10` leaves `IdentitiesOnly`-style /// clients at least nine real key attempts. pub max_auth_attempts: usize, - /// The initial channel receive window — mapped to russh's + /// The initial channel receive window, mapped to russh's /// `window_size` (per-channel memory bound). /// /// Default: 2 MiB (russh's own default posture, kept). pub window_size: u32, - /// The maximal size of a single SSH packet — mapped to russh's + /// The maximal size of a single SSH packet, mapped to russh's /// `maximum_packet_size` (per-channel record-size bound). /// /// Default: 32 KiB (russh's own default posture, kept). pub maximum_packet_size: u32, - /// Per-channel unprocessed-message buffer — mapped to russh's + /// Per-channel unprocessed-message buffer, mapped to russh's /// `channel_buffer_size` (the backpressure bound); messages past /// it propagate backpressure to the TCP stream, never an /// unbounded buffer. /// /// Default: 100 (russh's own default posture, kept). pub channel_buffer_size: usize, - /// The session wall clock — the connection is garbage-collected + /// The session wall clock; the connection is garbage-collected /// after this long with no activity. Mapped to russh's /// `Option` as always-set (`Some(value)`) in /// wave 2/4: the bounded-resources policy's "set - /// (assembly-tunable)" posture — the crate never constructs a + /// (assembly-tunable)" posture; the crate never constructs a /// session with no wall clock. Assembly-tunable. /// /// Default: `DEFAULT_INACTIVITY_TIMEOUT`. @@ -142,13 +142,13 @@ pub struct Limits { /// Client-direction keepalive interval (cloud fleets): the /// dead-peer probe, mapped to russh's `keepalive_interval`. /// - /// Default: `Some(15 s)` — the reverse-runner-evidence posture + /// Default: `Some(15 s)`, the reverse-runner-evidence posture /// (OpenSSH `ServerAliveInterval=15` parity): with russh's own /// default (`None`) a dead NAT'd connection sits unnoticed until /// an exec health check fails (`reverse-runner.md` lesson 3). /// `None` is available to the assembly but is not the posture. pub keepalive_interval: Option, - /// How many unanswered keepalives close the connection — mapped + /// How many unanswered keepalives close the connection, mapped /// to russh's `keepalive_max`. /// /// Default: `3` (OpenSSH `ServerAliveCountMax=3` parity, the @@ -204,30 +204,30 @@ impl Default for Limits { /// seams): what `drive_session[_pre_negotiated]` takes that the /// assembly composes (alktty 0.8.2's `adapter.rs:205-241` signature). /// **Shape decision** (recorded at `w3-seam-config`): a whole-`Option` -/// struct per seam, not flat `Option` fields — each seam is consumed +/// struct per seam, not flat `Option` fields; each seam is consumed /// atomically by exactly one seam call, so a struct admits no /// half-supplied seam states and the unset-declines contract reads as /// one `Option`: **`ServeConfig::session_seam` unset → the session /// rows decline even though the `session` feature is on** (the /// decline matrix's config-driven note), checked at request time by -/// the mappings — no construction-time validation. Cloned into each +/// the mappings; no construction-time validation. Cloned into each /// spawned serving task (all payload types `Arc` or plain data). #[cfg(feature = "session")] #[derive(Clone)] pub struct SessionSeam { - /// The alktty backends map — the `TtyAdapter`-style registry keyed + /// The alktty backends map, the `TtyAdapter`-style registry keyed /// by the `NegotiateRequest.backend` selector string. **Assembled /// by the assembly**: alkssh never touches a real backend, and the /// `local` backend shapes stay alktty-side (this dep's `local` - /// feature is not enabled — the map holds assembly-supplied + /// feature is not enabled; the map holds assembly-supplied /// implementations of alktty's [`TtyBackend`] only). pub backends: Arc>>, - /// The backend **selector** — the `NegotiateRequest.backend` + /// The backend **selector**, the `NegotiateRequest.backend` /// string alkssh writes into the locally-constructed negotiation /// (`w3-tty-session`'s negotiation rows; the wire command/args /// never reach it). Assembly-supplied, never wire-derived. pub backend: String, - /// The ADR-050 ownership provider — passed through + /// The ADR-050 ownership provider, passed through /// `drive_session[_pre_negotiated]` verbatim (the family ACL /// layer riding alongside; an alkcall type, no new dep). pub ownership: Option>, @@ -248,27 +248,27 @@ impl std::fmt::Debug for SessionSeam { /// The `git` feature's alkgit seam handle (`mapping.md` §The seams): /// what `serve_duplex_resolved` takes that the assembly composes -/// (alkgit 0.1.0's `duplex.rs:1412-1426` signature — the session +/// (alkgit 0.1.0's `duplex.rs:1412-1426` signature: the session /// budget, the four backend traits, the caller-owned pipeline, the /// push-options gate; the `limits` field landed with `w3-git-mapping` -/// — the first seam consumer — as a `w3-seam-config` course +/// the first seam consumer, as a `w3-seam-config` course /// correction: alkgit's ADR-009 budget is assembly config, the door /// never invents it). Same whole-`Option`-struct decision as /// [`SessionSeam`]: /// **`ServeConfig::git_seam` unset → the git row declines even though /// the `git` feature is on**, checked at request time by the -/// mappings — no construction-time validation. +/// mappings; no construction-time validation. #[cfg(feature = "git")] #[derive(Clone)] pub struct GitSeam { - /// The alkgit session budget (alkgit ADR-009's per-session bundle — + /// The alkgit session budget (alkgit ADR-009's per-session bundle: /// wall clock, pack-size caps, negotiation rounds): **constructed - /// by the assembly** (alkgit's own contract — the door never + /// by the assembly** (alkgit's own contract: the door never /// invents budget values), passed into `serve_duplex_resolved` /// verbatim (`w3-git-mapping`). Carried `Copy`; [`alkgit::Limits`]'s /// own defaults are the assembly's baseline. pub limits: alkgit::Limits, - /// The repo-id resolution trait (`GitRegistry::resolve`) — the + /// The repo-id resolution trait (`GitRegistry::resolve`), the /// ADR-007 pre-protocol gate's other half; alkssh never resolves /// (the collapsed-generic-denial posture lives in alkgit). pub registry: Arc, @@ -278,13 +278,13 @@ pub struct GitSeam { /// The pack generation + negotiation-ack trait /// (`generate`/`common_haves`). pub packgen: Arc, - /// The pack-preparation trait (`prepare` — never applies; the + /// The pack-preparation trait (`prepare` never applies; the /// `GitRefs::apply_updates` CAS stays the single ingestion home). pub ingest: Arc, /// The assembler's push-options flag (alkgit's ADR-013 §11 gate, - /// passed through verbatim) — `false` in the v1 default. + /// passed through verbatim), `false` in the v1 default. pub push_options_negotiated: bool, - /// The caller-owned, server-wide pipeline permit — alkgit's + /// The caller-owned, server-wide pipeline permit: alkgit's /// pack-pipeline concurrency bound, *shared across every session /// the serving direction takes* (the caller keeps its own handle; /// `Arc` for the share). One per `DialConfig`-independent serve @@ -308,7 +308,7 @@ impl std::fmt::Debug for GitSeam { } /// The `tunnel` feature's `-R` listen-leg registration seam (the -/// `w3-tunnel-listen` shape — the wave-3 seam-config's second +/// `w3-tunnel-listen` shape, the wave-3 seam-config's second /// course-correction, resolved per its own decision record): the /// assembly-supplied `Arc` alone cannot carry the /// door-side acceptance of the fabric's inbound forwarded opens, @@ -324,11 +324,11 @@ impl std::fmt::Debug for GitSeam { /// **`ServeConfig::tunnel_listen_seam` unset → the `-R` listen rows /// (`tcpip_forward` / `streamlocal_forward` / both cancel forms) /// decline even under the `tunnel` feature with a fabric leg present** -/// — an egress-only door (the POC-3 stage-C posture) is legitimate +/// : an egress-only door (the POC-3 stage-C posture) is legitimate /// config; the feature alone configures nothing. Checked at request /// time by the mappings; no construction-time validation. The /// registration itself (the alkcall openable registration the seam -/// fronts) is alkssh-side work at [`crate::SshAdapter::new`] — a +/// fronts) is alkssh-side work at [`crate::SshAdapter::new`]; a /// failed registration is a failed construction (fail-closed, never a /// half-configured adapter). #[cfg(feature = "tunnel")] @@ -336,7 +336,7 @@ pub struct TunnelListenSeam { /// The **shared** per-connection `OperationRegistry` the fabric /// leg's inbound ops dispatch against: the exact `Arc` the /// assembly passed in this leg's `ChannelClient` construction - /// (`ServingConfig.registry`) — alkssh registers the + /// (`ServingConfig.registry`): alkssh registers the /// `tunnel/forwarded` openable into it, and alkcall's dispatch /// reads it per call (the W2 post-hoc-registration posture). The /// door's own ACL entry rides the registration; arrivals lacking @@ -355,7 +355,7 @@ use alkcall::registry::registration::OperationRegistry; impl TunnelListenSeam { /// Builds the seam over the assembly's shared per-connection /// registry (the `ServingConfig.registry` the same fabric leg's - /// `ChannelClient` was constructed with — one `Arc`, both sides). + /// `ChannelClient` was constructed with: one `Arc`, both sides). pub fn new(registry: Arc) -> Self { Self { registry } } @@ -372,22 +372,22 @@ impl std::fmt::Debug for TunnelListenSeam { /// The server direction's assembly-supplied serving configuration /// (`overview.md` §Server stack): everything wave-2's serving loop -/// takes at construction. Pure data + injected handles — no russh +/// takes at construction. Pure data + injected handles; no russh /// `Config` is built here (wave 2), no serving loop exists yet. /// /// Construction carries no validation beyond the required handles: /// the unfeatured/unset capability surfaces are structural `Option`s -/// that decline at request time (the fail-closed contract) — see +/// that decline at request time (the fail-closed contract); see /// [`ServeConfig::shell_argv`] and [`ServeConfig::channel_client`]. pub struct ServeConfig { /// OQ-08 field 1: the shell argv, run verbatim for - /// `shell_request` (`NegotiateRequest.cmd`). No crate default — + /// `shell_request` (`NegotiateRequest.cmd`). No crate default: /// **unset → `shell_request` declines with a clean error, never a /// fallback**: the crate is not an sshd and has no account model /// from which a shell could be derived, so any baked-in shell /// would be deployment policy smuggled into the crate. A /// `session` build with this unset serves neither shell nor exec - /// requests (the git row is unaffected — parsing never needs a + /// requests (the git row is unaffected, since parsing never needs a /// shell). /// /// Set to `Some(vec)` to serve the shell row (feature-gated at @@ -396,33 +396,33 @@ pub struct ServeConfig { /// OQ-08 field 2: the exec wrapper argv (platform-neutral, e.g. /// `["/bin/sh", "-c"]`). A non-git `exec_request`'s wire command /// string is appended as the final argv element - /// (`wrapper ++ [cmd]`) — vanilla `ssh host "cmd"` quoting + /// (`wrapper ++ [cmd]`), the vanilla `ssh host "cmd"` quoting /// semantics; command strings are never naively split. No crate - /// default — **unset → the non-git exec row declines with a + /// default: **unset → the non-git exec row declines with a /// clean error, never a fallback**. /// /// Set to `Some(vec)` to serve the pipe-exec row (feature-gated /// at wave 2: only under the `session` feature). pub exec_wrapper_argv: Option>, /// The OQ-09 posture's assembly-supplied working directory for - /// alktty `NegotiateRequest.cwd` — **never wire-derived** + /// alktty `NegotiateRequest.cwd`, **never wire-derived** /// (`env_request` declines unconditionally; wire env is not /// family config). Unset → the backend-side default applies. pub session_cwd: Option, /// The OQ-09 posture's assembly-supplied environment for - /// `NegotiateRequest.env` — **never wire-derived**. Empty by + /// `NegotiateRequest.env`, **never wire-derived**. Empty by /// default. pub session_env: BTreeMap, - /// The `session` feature's alktty seam handle ([`SessionSeam`] — + /// The `session` feature's alktty seam handle ([`SessionSeam`], /// the backends map + backend selector + ownership provider the /// `drive_session[_pre_negotiated]` rows take). **Unset → the /// session rows decline even though the `session` feature is on** /// (the decline matrix's config-driven note; the feature alone /// configures nothing). Wave-3 extension of the wave-1 config - /// surface — shape decision recorded on [`SessionSeam`]. + /// surface; shape decision recorded on [`SessionSeam`]. #[cfg(feature = "session")] pub session_seam: Option, - /// The `git` feature's alkgit seam handle ([`GitSeam`] — the four + /// The `git` feature's alkgit seam handle ([`GitSeam`], the four /// backend traits + the caller-owned pipeline + the push-options /// flag the `serve_duplex_resolved` row takes). **Unset → the git /// row declines even though the `git` feature is on** (same @@ -430,33 +430,33 @@ pub struct ServeConfig { #[cfg(feature = "git")] pub git_seam: Option, /// The injected identity provider (alkcall's - /// `IdentityProvider::resolve_from_fingerprint`) — the assembly + /// `IdentityProvider::resolve_from_fingerprint`), the assembly /// supplies it; the crate never resolves identities itself and /// holds no identity model. pub identity_provider: Arc, /// The injected host-key source (the wave-1 /// [`HostKeySource`] seam, decrypt-at-construction per ADR-005 - /// decision 6) — feeds wave-2's `Config::keys`; a load failure + /// decision 6) feeds wave-2's `Config::keys`; a load failure /// means no server is constructed, never a half-configured one. pub host_key_source: Arc, /// The tunnel route-1 bridge's family-fabric entry: a held /// alkcall `ChannelClient` (`TunnelSession::open_direct` runs on /// it). **Absent → every tunnel row declines with a clean error /// even under the `tunnel` feature** (the feature alone configures - /// nothing — the fabric handle is the row's other half). The + /// nothing; the fabric handle is the row's other half). The /// present handle is still gated by the `tunnel` feature at wave /// 2: absent + unfeatured both decline; present + featured /// serves. pub channel_client: Option>, - /// The `-R` listen leg's registration seam ([`TunnelListenSeam`] — + /// The `-R` listen leg's registration seam ([`TunnelListenSeam`], /// the shared per-connection registry the fabric's inbound /// forwarded opens dispatch against). **Unset → the listen rows /// decline even under the `tunnel` feature with a fabric leg - /// present** (the egress-only door is legitimate config — the + /// present** (the egress-only door is legitimate config, the /// POC-3 stage-C posture; shape decision recorded on the type). #[cfg(feature = "tunnel")] pub tunnel_listen_seam: Option, - /// The listen leg's per-arrival bookkeeping — installed by + /// The listen leg's per-arrival bookkeeping, installed by /// [`crate::SshAdapter::new`] when the fabric leg + seam are both /// present (the registration site). Crate-private: never assembly /// data. @@ -469,10 +469,10 @@ pub struct ServeConfig { impl ServeConfig { /// Builds a serve-config from the two injected handles the - /// serving direction can never default — the identity provider + /// serving direction can never default, the identity provider /// and the host-key source. The OQ-08 fields start unset (their /// rows decline), the tunnel handle starts absent (its rows - /// decline), and `limits` starts at [`Limits::default()`] — + /// decline), and `limits` starts at [`Limits::default()`], /// override the `pub` fields from the assembly. pub fn new( identity_provider: Arc, @@ -500,14 +500,14 @@ impl ServeConfig { /// Whether the `shell_request` row is configurable at all in this /// configuration (`Some` under the `session` feature): `false` - /// means the row declines — the unset-declines contract, checked + /// means the row declines; the unset-declines contract, checked /// at request time by the wave-2 dispatch, never here. pub fn shell_configured(&self) -> bool { self.shell_argv.is_some() } /// Whether the non-git `exec_request` (pipe) row is configurable - /// at all in this configuration: `false` means the row declines — + /// at all in this configuration: `false` means the row declines; /// the unset-declines contract, checked at request time by the /// wave-2 dispatch, never here. pub fn exec_wrapper_configured(&self) -> bool { @@ -524,7 +524,7 @@ impl ServeConfig { /// Whether the `-R` listen rows' registration seam is configured /// in this configuration ([`TunnelListenSeam`] present; the /// `tunnel` feature gate applies at the dispatch on top): `false` - /// means the listen rows decline — the unset-declines contract, + /// means the listen rows decline; the unset-declines contract, /// checked at request time by the mappings, never here. #[cfg(feature = "tunnel")] pub fn tunnel_listen_seam_configured(&self) -> bool { @@ -534,7 +534,7 @@ impl ServeConfig { /// Whether the session rows' family seam is configured in this /// configuration ([`SessionSeam`] present; the `session` feature /// gate applies at the dispatch on top): `false` means the rows - /// decline — the unset-declines contract, checked at request time + /// decline; the unset-declines contract, checked at request time /// by the wave-3 mappings, never here. #[cfg(feature = "session")] pub fn session_seam_configured(&self) -> bool { @@ -543,8 +543,8 @@ impl ServeConfig { /// Whether the git row's family seam is configured in this /// configuration ([`GitSeam`] present; the `git` feature gate - /// applies at the dispatch on top): `false` means the row declines - /// — the unset-declines contract, checked at request time by the + /// applies at the dispatch on top): `false` means the row declines; + /// the unset-declines contract, checked at request time by the /// wave-3 mappings, never here. #[cfg(feature = "git")] pub fn git_seam_configured(&self) -> bool { @@ -581,21 +581,21 @@ impl std::fmt::Debug for ServeConfig { /// The client direction's dial configuration (`client.md` §The dial /// surface): everything wave-4's dial surface takes. Pure data + -/// injected handles — the russh client `Config` construction and the +/// injected handles; the russh client `Config` construction and the /// dial itself live in the crate's dial module (the `w4-dial` /// surface). /// /// Construction carries no validation: the key source's own -/// load path is fail-closed ([`KeySource`] — locked/absent/decryption +/// load path is fail-closed ([`KeySource`]: locked/absent/decryption /// failures are all no-dial outcomes), and the host-key policy's /// default is fail-closed ([crate::host_key::RejectAll]). /// /// **The `username` field** (the task's sanctioned -/// `w3-seam-config`-pattern course-correction — the only amendment the +/// `w3-seam-config`-pattern course-correction, the only amendment the /// wave-1 shape needed): the USERAUTH_REQUEST's user string. The /// wave-1 shape carried everything `client.md` §The dial surface names /// but structurally missed this one: russh's `authenticate_publickey` -/// requires a user, and the remote end evaluates it — the family +/// requires a user, and the remote end evaluates it; the family /// identity model stays fingerprint-only forever (`auth.md` §Host-key; /// the username is not identity and carries no routing semantics, /// OQ-03), so this field is pure dial data the assembly supplies. No @@ -603,28 +603,28 @@ impl std::fmt::Debug for ServeConfig { /// smuggled into the crate); an empty string is accepted as data and /// is the remote end's to refuse. pub struct DialConfig { - /// The dial target — `host:port` as russh's connect surface + /// The dial target: `host:port` as russh's connect surface /// takes it (the reverse-runner shape: vanilla `sshd` on the /// fleet box). The same address labels the host-key policy's /// presented-key decisions (host = the parsed host, port = the /// parsed port). pub address: String, /// The user the dial authenticates as, verbatim on the - /// USERAUTH_REQUEST — not identity (the fingerprint is; ADR-004 + /// USERAUTH_REQUEST, not identity (the fingerprint is; ADR-004 /// decision 5's posture, mirrored client-side), never logged (the /// crate's event vocabulary carries no username). See the type /// docs. pub username: String, /// The key source the dial authenticates with (the wave-1 - /// [`KeySource`] seam) — never a static key, never env vars; + /// [`KeySource`] seam): never a static key, never env vars; /// decrypt-at-dial, fail-closed per ADR-005. pub key_source: Arc, - /// The injected host-key policy (OQ-05) — the trust decision + /// The injected host-key policy (OQ-05), the trust decision /// surface the dial calls at russh's `check_server_key` hook. /// The crate is policy-blind; the built-in default policy /// ([crate::host_key::RejectAll]) connects to nothing, by design. pub host_key_policy: Arc, - /// The bounded-resource budget this dial runs under — the + /// The bounded-resource budget this dial runs under; the /// keepalive interval/max, the wall clock and the window/packet /// knobs ride here (see [`Limits`]; the keepalive 15 s / 3 /// default posture is the client direction's). @@ -634,7 +634,7 @@ pub struct DialConfig { impl DialConfig { /// Builds a dial-config from the address, the user it /// authenticates as, and the two injected handles the dial - /// direction can never default — the key source and the host-key + /// direction can never default, the key source and the host-key /// policy. `limits` starts at [`Limits::default()`] (keepalive /// 15 s / 3 posture riding inside). pub fn new( @@ -1033,7 +1033,7 @@ mod tests { } // The wave-3 per-feature seam handles: the construction shapes, the - // unset-declines-preserved rows and the Debug posture — each block + // unset-declines-preserved rows and the Debug posture; each block // only runs in the build that carries its feature (compile-time // feature isolation: no git build ever touches alktty types, // no session build ever touches alkgit types). @@ -1131,7 +1131,7 @@ mod tests { /// - *Contract stamp:* the `w3-tunnel-listen` seam shape (the /// unset-declines contract's tunnel extension): the seam starts - /// unset (the listen rows decline — an egress-only door is + /// unset (the listen rows decline; an egress-only door is /// legitimate config), sets independently of the fabric handle, /// and Debug-shapes without registry internals. #[cfg(feature = "tunnel")] diff --git a/src/dispatch.rs b/src/dispatch.rs index 471c2d4..55e27d8 100644 --- a/src/dispatch.rs +++ b/src/dispatch.rs @@ -1,75 +1,75 @@ //! The exec-grammar dispatch core (`w2-dispatch-decline-core`, full -//! grammar `w3-git-mapping`) — the routing decision and the wire-decline +//! grammar `w3-git-mapping`): the routing decision and the wire-decline //! reason shaping the per-connection handler hooks speak //! ([`crate::handler`]). //! //! **Parse-only** (ADR-006 point 3 as amended): an `exec_request` -//! parses *first* — before dispatch and before any resource +//! parses *first*, before dispatch and before any resource //! allocation (**decline first, alloc never**, the POC-3 stage-A rule: //! a leaked channel alloc is a capability leak). The parse is total: //! it routes every input to exactly one of [`ExecRoute`]'s outcomes. //! The *per-length limit* ([`crate::Limits::max_exec_command_len`]) is -//! consumed **before** this parse — the handler checks the wire byte +//! consumed **before** this parse: the handler checks the wire byte //! length first (pre-parse, pre-allocation), so everything below //! assumes a sized input. Invalid UTF-8 parses to the pipe row //! (parse-then-fail, the wave-2 rule). //! -//! ## The exec grammar (`w3-git-mapping` — the wave-2 probe's named +//! ## The exec grammar (`w3-git-mapping`, the wave-2 probe's named //! replacement, its unit rows migrated) //! -//! What vanilla git sends over SSH (`git-upload-pack '/owner/demo'` — +//! What vanilla git sends over SSH (`git-upload-pack '/owner/demo'`: //! single-quoted repo path with a leading `/`; POC-3 stage A §2's //! verified grammar table): //! //! - **`git-{upload,receive}-pack ''`** → [`ExecRoute::Git`]: //! the two serving services of ADR-016, one separating space, and a -//! path-shaped argument — quoted (the vanilla wire shape, fully +//! path-shaped argument: quoted (the vanilla wire shape, fully //! single-quote-wrapped) or unquoted absolute (leading `/`). The //! path is normalized: quotes stripped, leading `/` stripped, and -//! **one trailing `.git` suffix stripped** — the vanilla-clone idiom +//! **one trailing `.git` suffix stripped** (the vanilla-clone idiom //! (real git sends the remote URL's path verbatim, bare clones carry //! `.git`; the alkgit registry grammar (`validate_repo_id`) excludes //! `.`, so the door normalizes the idiom rather than asking //! registries for dotted keys; an empty remainder keeps `.git` and -//! fails validation — never silently emptied). The normalized path -//! is *not yet validated* — the git row (feature-gated) validates it +//! fails validation, never silently emptied). The normalized path +//! is *not yet validated*: the git row (feature-gated) validates it //! against `alkgit::validate_repo_id` (1–2 segments, charset, ≤ 100 //! bytes) and hands the id through; **alkssh never resolves** (the //! no-existence-oracle posture lives in alkgit's collapsed generic //! denial, and an id failing the *shape* gate is the git row's -//! `invalid-repo-id` decline — see below). Single-segment or +//! `invalid-repo-id` decline; see below). Single-segment or //! `.git`-empty shapes ride the same grammar. //! - **`git-send-pack` / `git-upload-archive`** → //! [`ExecRoute::Declined`]([`ExecDecline::UnknownService`]): the //! known non-serving git services take the honest decline-with-reason -//! surface (POC-3 §2; ADR-016's fixed refusal — `git-upload-archive` +//! surface (POC-3 §2; ADR-016's fixed refusal: `git-upload-archive` //! is absent from serving by ADR-016 §1). Decision recorded //! (`w3-git-mapping`): they do **not** ride the pipe row; the decline //! is build-independent (no feature ever serves them). //! - **A serving service with no argument at all** (service-only) → //! [`ExecRoute::Declined`]([`ExecDecline::ServiceOnly`]): SSH exec -//! must carry the repo (POC-3 §A — a subsystem-style name cannot +//! must carry the repo (POC-3 §A: a subsystem-style name cannot //! dispatch, so exec without a repo cannot either). //! - **Everything else** → [`ExecRoute::Pipe`] (parse-then-fail): not -//! git — including path-shaped-but-not-absolute unquoted arguments +//! git, including path-shaped-but-not-absolute unquoted arguments //! (`git-upload-pack rel`, exact strings the wave-2 probe pinned) //! and unterminated quotes; the probe's routing verdicts are //! preserved verbatim. //! //! ## The wire vocabulary (decision, recorded) //! -//! SSH request replies carry no failure text, so — except for the open -//! level — the *reason* lives in the event vocabulary +//! SSH request replies carry no failure text, so, except for the open +//! level, the *reason* lives in the event vocabulary //! ([`crate::observe`]), not on the wire. Decision: the grammar //! declinables (`unknown-service`, `service-only`, and the git row's //! `invalid-repo-id`) share the **request-level reply shape** with -//! parse-then-fail — `channel_failure`, channel left usable (the +//! parse-then-fail: `channel_failure`, channel left usable (the //! POC-1 §5 session-survives-declines posture; POC-3's decline shape), //! distinguishable only in the events. The *serving-path* shape //! (failure + close, the spawned task's) stays reserved for declined //! rows that owned the channel: the seam-unconfigured git row and the //! real serve's own outcomes (the denial band alkgit writes before any -//! protocol byte, then exit-status + close — the wire shapes the +//! protocol byte, then exit-status + close; the wire shapes the //! `git_map` module pins). use russh::ChannelOpenFailure; @@ -80,7 +80,7 @@ use russh::ChannelOpenFailure; /// `w3-git-mapping` grammar with the declined-with-reason class). #[derive(Debug, Clone, PartialEq, Eq)] pub enum ExecRoute { - /// A git-parseable command — routes to the git row. The repo path + /// A git-parseable command; it routes to the git row. The repo path /// is the normalized argument grammar (quotes, leading `/`, one /// trailing `.git`); validation (`alkgit::validate_repo_id`) is /// the git row's gate (the `crate::git_map` module). @@ -88,35 +88,35 @@ pub enum ExecRoute { service: GitServiceRoute, repo: String, }, - /// Everything else — routes to the session pipe row (the + /// Everything else: routes to the session pipe row (the /// `session` feature gate is the row's other half; unfeatured /// builds decline here). Pipe, /// A command the grammar recognizes as git-transport-shaped but - /// that can never dispatch on this door — declined with a reason, + /// that can never dispatch on this door; it is declined with a reason, /// honestly and build-independently (see the grammar section). Declined(ExecDecline), } -/// The git service the exec grammar recognized — the ADR-016 wire +/// The git service the exec grammar recognized: the ADR-016 wire /// strings, as the door-side form of `alkgit::Service` (the seam maps /// them verbatim; this type keeps the parse core feature-free). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum GitServiceRoute { - /// `git-upload-pack` — fetch. + /// `git-upload-pack`: fetch. UploadPack, - /// `git-receive-pack` — push. + /// `git-receive-pack`: push. ReceivePack, } -/// A git-shaped command that can never dispatch — the decline reasons +/// A git-shaped command that can never dispatch: the decline reasons /// the grammar itself decides (the git row adds `invalid-repo-id` at /// the validation gate; that one needs `alkgit`'s grammar, this type /// is the parse core's). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ExecDecline { /// A known non-serving git service arrived on the wire: - /// `git-send-pack` / `git-upload-archive` (POC-3 §2 — the honest + /// `git-send-pack` / `git-upload-archive` (POC-3 §2, the honest /// surface; ADR-016's refusal). UnknownService { service: &'static str }, /// A serving service name with no repo argument at all (POC-3 @@ -126,7 +126,7 @@ pub enum ExecDecline { impl ExecDecline { /// The event-vocabulary reason for this decline (§the wire - /// vocabulary — `&'static str` values only; no wire-carried + /// vocabulary: `&'static str` values only; no wire-carried /// service token ever rides an event). pub(crate) fn reason(self) -> &'static str { match self { @@ -136,7 +136,7 @@ impl ExecDecline { } } -/// The exec-grammar parse — the wave-2 `classify_exec` probe's +/// The exec-grammar parse: the wave-2 `classify_exec` probe's /// replacement, its unit rows migrated (see the grammar section for /// the exact shape rules). pub fn parse_exec(command: &str) -> ExecRoute { @@ -174,13 +174,13 @@ pub fn parse_exec(command: &str) -> ExecRoute { } } -/// The grammar's construction arm (`w4-op-rows`) — the client +/// The grammar's construction arm (`w4-op-rows`), the client /// direction's mirror of [`parse_exec`]: the git route + repo id → /// the vanilla wire command string, byte-for-byte the shape the -/// grammar parses back (`git-{upload,receive}-pack '/'` — the +/// grammar parses back (`git-{upload,receive}-pack '/'`, the /// fully-single-quote-wrapped path with the leading `/`, POC-3 §A's -/// verified shape). The client row reuses — never forks — the -/// grammar: it hands the constructed command back through +/// verified shape). The client row reuses the grammar, never forks +/// it: it hands the constructed command back through /// [`parse_exec`] before any wire op, so the shared verdicts (the /// per-length cap, the decline classes) ride both arms /// (`client.md` §op rows: "the same exec grammar the server side @@ -195,10 +195,10 @@ pub(crate) fn build_git_exec_command(service: GitServiceRoute, repo_id: &str) -> } /// The argument-grammar stage: a path-shaped argument (fully wrapped -/// in single quotes — the vanilla wire shape — or unquoted absolute; +/// in single quotes, the vanilla wire shape, or unquoted absolute; /// anything else is not git) normalized to the repo path: quotes /// stripped, leading `/` stripped, one trailing `.git` stripped (the -/// recorded normalization — see the module grammar section; an +/// recorded normalization; see the module grammar section; an /// empty-after-normalized id is *kept* for the git row's validation /// to decline as `invalid-repo-id`, never silently emptied). fn normalize_repo_path(argument: &str) -> Option { @@ -222,10 +222,10 @@ fn normalize_repo_path(argument: &str) -> Option { Some(normalized.to_owned()) } -/// The wire decline reason for a **featureless** row — a known channel +/// The wire decline reason for a **featureless** row: a known channel /// type this build serves nothing of (unfeatured or never-feature): /// `administratively prohibited`, the vanilla-observable policy -/// refusal (POC-1 §5 — channel-scoped, auth intact, no hangs). A +/// refusal (POC-1 §5: channel-scoped, auth intact, no hangs). A /// never-feature (`x11`, auth-agent) and an unfeatured feature row /// share this class honestly: without the feature there is no /// capability to configure, so nothing distinguishable exists. @@ -234,14 +234,14 @@ pub(crate) fn unfeatured_open_decline() -> ChannelOpenFailure { } /// The wire decline reason for a **cannot-bridge** tunnel open -/// (`w3-tunnel-direct` — the wave-2 seam stub's reason surviving as +/// (`w3-tunnel-direct`, the wave-2 seam stub's reason surviving as /// the real decline): `connect failed`, the explicit reject shape -/// ADR-006 decision 1 pins — accept only after the fabric open +/// ADR-006 decision 1 pins: accept only after the fabric open /// succeeds, and a fabric-open failure maps to this explicit `SSH /// `ConnectFailed` (the channel never establishes, so the client /// observes a channel-scoped refusal, no hang). The same code covers /// the other cannot-bridge classes of the direct rows (the fabric -/// entry unconfigured under the feature — the unset-declines posture — +/// entry unconfigured under the feature (the unset-declines posture), /// and wire arguments naming an impossible target; a vanilla client /// cannot distinguish these from a dead target, and the event /// vocabulary records which). Policy refusals stay @@ -252,7 +252,7 @@ pub(crate) fn connect_failed_open_decline() -> ChannelOpenFailure { /// The wire decline reason for an open beyond the **in-crate /// concurrent-channel cap** (`overview.md` §Bounded-resources policy, -/// `w2-bounded-resources`): `administratively prohibited` — the cap is +/// `w2-bounded-resources`): `administratively prohibited`; the cap is /// the assembly's own configured policy ceiling, refused fail-closed /// at the open (never queued, never half-open). OpenSSH's own /// `MaxSessions` ceiling answers the same code, so vanilla clients @@ -281,8 +281,8 @@ mod tests { git(command).1 } - /// - *Contract stamp:* ADR-006 decision 2 (the exec-only git parse - /// — the vanilla wire shape `git-upload-pack '/owner/demo'`). + /// - *Contract stamp:* ADR-006 decision 2 (the exec-only git parse: + /// the vanilla wire shape `git-upload-pack '/owner/demo'`). #[test] fn vanilla_quoted_upload_pack_parse_is_git() { let (service, repo) = git("git-upload-pack '/owner/demo'"); @@ -316,16 +316,16 @@ mod tests { assert_eq!( git_repo("git-upload-pack '/r.git.git'"), "r.git", - "one suffix only — the remainder fails validation honestly" + "one suffix only; the remainder fails validation honestly" ); assert_eq!( git_repo("git-upload-pack '/.git'"), ".git", - "the empty remainder is kept — the git row declines it, never a silent emptying" + "the empty remainder is kept (the git row declines it, never a silent emptying)" ); } - /// - *Contract stamp:* POC-3 §2 (service-only → declined — SSH + /// - *Contract stamp:* POC-3 §2 (service-only → declined: SSH /// exec must carry the repo; the decline-with-reason surface, /// not the pipe row). #[test] @@ -341,7 +341,7 @@ mod tests { } /// - *Contract stamp:* POC-3 §2 (unknown services declined - /// honestly — the decision that they take the decline surface, + /// honestly; the decision that they take the decline surface, /// not the pipe row). #[test] fn unknown_services_parse_to_the_decline() { @@ -360,7 +360,7 @@ mod tests { } /// - *Contract stamp:* mapping.md §Session-channel dispatch - /// (non-git → parse-then-fail, the pipe row — the wave-2 probe's + /// (non-git → parse-then-fail, the pipe row; the wave-2 probe's /// pinned routing verdicts, preserved). #[test] fn non_git_commands_parse_to_the_pipe_row() { @@ -378,7 +378,7 @@ mod tests { } } - /// Unterminated empty quotes are not the vanilla path shape — the + /// Unterminated empty quotes are not the vanilla path shape; the /// probe's pipe verdict applies. A quoted path without the leading /// slash is still path-shape (the POC's loose quote trim); it rides /// the grammar to the git row's validation. @@ -390,7 +390,7 @@ mod tests { } /// Quoted-empty and slash-only arguments parse as git with an empty - /// normalized id — the git row's validation declines them as + /// normalized id; the git row's validation declines them as /// `invalid-repo-id` (kept, never silently emptied). #[test] fn empty_ids_parse_git_and_the_row_downstream_declines() { @@ -399,7 +399,7 @@ mod tests { } /// - *Contract stamp:* mapping.md §Session-channel dispatch (deep - /// paths ride the grammar to the git row — validation is the + /// paths ride the grammar to the git row; validation is the /// registry-grammar gate downstream, e.g. 3 segments decline as /// `invalid-repo-id`, not at the parse). #[test] @@ -418,7 +418,7 @@ mod tests { /// - *Contract stamp:* `client.md` §op rows (the same exec /// grammar the server side parses, reused not forked); - /// ADR-006 decision 2 — the construction arm's command parses + /// ADR-006 decision 2: the construction arm's command parses /// back through [`parse_exec`] to exactly the route it was /// built from, for both services and every grammar shape. #[cfg(feature = "git")] @@ -451,7 +451,7 @@ mod tests { } } - /// - *Contract stamp:* the construction arm is grammar-loyal — + /// - *Contract stamp:* the construction arm is grammar-loyal: /// it is only ever reachable for the two *serving* services /// (the type is the gate); the wire shape is fully /// single-quote-wrapped with the leading `/`. diff --git a/src/error.rs b/src/error.rs index 5877b00..0fcc293 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,25 +1,25 @@ -//! The crate's error taxonomy — fail-closed, no catch-alls (ADR-005 +//! The crate's error taxonomy: fail-closed, no catch-alls (ADR-005 //! decision 4: the vault's error taxonomy is the adapter's to reshape, //! never to collapse). //! //! Deliberately **not** error types, per the family contracts: //! -//! - **Auth declines** — dispositions (`Auth::Reject`, ADR-004), +//! - **Auth declines**: dispositions (`Auth::Reject`, ADR-004), //! never errors; a decline is an authorized outcome, not a failure. -//! - **Wire decline reasons** — SSH-shaped responses to the client +//! - **Wire decline reasons**: SSH-shaped responses to the client //! (the wave-2 decline core's material), never this taxonomy. -//! - **Config validation** — the OQ-08/serve-config fields are +//! - **Config validation**: the OQ-08/serve-config fields are //! `Option` and decline at request time, not construction time; no //! config-error type exists unless a need is found. use thiserror::Error; /// Every way a vault-backed key source can fail to produce key -/// material (ADR-005 decision 4 — the failure matrix as distinct +/// material (ADR-005 decision 4: the failure matrix as distinct /// variants). All paths are fail-closed: a failed load never yields a /// dial, and a failed host-key load never yields a server. /// -/// The vault itself is a secret store on this path — the error +/// The vault itself is a secret store on this path; the error /// taxonomy here is the adapter's reshaping of the vault's, never a /// re-export of it. Variants are deliberately closed: no catch-all, /// no `Other`, no `Unknown`. @@ -28,14 +28,14 @@ pub enum KeySourceError { /// The vault was locked when the key was requested. /// /// ADR-005 semantics: the vault participates only at use time - /// (decrypt-at-use), so a locked vault blocks exactly that — no + /// (decrypt-at-use), so a locked vault blocks exactly that: no /// key material can be decrypted, so there is no dial; on the /// host-key path the load feeds server construction /// (decrypt-at-construction), so no server is constructed /// (POC-2 §5). Live sessions are unaffected: the decoded /// `PrivateKey` is a dial's lifetime, not a vault-coupled lease. /// - /// Fail-closed consequence: operation refused. Never unlock — + /// Fail-closed consequence: operation refused. Never unlock; /// the vault's lifecycle is the assembly's, never the adapter's. #[error("vault is locked; no key material available until unlocked")] Locked, @@ -43,7 +43,7 @@ pub enum KeySourceError { /// No blob exists at the requested key location. /// /// ADR-005 semantics: the assembly source has no - /// `EncryptedData` record for the requested key — no vault call + /// `EncryptedData` record for the requested key, so no vault call /// is needed to know (POC-2 §3). Distinct from every other /// variant on purpose: an absent key is a configuration/ /// registration gap, while a locked/decryption failure is a @@ -55,11 +55,11 @@ pub enum KeySourceError { #[error("no key material at the requested key location")] Absent, - /// Decryption failed — wrong mnemonic or tampered ciphertext. + /// Decryption failed: wrong mnemonic or tampered ciphertext. /// /// ADR-005 semantics: the AES-256-GCM open failed (POC-2 §3): /// the mnemonic derives an unrelated key, or the ciphertext was - /// altered in flight — the refuse-at-crypto class. The vault + /// altered in flight (the refuse-at-crypto class). The vault /// reports this class as opaque message text, which is the /// honest content here. /// @@ -71,31 +71,31 @@ pub enum KeySourceError { /// The record's key version is one the vault cannot resolve. /// /// ADR-005 semantics: the vault declines *before* touching - /// crypto — an unknown/unresolvable `key_version` (reserved/legacy + /// crypto: an unknown/unresolvable `key_version` (reserved/legacy /// v1 is the TS_PBKDF2 class; a future version the vault predates /// is the other class) is refused at derivation-path resolution /// (POC-2 §3). `EncryptedData` remains opaque: the crate never - /// interprets versions — this variant carries only the vault's + /// interprets versions; this variant carries only the vault's /// refusal message. /// /// Fail-closed consequence: no dial; on the host-key path, no /// server construction. Rotation (higher version the vault - /// supports) is the storage-side migration — a version the + /// supports) is the storage-side migration; a version the /// vault cannot derive never becomes a partially usable key. #[error("vault cannot resolve the record's version: {0}")] UnknownKeyVersion(String), /// The decrypted plaintext arrived but is not decodable key - /// material — the one-time [`decode_secret_key`](russh::keys::decode_secret_key) + /// material, that is, the one-time [`decode_secret_key`](russh::keys::decode_secret_key) /// failure. /// /// ADR-005 semantics: the vault decrypted *something* /// successfully and the plaintext is not an OpenSSH /// private-key PEM (decision 1's inner format). Distinct from - /// [`KeySourceError::Decryption`] on purpose — the + /// [`KeySourceError::Decryption`] on purpose: the /// custody boundary held, what was guarded is not a key. The /// underlying parse error's message is deliberately *not* - /// carried — the machinery's text can echo plaintext-shaped + /// carried, because the machinery's text can echo plaintext-shaped /// material (the `w5-fuzz-harness` finding: the `ssh-key` PPK /// path interpolates the raw header), so the payload is /// crate-owned fixed text; the RC-pinned `ssh-key` error type @@ -107,24 +107,24 @@ pub enum KeySourceError { Decode(String), } -/// The adapter (server-direction) error surface — the failure classes +/// The adapter (server-direction) error surface, the failure classes /// the mount point can reach, deliberately closed: /// -/// - **Construction** — the [`SshAdapter::new`](crate::SshAdapter::new) +/// - **Construction**: the [`SshAdapter::new`](crate::SshAdapter::new) /// setup failed *before any session exists*: a failed host-key load -/// (the [`KeySourceError`] variant is preserved verbatim — locked / +/// (the [`KeySourceError`] variant is preserved verbatim: locked / /// absent / decryption / unknown-version / decode each stays itself) /// or a refused `-R` listen-leg registration (`ListenRegistration`, -/// `w3-tunnel-listen` — a fabric that could mint listens the door +/// `w3-tunnel-listen`; a fabric that could mint listens the door /// cannot serve is worse than a half-configured adapter). -/// **No adapter is constructed** (ADR-005 decision 6 — never a +/// **No adapter is constructed** (ADR-005 decision 6: never a /// half-configured adapter, never a keyless server that fails /// later). -/// - **Wire** — the russh session stack's own error, mapped +/// - **Wire**: the russh session stack's own error, mapped /// transparently (`From`, the wave-1 error-model's /// reserved `From` requirement of the per-connection /// [`russh::server::Handler`]): KEX, transport, and IO failures of -/// a mounted session. Auth declines are *not* this class — they are +/// a mounted session. Auth declines are *not* this class; they are /// dispositions (ADR-004), and wire decline reasons are the /// dispatch's SSH-shaped responses, never this taxonomy. /// @@ -132,7 +132,7 @@ pub enum KeySourceError { /// direction can fail is one of these classes or a decline. #[derive(Debug, Error)] pub enum AdapterError { - /// The host-key load at adapter construction refused — fail-closed + /// The host-key load at adapter construction refused, fail-closed /// (ADR-005 decision 6). The [`KeySourceError`] variant is the /// original refusal class, preserved un-collapsed. #[error("ssh server construction refused: {0}")] @@ -140,14 +140,14 @@ pub enum AdapterError { /// The `-R` listen leg's door-side openable registration refused /// at construction (`w3-tunnel-listen`): fail-closed, never a - /// half-configured adapter — a construction where the fabric could + /// half-configured adapter: a construction where the fabric could /// mint listens the door cannot serve is worse than no adapter. /// The string carries the registration failure detail. /// /// This stays the construction-time class: the wire-time sibling /// (`w4-router-collision`, the `ListenRouter::register` /// token-collision refusal) is a request-time **decline - /// disposition** (`RequestDenied`, reason `token-collision`) — + /// disposition** (`RequestDenied`, reason `token-collision`); /// a global-request hook's `Err` (this taxonomy's only route into /// the request surface) would kill the whole russh session, and /// wire decline reasons are never this taxonomy. @@ -160,53 +160,53 @@ pub enum AdapterError { } /// The dial surface's failure classes (the client direction's error -/// counterpart of [`AdapterError`]) — deliberately closed, every +/// counterpart of [`AdapterError`]), deliberately closed, every /// variant a no-connection outcome (ADR-005 decision 4: failures are /// fail-closed and distinct, never collapsed, never a fallback dial): /// -/// - **KeySource** — the decrypt-at-dial load refused. The +/// - **KeySource**: the decrypt-at-dial load refused. The /// [`KeySourceError`] variant is preserved verbatim (locked / absent -/// / decryption / unknown-version / decode each stays itself — the +/// / decryption / unknown-version / decode each stays itself, the /// ADR-005 decision 4 matrix read through the dial seam). No key /// material, no dial. -/// - **Address** — the dial target is not a parseable `host:port`. +/// - **Address**: the dial target is not a parseable `host:port`. /// Checked at dial time (the config carries no construction-time /// validation, the family contract); a malformed target is a /// refusal before any connection. -/// - **HostKeyRejected** — the injected host-key policy +/// - **HostKeyRejected**: the injected host-key policy /// ([`crate::HostKeyPolicy`]) declined the presented server key at /// `check_server_key` (a `false` verdict is the decline /// disposition; russh surfaces it as its `UnknownKey` wire error, /// which this crate maps here because that hook is the only -/// producer). The trust decision is the policy's — its own record +/// producer). The trust decision is the policy's; its own record /// (its decision log) carries the reasons; the crate never /// second-guesses or retries. -/// - **AuthRejected** — the remote end refused the publickey +/// - **AuthRejected**: the remote end refused the publickey /// authentication (the family contract is exactly one /// publickey-only attempt; there is no retry, no fallback method). -/// - **Wire** — the russh session stack's own error, mapped +/// - **Wire**: the russh session stack's own error, mapped /// transparently, including the dial's connect/resolve/IO classes. #[derive(Debug, Error)] pub enum DialError { - /// The dial key's decrypt-at-dial load refused — every + /// The dial key's decrypt-at-dial load refused; every /// [`KeySourceError`] variant is a no-dial outcome, preserved /// un-collapsed (ADR-005 decision 4). #[error("dial key source refused: {0}")] KeySource(#[from] KeySourceError), - /// The dial target is not a parseable `host:port` address — the + /// The dial target is not a parseable `host:port` address, so the /// wire never dialed. The string carries the address as given. #[error("dial target is not a usable host:port address: {0}")] Address(String), - /// The host-key policy declined the presented server key — the + /// The host-key policy declined the presented server key, so the /// dial aborts (a disposition the dial cannot proceed on; the /// crate default [`RejectAll`](crate::RejectAll) policy makes /// every dial refuse, by design). #[error("host-key policy declined the presented server key")] HostKeyRejected, - /// The remote end refused the publickey authentication — the + /// The remote end refused the publickey authentication; this is /// family's one-attempt publickey-only posture (no retries, no /// fallback methods, never another key). #[error("authentication was refused by the remote end")] @@ -224,7 +224,7 @@ impl From for DialError { /// The transparent russh mapping with one semantic upgrade: /// `UnknownKey` is the wire shape of a host-key policy decline /// (the client's `check_server_key` hook is the only producer), - /// so it becomes [`DialError::HostKeyRejected`] — every other + /// so it becomes [`DialError::HostKeyRejected`]; every other /// error stays the transparent [`DialError::Wire`] class. fn from(error: russh::Error) -> Self { match error { @@ -235,22 +235,22 @@ impl From for DialError { } /// The family-typed mirror of the SSH `CHANNEL_OPEN` rejection -/// reasons (RFC 4250 §1.5 / RFC 4254 §5.2) — the op rows translate +/// reasons (RFC 4250 §1.5 / RFC 4254 §5.2); the op rows translate /// the wire's typed-open decline into this closed vocabulary /// (`client.md` §op rows: the family surface carries no vanilla types). /// The mapping is one-to-one with russh's /// [`russh::ChannelOpenFailure`], whose `Other` arm mirrors its -/// `code`/`reason` pair verbatim — a decline reason the client +/// `code`/`reason` pair verbatim, so a decline reason the client /// *could not map* is never silently collapsed onto a known class. #[derive(Debug, Clone, Error, PartialEq, Eq)] pub enum OpenDeclineReason { - /// The SSH `administratively prohibited` class — a policy + /// The SSH `administratively prohibited` class: a policy /// refusal at the server (the door's own unfeatured/cap /// declines answer with this family's server-direction mirror). #[error("the server refused the open (administratively prohibited)")] Prohibited, - /// The SSH `connect failed` class — the target could not be + /// The SSH `connect failed` class: the target could not be /// bridged (a dead `-L` target, an impossible one). #[error("the server rejected the open (connect failed)")] ConnectFailed, @@ -263,7 +263,7 @@ pub enum OpenDeclineReason { #[error("the server rejected the open (resource shortage)")] ResourceShortage, - /// A rejection reason with no standard code — the wire's own + /// A rejection reason with no standard code: the wire's own /// `code`/`reason` pair rides (the mirror never invents a class /// for an unmappable one). #[error("the server rejected the open (code {code}: {reason})")] @@ -283,12 +283,12 @@ impl From for OpenDeclineReason { } } -/// The client direction's op-row failure classes (`w4-op-rows`) — +/// The client direction's op-row failure classes (`w4-op-rows`), /// the exec/pty / tunnel / git-pack op surfaces' closed taxonomy -/// (`RemoteSession` / `TunnelChannel` / `GitPackSession` — the +/// (`RemoteSession` / `TunnelChannel` / `GitPackSession`, the /// feature-gated members live in the crate root's exports), deliberately distinct from [`DialError`]: /// an op runs on an *already-dialled* connection, so its failure is -/// never a no-connection outcome — the connection stays usable +/// never a no-connection outcome: the connection stays usable /// ([`OpError::OpenDeclined`] / [`OpError::RequestRefused`] and /// [`OpError::ChannelEnded`] are channel/op-scoped, mirroring the /// server direction's decline shapes: channel-scoped, auth intact, @@ -299,7 +299,7 @@ impl From for OpenDeclineReason { /// #[derive(Debug, Error)] pub enum OpError { - /// The server refused the op's **channel open** — the typed + /// The server refused the op's **channel open**, the typed /// open's decline (POC-1 §6: a rejected open resolves on the /// awaiting call, never a `wait()` match). The family-mirrored /// reason rides; the connection stays usable (row-pinned). @@ -307,7 +307,7 @@ pub enum OpError { OpenDeclined(#[from] OpenDeclineReason), /// The server refused the op's **request** on the opened channel - /// — the SSH-REQUEST reply's `Failure` class, observed through + /// in the SSH-REQUEST reply's `Failure` class, observed through /// the `wait()`-drain (POC-3 §D.3: Success/Failure arrive on the /// channel queue, not as `Err` from the request call). The /// channel is closed behind the refusal (the row owned it). @@ -315,26 +315,26 @@ pub enum OpError { RequestRefused, /// The channel ended before the op's request reply arrived (the - /// `wait()`-drain saw the channel's end) — the op cannot + /// `wait()`-drain saw the channel's end); the op cannot /// proceed, nothing is fabricated. #[error("the channel ended before the op's request reply arrived")] ChannelEnded, /// The op's command exceeds the exec-length budget - /// (`Limits::max_exec_command_len`) — the per-length cap's + /// (`Limits::max_exec_command_len`): the per-length cap's /// client-mirror verdict, answered **before any wire op** (bounded /// resources; the server direction's pre-parse cap mirrored at /// the client's command-construction gate). #[error("the op's command exceeds the configured exec-command length cap")] CommandTooLong, - /// The git row's repo id is outside the ADR-008 grammar — the + /// The git row's repo id is outside the ADR-008 grammar, the /// git row's validation gate mirrored (the server direction's /// `repo_id_validates` verdict), answered before any wire op. #[error("the repository id is outside the repo-id grammar")] InvalidRepoId, - /// Unix sockets are unavailable on this platform — the + /// Unix sockets are unavailable on this platform; this is the /// `direct-streamlocal` twin's runtime-Unix gate (OQ-11: /// universal compile, clean off-Unix decline **before any wire /// op**), mirrored from the server direction's gate. @@ -344,7 +344,7 @@ pub enum OpError { /// The reverse-forward op's channel type has **no acceptor /// registered** (ADR-003 §4's client-side gate surfaced to the /// *issuing* side: a reverse listen whose data leg could not serve - /// arrivals is issued never — the half-capability posture, + /// arrivals is issued never; the half-capability posture, /// answered before any wire op). Featured-but-unregistered is the /// exact class: the unset-declines convention mirrored (the /// acceptor slots are assembly-mutable, install-first is the @@ -353,27 +353,27 @@ pub enum OpError { NoAcceptor, /// The peer refused the op's reverse-forward global request (the - /// `RequestDenied` wire decline class) — a listen denial or the + /// `RequestDenied` wire decline class); a listen denial or the /// cancel forms' unknown-listener answer (sshd parity: match by /// the raw wire strings). Channel-scoped honesty: the connection /// stays usable (row-pinned), and the wire's own reason classes - /// are never invented here — the closed family class mirrors the + /// are never invented here; the closed family class mirrors the /// wire shape, `RequestRefused`'s global-request counterpart. #[error("the peer refused the reverse-forward request")] ListenRefused, /// The op's reverse-listen admission hit the connection's /// dedicated listener ceiling (the listener counter sharing - /// `Limits::max_concurrent_channels` — the server-side + /// `Limits::max_concurrent_channels`, the server-side /// listener-counter posture mirrored; the cap relation recorded in - /// `client_accept.rs`) — answered **before any wire op**: a + /// `client_accept.rs`), answered **before any wire op**: a /// request the budget cannot track is issued never. #[error("the connection's reverse-listen count is at its ceiling")] ListenCapExceeded, /// The sftp route is the OQ-13 decline placeholder (the feature /// exists, the route does not until alkfs lands, on either - /// direction) — answered before any wire op, never a + /// direction), answered before any wire op and never a /// half-opened subsystem channel. #[error("the sftp route is not served (the OQ-13 decline placeholder)")] SftpNotServed, @@ -389,7 +389,7 @@ impl From for OpError { /// `russh::Error::ChannelOpenFailure` and maps to /// [`OpError::OpenDeclined`] (family-mirrored /// [`OpenDeclineReason`]); a denied reverse-forward *global* - /// request (`RequestDenied` — the listen/cancel forms' only wire + /// request (`RequestDenied`, the listen/cancel forms' only wire /// decline shape at this pin, the rows' only producer) maps to /// [`OpError::ListenRefused`]; every other russh error stays the /// transparent [`OpError::Wire`]. @@ -510,7 +510,7 @@ mod tests { } /// The host-key policy's `false` verdict is russh's `UnknownKey` - /// wire error — the client's `check_server_key` hook is the only + /// wire error; the client's `check_server_key` hook is the only /// producer, so the transparent mapping upgrades exactly that one /// class and leaves everything else `Wire`. /// @@ -602,7 +602,7 @@ mod tests { /// - *Contract stamp:* `client.md` §op rows (no vanilla-concept /// leaks up) + POC-1 §6 (the typed open's decline resolves on - /// the awaiting call) — the wire class mirrors one-to-one into + /// the awaiting call); the wire class mirrors one-to-one into /// the family vocabulary, `Other` verbatim, nothing collapsed. #[test] fn open_decline_mirror_preserves_every_class() { @@ -653,7 +653,7 @@ mod tests { } /// - *Contract stamp:* the reverse-forward global request's wire - /// decline class (`RequestDenied` — the listen/cancel forms' + /// decline class (`RequestDenied`, the listen/cancel forms' /// only producer shape at this pin): `ListenRefused`, never the /// transparent wire class; the typed-open mapping unchanged. #[test] @@ -662,7 +662,7 @@ mod tests { assert!(matches!(mapped, OpError::ListenRefused), "got {mapped:?}"); } - /// - *Contract stamp:* POC-1 §6 — a rejected channel open + /// - *Contract stamp:* POC-1 §6, in which a rejected channel open /// surfaces on the awaiting typed call as /// `russh::Error::ChannelOpenFailure(..)`; the op rows map it /// into [`OpError::OpenDeclined`] and every other wire error diff --git a/src/exit_code.rs b/src/exit_code.rs index 6db084f..ffce29f 100644 --- a/src/exit_code.rs +++ b/src/exit_code.rs @@ -1,4 +1,4 @@ -//! The exit-currency module — mapping.md §Exit chunk's derivation +//! The exit-currency module: mapping.md §Exit chunk's derivation //! contract (rules 1–6, normative) as code, *shared by both //! directions* (`w4-op-rows` extracted it out of `tty_map.rs`, whose //! server-side session rows were its first and only consumer). @@ -12,27 +12,27 @@ //! exactly one SSH exit report shape, **never widened**. //! - **The client direction** (`w4-op-rows`): the SSH exit report → //! the family `i32` code ([`signal_code_from_name`] and the -//! direct `u32 → i32` identity) — the exact inverse arm, riding the +//! direct `u32 → i32` identity), the exact inverse arm riding the //! same table. The mirror consumes the convention as-is, including -//! its one collision (the `−1` sentinel vs a genuine SIGHUP — +//! its one collision (the `−1` sentinel vs a genuine SIGHUP; //! mapping.md rule 3's symmetric-fidelity cost). //! //! No widening in either arm: the chunk is not enriched, the wire //! report is not enriched, and the *core_dumped* bool is never -//! asserted (alktty discards it — nothing better is knowable). +//! asserted (alktty discards it; nothing better is knowable). //! //! ## The server arm's rules (mapping.md, normative) //! //! 1. `code ≥ 0` → `exit-status(N)`. //! 2. negative `−N`, N ≥ 2 → `exit-signal(name)` via the crate-local //! **Unix signum→name table** ([`SIGNAL_NAMES`]). Server-side -//! work — the signal semantics belong to the serving platform +//! work: the signal semantics belong to the serving platform //! where the backend reaps. Deliberately *not* derived from //! alktty's `signal_from_name` inverse, which is a forward //! name→number map for the control row, not a derivation table. -//! `core_dumped` is **never asserted** — SSH's `exit-signal` bool +//! `core_dumped` is **never asserted**; SSH's `exit-signal` bool //! stays false on every row. -//! 3. `−1` → `exit-status(255)`, never a signal claim — the +//! 3. `−1` → `exit-status(255)`, never a signal claim: the //! could-not-determine sentinel collides with the SIGHUP encoding //! on the pipe path, accepted symmetrically per the mapping: //! neither a fabricated signal for a wait failure nor a real one. @@ -41,13 +41,13 @@ //! 5. **The PTY-path fidelity limit (upstream)**: portable-pty 0.9 //! reaps a signal-terminated Unix child as a plain code (the //! signal number is unrecoverable through its trait surface), so -//! signal-terminated PTY sessions arrive as `exit-status(1)` — a +//! signal-terminated PTY sessions arrive as `exit-status(1)`, a //! documented alktty/portable-pty ask; this table in practice //! sees the *pipe* path's negative encoding only. Faithful //! `exit-signal` there needs the alktty backend to conform to its //! own ADR's negative-code convention; alkssh's contract adapts //! automatically. -//! 6. Unmapped negatives → rule 3 (`exit-status(255)`) — the mapping +//! 6. Unmapped negatives → rule 3 (`exit-status(255)`); the mapping //! never invents a name (defensive case: the convention's //! producers are `−1` and `−signum` only). //! @@ -56,26 +56,26 @@ //! 1. `exit-status(N)` → the family code `N` (direct identity). //! 2. `exit-signal(name)` → the family code `−N` via the same //! [`SIGNAL_NAMES`] table read backwards -//! ([`signal_code_from_name`]) — the mapping never invents a +//! ([`signal_code_from_name`]); the mapping never invents a //! signum. //! 3. A name with no table entry → `−1` (the sentinel; the same //! honest could-not-determine semantic rule 3 consumes on the -//! server arm — including a genuine SIGHUP, whose mirror rides +//! server arm, including a genuine SIGHUP, whose mirror rides //! `−1` by the same accepted collision). -//! 4. No exit report at all ends a session with none — the +//! 4. No exit report at all ends a session with none, the //! no-exit-chunk close family's mirror ("reports nothing", //! mapping.md): the caller observes the session's end, never a //! fabricated code. -/// One SSH exit report shape derived from an exit chunk — +/// One SSH exit report shape derived from an exit chunk; /// [`derive_exit`]'s outcome. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg(feature = "session")] pub(crate) enum ExitReport { - /// `exit-status(N)` — codes ≥ 0, the `−1` sentinel, and every + /// `exit-status(N)`: codes ≥ 0, the `−1` sentinel, and every /// unmapped negative (rules 1, 3, 4, 6). Status(u32), - /// `exit-signal(name)` — a mapped negative `−N`, N ≥ 2 (rule 2). + /// `exit-signal(name)`: a mapped negative `−N` where N ≥ 2 (rule 2). /// The name is the table's value, never an invention. Signal(&'static str), } @@ -83,11 +83,11 @@ pub(crate) enum ExitReport { /// The crate-local Unix signum→name table (server arm rule 2 / client /// arm rule 2): the 1–31 conventional Unix signals, as the exit /// chunk's producers encode them (`−signum`) and as the wire's -/// `exit-signal` senders name them. Server-side work — the signal +/// `exit-signal` senders name them. Server-side work: the signal /// semantics belong to the serving platform where the backend reaps. /// Deliberately **not** derived from alktty's `signal_from_name` (a /// forward name→number map for the control row, not a derivation -/// table; deliberately narrower too — it exists for what a front-end +/// table; deliberately narrower too, existing for what a front-end /// sends, not for what a child can die by). pub(crate) const SIGNAL_NAMES: &[(u32, &str)] = &[ (1, "HUP"), @@ -124,7 +124,7 @@ pub(crate) const SIGNAL_NAMES: &[(u32, &str)] = &[ ]; /// The derivation contract's whole decision procedure (the §module -/// docs' rules 1–6 — normative). +/// docs' rules 1–6; normative). #[cfg(feature = "session")] pub(crate) fn derive_exit(code: i32) -> ExitReport { match code { @@ -143,7 +143,7 @@ pub(crate) fn derive_exit(code: i32) -> ExitReport { /// The client arm's inverse read (§module docs, rules 1–3): the SSH /// `exit-signal` sender's name → the family exit-code convention's /// value (`−signum`), `−1` for a name with no table entry (the -/// sentinel — the mapping never invents a signum; a genuine SIGHUP +/// sentinel; the mapping never invents a signum, and a genuine SIGHUP /// rides it by the same accepted collision). pub(crate) fn signal_code_from_name(name: &str) -> i32 { match SIGNAL_NAMES.iter().find(|(_, n)| *n == name) { @@ -155,7 +155,7 @@ pub(crate) fn signal_code_from_name(name: &str) -> i32 { /// The table's name → russh's `Sig` vocabulary (the /// `exit_signal_request` parameter). russh's known set rides its /// variant names; anything else rides `Sig::Custom` (RFC 4254 §6.10's -/// signal-name encoding — vanilla clients parse arbitrary names). +/// signal-name encoding, since vanilla clients parse arbitrary names). #[cfg(feature = "session")] pub(crate) fn sig_from_name(name: &str) -> russh::Sig { match name { @@ -177,7 +177,7 @@ pub(crate) fn sig_from_name(name: &str) -> russh::Sig { /// The SSH signal row's name translation: russh's `Sig` → the name /// string alktty's control vocabulary carries (the uppercase names; -/// `Custom` carrying its own). Names flow to the backend verbatim — +/// `Custom` carrying its own). Names flow to the backend verbatim, /// no alkssh-side filter (mapping.md §the control rows; the client /// arm's `exit-signal` consumption reads through this before /// [`signal_code_from_name`]). @@ -207,7 +207,7 @@ mod tests { use russh::Sig; /// - *Contract stamp:* mapping.md §Exit chunk rule 1 (`code ≥ 0` - /// → `exit-status(N)` — the chunk carries the whole truth for + /// → `exit-status(N)`; the chunk carries the whole truth for /// clean exits). #[test] fn non_negative_codes_map_to_exit_status() { @@ -218,8 +218,8 @@ mod tests { } /// - *Contract stamp:* mapping.md §Exit chunk rule 2 (negative - /// `−N`, N ≥ 2 → `exit-signal(name)` via the table — the POC-3 - /// §D.2 live evidence: `−15` → `exit-signal("TERM")`). + /// `−N`, N ≥ 2 → `exit-signal(name)` via the table; the POC-3 + /// §D.2 live evidence is `−15` → `exit-signal("TERM")`). #[test] fn negative_signals_map_through_the_table() { for (signum, name) in SIGNAL_NAMES.iter().skip(1) { @@ -230,7 +230,7 @@ mod tests { } /// - *Contract stamp:* mapping.md §Exit chunk rule 3 (`−1` → - /// `exit-status(255)`, never a signal claim — the sentinel/ + /// `exit-status(255)`, never a signal claim; the sentinel/ /// SIGHUP collision accepted symmetrically). #[test] fn the_sentinel_is_not_a_signal() { @@ -238,7 +238,7 @@ mod tests { } /// - *Contract stamp:* mapping.md §Exit chunk rule 6 (unmapped - /// negatives → rule 3 — the mapping never invents a name). + /// negatives → rule 3; the mapping never invents a name). #[test] fn unmapped_negatives_report_255() { for code in [i32::MIN, -33, -32, -100, -1_000_000] { @@ -246,7 +246,7 @@ mod tests { } } - /// - *Contract stamp:* the table bound — every entry is the + /// - *Contract stamp:* the table bound: every entry is the /// conventional Unix signal set 1–31, sorted, names unique and /// uppercase (the vocabulary the derivation table promises). #[test] @@ -282,7 +282,7 @@ mod tests { } } -/// The client arm's mirror row — runnable in every build the arm +/// The client arm's mirror row, runnable in every build the arm /// compiles in (session or git; the git-only builds carry the client /// rows too). #[cfg(test)] @@ -290,7 +290,7 @@ mod tests { mod client_arm_rows { use super::SIGNAL_NAMES; - /// - *Contract stamp:* the client arm (§module docs' rules 1–3) — + /// - *Contract stamp:* the client arm (§module docs' rules 1–3), /// the inverse read through the same table, never widened: /// mapped names ride `−signum`, unmapped names ride the `−1` /// sentinel (the mapping never invents a signum). diff --git a/src/fingerprint.rs b/src/fingerprint.rs index ebc4b4f..b11fa61 100644 --- a/src/fingerprint.rs +++ b/src/fingerprint.rs @@ -6,7 +6,7 @@ //! path (client) surfaces it at `check_server_key`, and assembly //! registrations store it as a string. The string format //! (`SSHFP`-style `SHA256:` prefix over the OpenSSH wire-key digest, -//! unpadded base64) is a **contract invariant** — registration strings +//! unpadded base64) is a **contract invariant**: registration strings //! from any standard issuer (`ssh-keygen -lf`, alkcall-side //! computation) must compare equal to what this crate computes. //! @@ -17,13 +17,13 @@ use russh::keys::{HashAlg, PublicKey}; -/// Computes a public key's fingerprint — the single fingerprint path +/// Computes a public key's fingerprint, the single fingerprint path /// in the crate (ADR-004 decision 1's contract invariant). /// /// The returned string is the OpenSSH fingerprint format: `SHA256:` /// followed by the unpadded base64 of the SHA-256 digest over the /// key's OpenSSH wire encoding, byte-identical to independent issuers -/// (`ssh-keygen -lf`) — parity is proven, not assumed. Every +/// (`ssh-keygen -lf`); parity is proven, not assumed. Every /// fingerprint comparison in the crate and every registration value an /// assembly stores is this string; no other formatting path exists. pub fn fingerprint(public_key: &PublicKey) -> String { diff --git a/src/git_map.rs b/src/git_map.rs index 41a3747..1af62ea 100644 --- a/src/git_map.rs +++ b/src/git_map.rs @@ -1,4 +1,4 @@ -//! The git mapping (`w3-git-mapping`) — the git branch of the spine +//! The git mapping (`w3-git-mapping`), the git branch of the spine //! (ADR-006 decision 2, exec-only, the alkforge primary purpose): the //! dispatch's [`ExecRoute::Git`](crate::dispatch::ExecRoute) route //! dispatches to the published alkgit seam, @@ -10,33 +10,33 @@ //! //! ## The decisions recorded here (the task's decide-and-record set) //! -//! - **Repo id — validate, never resolve.** The parse stage +//! - **Repo id: validate, never resolve.** The parse stage //! ([`crate::dispatch`]) normalizes the wire path; this stage //! validates the id against `alkgit::validate_repo_id` (1–2 -//! segments, charset `a-z0-9-_`, ≤ 100 bytes — the ADR-008 +//! segments, charset `a-z0-9-_`, ≤ 100 bytes, the ADR-008 //! repo-id grammar) and hands it through untouched to //! `serve_duplex_resolved`. **alkssh never resolves**: the //! resolution, the authorize policy and the collapsed generic //! denial (unknown ≡ unauthorized, one wire shape, no existence //! oracle) live at the seam. An id failing the *shape* gate is -//! declined here — `invalid-repo-id`, request-level, reason-only on +//! declined here as `invalid-repo-id`, request-level, reason-only on //! the wire (the reply-vocabulary decision in [`crate::dispatch`]). //! //! - **Wire shapes per decline class** (the open/reply vocabulary): -//! - *Request-level* declinables (`unknown-service`, `service-only` -//! — the parse core's; `invalid-repo-id` — this module's gate): +//! - *Request-level* declinables (`unknown-service` and `service-only` +//! from the parse core; `invalid-repo-id` from this module's gate): //! `channel_failure`, channel left usable. The reply vocabulary is //! shared with parse-then-fail; the reason lives in the events //! only. //! - *Serving-path* declines (the row owned the channel): //! seam-unconfigured (feature on, [`crate::GitSeam`] absent) and -//! the identity-less guard — failure + close, from the spawned +//! the identity-less guard, failure + close from the spawned //! task, the wave-2 seam-stub shape. //! - *The seam's own denials* are not alkssh declines: an unknown or //! ungranted repo flows to `serve_duplex_resolved`, whose //! collapsed generic denial writes the `ERR access denied: ` //! band over the channel **before any pack/ref byte** -//! (`SubstrateError::AccessDenied`) — the POC-3 §A.5 byte-order +//! (`SubstrateError::AccessDenied`); the POC-3 §A.5 byte-order //! evidence, contract-pinned by the denial rows in //! `tests/git_mapping.rs`. //! @@ -45,7 +45,7 @@ //! built from the channel's **split halves**, never //! `Channel::into_stream()`. `into_stream` wraps the whole channel //! in russh's `ChannelCloseOnDrop`, whose `Drop` sends -//! server→client `CHANNEL_CLOSE` from a *spawned task* — inside the +//! server→client `CHANNEL_CLOSE` from a *spawned task* inside the //! seam call, racing [`serve_git_row`]'s explicit //! `exit_status_request` for a queue position on the same bounded //! `Sender` (russh's `event_buffer_size`, default 10): a full @@ -53,7 +53,7 @@ //! let the loop remove the channel, and silently no-op the report. //! The split-halves shape removes the competitor instead of racing //! it: russh 0.65 keeps its `ChannelRx`/`ChannelTx` private, so -//! [`GitChannelDuplex`] is built from the public API — the reader +//! [`GitChannelDuplex`] is built from the public API: the reader //! is the module's [`ChannelHalveReader`] (an owned read half //! repinning the private `ChannelRx`'s observation semantics //! without the close-on-drop wrapper; its only `Drop` behavior @@ -62,14 +62,14 @@ //! sends EOF, exactly `into_stream`'s). Nothing the seam drops ever //! messages the wire, so the report's send is the sole //! close-contracting sender, and its queue position ahead of the -//! explicit close holds by construction — sequential awaited sends +//! explicit close holds by construction: sequential awaited sends //! on the one `Handle`, saturated buffer or not. The tty rows are //! not in this class: their report precedes any close-contracting -//! drop within one task — the wave-3 gate verified. +//! drop within one task (the wave-3 gate verified). //! //! - **Exit-status mapping** (POC-3 §A.5, decided): //! [`serve_git_row`] maps the serve outcome onto exactly two -//! codes — `Ok(())` → `exit-status(0)` (vanilla git exits 0 on +//! codes: `Ok(())` → `exit-status(0)` (vanilla git exits 0 on //! success) and every `SubstrateError` → `exit-status(1)`. `1` for //! `AccessDenied` is the POC's wire evidence (the russh client //! observed `ExitStatus{1}` after the denial band); `Io`/`Protocol` @@ -77,32 +77,32 @@ //! machinery-misuse variants (`ResetRequired`/`WriterTaken`/ //! `RawTailUnavailable`) never arise from the serving entry //! (substrate-internal misuse, never a wire shape) and are -//! defensively mapped to `1`. `255` is never fabricated — it is +//! defensively mapped to `1`. `255` is never fabricated; it is //! OpenSSH's could-not-start semantic, which this door never claims. //! The status is sent **before** close, from the spawned serving //! task via the cloned `Session::handle()` //! ([`crate::serve`]'s mechanics; `mapping.md`'s exit_status row). //! //! - **Identity ride** (`w2-auth-bridge`'s parked item, discharged -//! here): the resolved identity — the bridge's -//! `auth_succeeded`-state ride-along in handler state — is cloned +//! here): the resolved identity (the bridge's +//! `auth_succeeded`-state ride-along in handler state) is cloned //! into the serving task and passed on //! `serve_duplex_resolved`'s identity param, so the visible-surface //! invariant is observable through the git row: alkgit's //! `authorize` evaluation is the live witness (a granted-private -//! repo serves, an ungranted one denies — the harness rows pin +//! repo serves, an ungranted one denies; the harness rows pin //! both). A handler state without an identity is unreachable (russh //! authorizes before channels exist) and declines serving-path -//! (`no-identity`) — never anonymous serving. +//! (`no-identity`), never anonymous serving. //! //! - **Process-mode dialect**: alkgit speaks first (fetch: the V2 //! advertisement, no `# service=` prefix; push: the V0 ref -//! advertisement) — nothing alkssh-side; the byte-level rows in +//! advertisement), nothing alkssh-side; the byte-level rows in //! `tests/git_mapping.rs` verify the dialect holds over the channel //! duplex. //! //! The serve outcome's event shape: the serving-path lifecycle only -//! (started / ended — the vocabulary's `warn`-failed when the wire +//! (started / ended, with the vocabulary's `warn`-failed when the wire //! reporting breaks). A serve `Err` is *not* a decline event: the //! substrate already mapped its own error onto the wire (bands, the //! denial), and the client's observation is the exit-status above. @@ -123,7 +123,7 @@ use crate::dispatch::GitServiceRoute; use crate::observe; /// The git row's validation gate: the id's shape against -/// `alkgit::validate_repo_id` — the ADR-008 repo-id grammar for +/// `alkgit::validate_repo_id`, the ADR-008 repo-id grammar for /// *rejection* only (the mapping-free posture; the id is never /// decomposed, joined, or normalized into paths beyond /// [`crate::dispatch`]'s quote/slash/`.git` stage). @@ -150,13 +150,13 @@ fn exit_code(outcome: &Result<(), SubstrateError>) -> u32 { } } -/// The seam's duplex over the **split** channel halves — the +/// The seam's duplex over the **split** channel halves, the /// status-before-close shape's carrier (the module doc's /// §Status-before-close decision). russh 0.65 keeps its `ChannelRx`/ /// `ChannelTx` types private, so both halves are built from public /// API: the reader is a [`ChannelHalveReader`] (an owned close-free /// read half), the writer the write half's `ChannelTx` via -/// `make_writer_ext(None)` — its `poll_shutdown` sends EOF, exactly +/// `make_writer_ext(None)`; its `poll_shutdown` sends EOF, exactly /// `into_stream`'s semantics, its `Drop` messages nothing (the /// `ChannelTx` `Drop` is a writer-notification only). Nothing the /// seam drops ever messages the wire, so the report's send is the @@ -195,20 +195,20 @@ impl AsyncWrite for GitChannelDuplex { } } -/// The owned close-free read half — the seam-side reader. Semantics +/// The owned close-free read half, the seam-side reader. Semantics /// repinned from russh's private `ChannelRx` (the `into_stream` /// shape's reader; identical observable behavior without the /// `ChannelCloseOnDrop` wrapper): `Data` fills the buffer (partial /// reads buffered), `ExtendedData` with no sideband and the other /// non-data messages are swallowed and re-read (the `_` arm), /// `Eof` ends the stream, and the peer's `Close` leaves the reader -/// to the channel's sender-death EOF (`wait()` → `None` — the -/// channel's internal sender drops at the loop's close processing). +/// to the channel's sender-death EOF (`wait()` → `None`, the +/// channel's internal sender dropping at the loop's close processing). /// /// The `wait()` access is future-owned: each read round-trips the /// half through a boxed [`Future`] that parks it inside russh's /// `ChannelReadHalf::wait` and hands it back with the observed -/// message on completion — the reader is fully owned (usable under +/// message on completion; the reader is fully owned (usable under /// the seam's `'static` `T` bound) across every park, buffer and /// drop state; no `Drop` path ever messages the wire. struct ChannelHalveReader { @@ -296,15 +296,15 @@ fn git_channel_duplex(channel: Channel) -> GitChannelDuplex { } /// The spawned git serving path: dispatch to the seam over the -/// [`git_channel_duplex`] (the split halves — the seam contracts +/// [`git_channel_duplex`] (the split halves; the seam contracts /// nothing on its drops), then the exit-status-then-close report -/// through the cloned handle — the report's send is the sole +/// through the cloned handle; the report's send is the sole /// close-contracting sender and each send awaits before the next is /// issued, so the status-before-close order holds by construction /// under any schedule. The channel was taken from the handler's store /// by the dispatch (the store-and-take handoff); the spawned task owns /// the halves and their report surface. A failing report send means -/// the session is gone — the lifecycle's `warn`-failed records it (the +/// the session is gone; the lifecycle's `warn`-failed records it (the /// one warn of the vocabulary). pub(crate) async fn serve_git_row( handle: Handle, diff --git a/src/handler.rs b/src/handler.rs index 8a180f2..486a80b 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,4 +1,4 @@ -//! The per-connection server handler — the ADR-004 dispositional auth +//! The per-connection server handler: the ADR-004 dispositional auth //! bridge, plus the exec-grammar dispatch and the fail-closed decline //! core (`w2-dispatch-decline-core`; `w2-auth-bridge` filled the auth //! hooks; `w3-git-mapping` replaced the skeleton probe with the full @@ -9,30 +9,30 @@ //! //! russh performs all cryptographic work: [`Handler::auth_publickey`] //! fires *after* signature and ownership verification, so this handler -//! never sees or verifies a signature — its surface is dispositions +//! never sees or verifies a signature; its surface is dispositions //! only. The single resolution path: ed25519-only gate → the crate's //! one fingerprint path ([`crate::fingerprint::fingerprint`]) → the //! injected `IdentityProvider::resolve_from_fingerprint` → `Some` //! accepts with the resolved identity stored in per-connection handler -//! state (it rides the session for the wave-3 seam propagation — +//! state (it rides the session for the wave-3 seam propagation, //! [`Handler::auth_succeeded`] is the ride-along hook); `None` rejects -//! fail-closed — the resolved-identity-`None` path never creates a +//! fail-closed; the resolved-identity-`None` path never creates a //! weakly authorized session. //! -//! Every other method is an **explicit** reject — [`Handler::auth_none`], +//! Every other method is an **explicit** reject: [`Handler::auth_none`], //! [`Handler::auth_password`] and [`Handler::auth_keyboard_interactive`] -//! each implemented, never inherited — so the posture survives a pin +//! each implemented, never inherited, so the posture survives a pin //! bump that could silently change russh's defaults (ADR-004 decision //! 3). The non-ed25519 algorithm decline is explicit-over-inherited too //! (ADR-002 decision 4). [`Handler::auth_publickey_offered`] -//! accepts-and-delegates explicitly (the probe hook consumes no attempt -//! — POC-1 verified; the delegation keeps `max_auth_attempts` counting +//! accepts-and-delegates explicitly (the probe hook consumes no attempt, +//! POC-1 verified; the delegation keeps `max_auth_attempts` counting //! honest). //! //! The username carries no semantics (OQ-03 resolved): resolution is -//! fingerprint-only — the bridge core takes no username parameter at +//! fingerprint-only; the bridge core takes no username parameter at //! all, structurally refusing any identity input from the user string. -//! Auth declines are *dispositions* (`Auth::Reject`), not errors — the +//! Auth declines are *dispositions* (`Auth::Reject`), not errors; the //! error model stays key-source-only. //! //! ## The parse-only dispatch + the fail-closed decline core @@ -41,23 +41,23 @@ //! exec-parse skeleton probe live in [`crate::dispatch`].) Every //! `channel_open_*` hook gates per the feature graph: `session` //! channels open only where a session-serving feature exists (`session` -//! ∨ `git` — the parse path lives inside session channels); +//! ∨ `git`, since the parse path lives inside session channels); //! `direct-tcpip` / `forwarded-tcpip` / `direct-streamlocal` gate on -//! the `tunnel` feature; **`x11` always declines** — never +//! the `tunnel` feature; **`x11` always declines**, never //! feature-gated (ADR-003 §5). Unfeatured and never-feature rows //! decline **at the open** with a clean wire reason -//! ([`crate::dispatch::unfeatured_open_decline`]) — never a +//! ([`crate::dispatch::unfeatured_open_decline`]), never a //! half-open channel. The `direct-tcpip` / `direct-streamlocal` //! featured rows are the route-1 bridge (`w3-tunnel-direct`, //! [`crate::tunnel_map`]): the pre-admit decline classes (the unset -//! fabric handle under the feature — the unset-declines posture; the +//! fabric handle under the feature, the unset-declines posture; the //! unreachable-in-practice `no-identity`; an impossible wire target), -//! the cap admission at the hook, then the spawned bridge — accept +//! the cap admission at the hook, then the spawned bridge; accept //! only after the fabric open succeeds, `ConnectFailed` on failure //! ([`crate::dispatch::connect_failed_open_decline`], the wave-2 //! seam stub's reason surviving as the real decline). -//! An **inbound** `forwarded-tcpip` open — arriving *from* the vanilla -//! client — declines with the same explicit `ConnectFailed` as the +//! An **inbound** `forwarded-tcpip` open, arriving *from* the vanilla +//! client, declines with the same explicit `ConnectFailed` as the //! unvanilla-arrival class (`w3-tunnel-listen`: the real `-R` data //! leg is the door's own server-initiated opens, driven by the //! [`crate::tunnel_map`] arrival pump; a vanilla client never @@ -65,47 +65,47 @@ //! The bare //! `auth-agent@openssh.com` channel *type* //! (`forwarded-streamlocal@openssh.com` likewise) has no russh handler -//! hook at this pin — russh rejects those opens inline +//! hook at this pin; russh rejects those opens inline //! (administratively prohibited), which is the decline the never- //! feature contract needs, but it is an inherited posture: a pin bump //! that changed it would surface here as an accepted-then-dropped //! channel (third-party-upstream note; file upstream first). //! //! The session rows are **parse-only**: `exec_request` parses first -//! (the full grammar, [`crate::dispatch::parse_exec`] — a git route to +//! (the full grammar, [`crate::dispatch::parse_exec`], a git route to //! the git row, a declined-with-reason grammar class to its honest //! decline, anything else to the session pipe row); `pty_request` / //! `shell_request` route to the session rows. Nothing is served before -//! a request exists — no request, no serving, so a request-less +//! a request exists: no request, no serving, so a request-less //! session channel declines as unfeatured by construction. //! **Decline first, alloc never**: every decline here precedes any //! channel/resource allocation (a leaked channel alloc is a -//! capability leak — the POC-3 stage-A rule); the per-length +//! capability leak, the POC-3 stage-A rule); the per-length //! `max_exec_command_len` cap is enforced before the parse itself. //! //! The store-and-take channel handoff (`w3-git-mapping`) //! //! A confirmed `session` open **stores** its [`Channel`] in //! per-connection handler state ([`Self::take_stored_channel`]'s -//! supplier: `channel_open_session` accepts, then inserts — the +//! supplier: `channel_open_session` accepts, then inserts; the //! POC-3 §A.4 accepted-but-held shape); the git row's `exec_request` //! **takes** it (`channels.remove(&id)` → `into_stream()` in the //! spawned serving task) and the session's packet loop keeps owning //! the store: `channel_close` removes whatever it held (a channel //! that served or declined without an exec frees there), and every -//! mutation happens on the loop's task — single-writer, no lock. A +//! mutation happens on the loop's task: single-writer, no lock. A //! git exec on a channel whose stored handle is already gone -//! (re-served, or never held — unvanilla) declines serving-path. +//! (re-served, or never held, which is unvanilla) declines serving-path. //! //! ## The session rows' real serving paths (`w3-tty-session`) //! //! The pty/shell/pipe rows replaced their wave-3 skeleton stubs with //! the alktty translation bridge ([`crate::tty_map`]): the pty row //! stores the negotiated `TerminalParamsWire` ([`Self::ptys`]'s -//! supplier — taken by the later shell/exec request on the same +//! supplier, taken by the later shell/exec request on the same //! channel, `ssh -t host "cmd"`'s pty-then-exec); the shell and pipe //! rows take the stored channel the same way the git row does and -//! spawn `serve_tty_row` over the configured seam — locally-built +//! spawn `serve_tty_row` over the configured seam, with locally-built //! negotiation, unset-fields-decline (OQ-08: `shell_argv` unset → //! the shell row declines, `exec_wrapper_argv` unset → the pipe row //! declines, `session_seam` unset → both rows and the pty row @@ -118,15 +118,15 @@ //! ## The control rows' per-channel surface (`w3-tty-session`) //! //! `window_change_request` and `signal` arrive on the packet loop -//! **after** the serving task owns the wire — the spawned bridge is +//! **after** the serving task owns the wire, and the spawned bridge is //! reached through [`Self::bridges`]' per-channel surface //! ([`crate::tty_map::BridgeSurface`]: the bounded control mpsc's -//! `try_send` — never awaited on the packet loop — plus the +//! `try_send` (never awaited on the packet loop), plus the //! per-channel cancel). A resize for a channel whose pty is stored //! but not yet serving updates the stored params (the final size //! wins); signal names are accepted verbatim (the backend owns the //! semantics). Unfeatured builds emit the request-level decline -//! event with no reply — the control rows are fire-and-forget, no +//! event with no reply; the control rows are fire-and-forget, no //! SSH reply exists to send. [`Self::channel_close`] releases the //! surface (firing the cancel: the alktty kill-on-drop contract is //! the cancelled session's cleanup) along with the channel and pty @@ -137,45 +137,45 @@ //! ## The spawn-and-return structural constraint (ADR-006 decision 4) //! //! russh at this pin runs handler callbacks **inline inside the -//! session's packet loop** — a blocking handler suspends all packet +//! session's packet loop**: a blocking handler suspends all packet //! routing and deadlocks against the peer's follow-up bytes (POC-3 //! proved by construction with receive-pack). Every serving path is //! therefore spawned through [`crate::serve::spawn_serving_path`] and //! the handler returns fast: the serving rows (the git row's alkgit //! dispatch, the session rows' config-driven declines and //! [`crate::tty_map`]'s bridge) all clone `session.handle()`, spawn -//! through the clone, and are gone from the hook's stack — no hook +//! through the clone, and are gone from the hook's stack; no hook //! awaits a serving path inline. The decline keeps its wire shape //! (failure then close), riding the spawn. Exit/status reporting from //! spawned tasks rides the same cloned handle -//! ([`crate::serve::report_exit_status_then_close`] — the mechanics; +//! ([`crate::serve::report_exit_status_then_close`], the mechanics; //! the tty rows' derivation rules live in [`crate::tty_map`]), pinned //! end-to-end by the mechanics rows in `tests/spawn_return.rs` and the //! mapping rows in `tests/git_mapping.rs` / `tests/tty_mapping.rs`. //! //! The open-level declines (unfeatured/never-feature rows, the //! direct rows' pre-admit classes) stay inline by class: they answer -//! the open *before* any channel is owned — nothing is served yet, +//! the open *before* any channel is owned: nothing is served yet, //! so nothing spawns. The route-1 bridge (`w3-tunnel-direct`) moved //! the direct rows' accept past the fabric open: the accept and the //! pump ride the spawned task, per the same constraint. The `-R` //! listen rows' family-ward dial is the one **inline await** on the //! loop (`w3-tunnel-listen`'s recorded decision: the global request's -//! reply + the `&mut u32` bound-port out-param are the hook's own — -//! no spawned-task answer exists at this pin — and the fabric's +//! reply + the `&mut u32` bound-port out-param are the hook's own, +//! no spawned-task answer exists at this pin, and the fabric's //! answer rides the fabric leg's connections, not this session's //! routing; bounded by `LISTEN_DIAL_TIMEOUT`), while everything under -//! the reply — the arrivals, the pumps — stays spawned. +//! the reply (the arrivals, the pumps) stays spawned. //! -//! Request-level declines: `subsystem_request` declines every name — +//! Request-level declines: `subsystem_request` declines every name: //! `sftp` is the OQ-13 placeholder (the feature exists, the route //! does not until alkfs lands); git service names carry only a name, //! never a repository id, so git can never dispatch as a subsystem //! (ADR-006 decision 2); everything else is unimplemented. `env_request` -//! declines unconditionally (OQ-09 — no allowlist ships: wire env is +//! declines unconditionally (OQ-09; no allowlist ships: wire env is //! not family config). `x11_request` and `agent_request` decline //! (ADR-003 §5). The global listen requests (`tcpip_forward` -//! / `streamlocal_forward` + their cancel forms) — the `-R` rows +//! / `streamlocal_forward` + their cancel forms), the `-R` rows //! (`w3-tunnel-listen`): the real flow under `tunnel` with the listen //! seam configured (the family-ward `TunnelListener::open` dial, the //! arrivals' arrival pump through the shared router); every decline @@ -186,7 +186,7 @@ //! Two decline classes, chosen for vanilla-client observability (POC-1 //! §5: channel-scoped decline, auth intact, no hangs): //! -//! - **Open-level declines** — channel-open failure codes (`x11` +//! - **Open-level declines** (channel-open failure codes: `x11` //! never-feature, unfeatured feature rows, the tunnel rows' //! identity-less guard and beyond-cap refusals → administratively //! prohibited; the direct rows' cannot-bridge classes (the fabric @@ -196,54 +196,54 @@ //! connect failed). These //! happen before the channel exists, so the SSH open-failure code is //! the honest, richest reason surface. -//! - **Request-level declines** — [`Session::channel_failure`]: the +//! - **Request-level declines** ([`Session::channel_failure`]): the //! SSH request-reply vocabulary has no failure text, so a request //! decline's "reason" is the routing decision itself (documented //! above, in [`crate::dispatch`]'s grammar, and per feature build in //! `mapping.md`'s decline matrix). A *capability* decline answers //! failure and leaves the channel usable (the POC-1 §5 -//! session-survives-declines posture) — including the git grammar's +//! session-survives-declines posture), including the git grammar's //! declinables (`unknown-service` / `service-only` / //! `invalid-repo-id`, the parsed reply shapes, `w3-git-mapping`); //! a *serving-path* decline (a routable row that owns the request's //! whole outcome: the seam-unconfigured git row, the session rows' -//! unset-field and unset-seam declines — `w3-tty-session`'s OQ-08 -//! shapes — and the identity-less guard) answers failure and closes -//! the channel — the vanilla-clean shape for a row whose serving +//! unset-field and unset-seam declines, `w3-tty-session`'s OQ-08 +//! shapes, and the identity-less guard) answers failure and closes +//! the channel, the vanilla-clean shape for a row whose serving //! path cannot exist. The serving-path decline rides the spawned //! serving task (ADR-006 decision 4, §The spawn-and-return //! structural constraint above); the wire shape is unchanged. The //! `channel-not-held` guard is the inline request-level shape (the //! channel that could not be held stays usable). The real serve's //! own outcomes are not declines: the substrate maps them (denial -//! band before any protocol byte; exit-status then close — the -//! `exit_code` mapping decision recorded in [`crate::git_map`]; +//! band before any protocol byte; exit-status then close (the +//! `exit_code` mapping decision recorded in [`crate::git_map`]); //! the tty bridge's negotiation-error and exit-chunk decisions in //! [`crate::tty_map`]). //! //! ## The event vocabulary on every decline (`w3-decline-tracing`) //! //! Every decline site here emits its event through -//! [`crate::observe`] — the wave-2 gate's booked finding: the +//! [`crate::observe`], the wave-2 gate's booked finding: the //! deciding context (row, feature build, channel id, decline class, //! reason) rides the tracing event, not just the routing decision //! documented per build. The vocabulary and its safety posture (no -//! secrets, no username, no fingerprint — structurally) live in that +//! secrets, no username, no fingerprint; enforced structurally) live in that //! module; the serving-path lifecycle (started / ended / failure) //! hangs off the spawned stub body and is what the wave-3 mappings' //! real serving paths inherit. //! //! ## Bounded resources at the handler surface (`w2-bounded-resources`) //! -//! (AGENTS.md convention 9; `overview.md` §Bounded-resources policy — -//! the "concurrent channels per session — ours" row.) The in-crate +//! (AGENTS.md convention 9; `overview.md` §Bounded-resources policy, +//! the "concurrent channels per session: ours" row.) The in-crate //! concurrent-channel cap ([`crate::channel_cap::ChannelCap`]) is //! enforced at every `channel_open_*` hook: an accept path beyond //! `Limits::max_concurrent_channels` is refused fail-closed at the -//! open ([`crate::dispatch::cap_exceeded_open_decline`] — never +//! open ([`crate::dispatch::cap_exceeded_open_decline`]; never //! queued, never half-open), and the count releases so the cap //! recovers: through the `channel_close` hook for established -//! channels, and — `w3-tunnel-direct` — inside the route-1 bridge's +//! channels, and, for `w3-tunnel-direct`, inside the route-1 bridge's //! spawned task on a fabric-open failure (the admitted-but-rejected //! shape: ADR-006 decision 1 rejects the open, so no `channel_close` //! can ever fire for it; the release mechanism is the shared @@ -251,14 +251,14 @@ //! its two budget surfaces (`w3-tunnel-listen`, recorded in //! `channel_cap.rs`): the arrivals admit into the owning route's //! count inside the spawned arrival tasks (a beyond-cap arrival never -//! opens an SSH channel — teardown-at-birth), and the listen count is +//! opens an SSH channel, which is teardown-at-birth), and the listen count is //! its own dedicated counter against the same ceiling (the //! listener/channels mix stays unconstrained; both stay bounded). The //! order of the //! gates: the feature gate first (an unfeatured build declines //! everything before the cap matters), then the pure-decline classes //! (the tunnel rows' unset-handle/unix-gate/identity/invalid-target -//! checks precede the admission — decline-first-alloc-never applies +//! checks precede the admission; decline-first-alloc-never applies //! to the budget too), the cap admission before any accept; the //! admitted count is held across the fabric open and released exactly //! once on either path. The `max_exec_command_len` cap is @@ -272,7 +272,7 @@ //! The handler type is deliberately constructible outside this module //! (re-exported `#[doc(hidden)]` from the crate root) so the wave-1 //! contract tests drive these hooks directly against the in-memory -//! doubles — the wire-facing `VerifiedPublicKey`/`PublicKeyOffer` hook +//! doubles; the wire-facing `VerifiedPublicKey`/`PublicKeyOffer` hook //! arguments are `#[non_exhaustive]` (only russh constructs them), so //! the bridge core is its own method ([`SessionHandler::resolve_bridge`]) //! the tests call with ordinary key material; the wire-level rows @@ -308,36 +308,36 @@ use crate::tunnel_map; use alktty::negotiation::NegotiateRequest; /// The per-connection handler (one per mounted stream): russh constructs -/// nothing here — [`crate::SshAdapter::handle`] builds one per accepted +/// nothing here; [`crate::SshAdapter::handle`] builds one per accepted /// stream and drives it through `russh::server::run_stream`. /// /// Carries the serve-config the auth bridge and dispatch consume, the -/// in-crate concurrent-channel cap (`ChannelCap` — see the private +/// in-crate concurrent-channel cap (`ChannelCap`, see the private /// `channel_cap` module; enforced at every `channel_open_*` accept /// path, bounded resources, AGENTS.md convention 9), and the resolved /// identity once a publickey auth has been accepted (see -/// [`Self::resolved_identity`] — the wave-3 seam reads it). +/// [`Self::resolved_identity`], which the wave-3 seam reads). pub struct SessionHandler { serve: Arc, /// The in-crate concurrent-channel cap (`w2-bounded-resources`), /// shared as an `Arc` since `w3-tunnel-direct`: the route-1 bridge's /// spawned task releases the count on a fabric-open failure (the - /// admitted-but-rejected shape — no `channel_close` can ever fire + /// admitted-but-rejected shape, no `channel_close` can ever fire /// for it; see `channel_cap.rs`'s release-sites record). Admissions - /// have two sites since `w3-tunnel-listen` — the packet loop's - /// open hooks and the `-R` arrival tasks — and releases three; the + /// have two sites since `w3-tunnel-listen`: the packet loop's + /// open hooks and the `-R` arrival tasks, and releases three; the /// mutex makes them sound (the reasoning, recorded in /// `channel_cap.rs`). channel_cap: Arc, /// The `-R` listen leg's per-session bookkeeping /// (`w3-tunnel-listen`): the minted-listen map (token → pending - /// listen; written only by the packet loop's hooks — the listen + /// listen; written only by the packet loop's hooks. The listen /// global requests mints, the cancel forms + this handler's /// teardown remove, single-writer/no-lock like the `channels` /// store) and the listen count's dedicated /// `max_concurrent_channels`-ceiling counter (a listen is at least /// one future channel's potential; its own counter keeps the - /// listener/channels mix unconstrained while both stay bounded — + /// listener/channels mix unconstrained while both stay bounded, /// no unbounded listener map). #[cfg(feature = "tunnel")] listeners: HashMap, @@ -349,7 +349,7 @@ pub struct SessionHandler { /// the close releases them. Written only by the packet loop's /// hooks (`channel_open_session` inserts; the git row's and the /// session rows' serving dispatches remove for their taken - /// channel; `channel_close` removes) — single-writer, no lock. + /// channel; `channel_close` removes); single-writer, no lock. channels: HashMap>, /// The session rows' negotiated pty params (`w3-tty-session`): /// `pty_request` stores, the later `shell_request`/`exec_request` @@ -376,17 +376,17 @@ impl Drop for SessionHandler { /// **session-row** serving task of this connection watches it and /// cancels its alktty session (the kill-on-drop cleanup) instead /// of outliving the connection. The git serving task does not - /// watch this signal — it ends through the channel duplex (stream + /// watch this signal; it ends through the channel duplex (stream /// EOF / send failure) once the russh session dies, bounded by the /// alkgit seam's own `session_wall_clock` (the alkgit limits the /// assembly configured). The `tunnel` build adds the `-R` /// leg's teardown (`w3-tunnel-listen`): the session's pending /// listens' tokens leave the shared router (a fabric arrival after - /// the session is gone is the correlation-miss class — + /// the session is gone is the correlation-miss class, /// teardown-at-birth) and the listener objects drop here (the /// fabric-side reap). Any in-flight arrival already past the /// route lookup fails its dead-handle open and releases its - /// admission — the never-established path. + /// admission, the never-established path. fn drop(&mut self) { #[cfg(feature = "session")] self.teardown.fire(); @@ -401,7 +401,7 @@ impl Drop for SessionHandler { } impl SessionHandler { - /// Builds the handler over the serving configuration — the + /// Builds the handler over the serving configuration; the /// identity provider inside is the assembly-supplied /// `alkcall::core::auth::IdentityProvider`; the bridge only /// resolves through it. @@ -428,14 +428,14 @@ impl SessionHandler { /// store-and-take handoff): the git row's and the session rows' /// dispatches remove the handle the open stored, handing the /// stream into the spawned serving task. `None` when nothing is - /// held — a re-served or never-held channel (unvanilla; declined + /// held: a re-served or never-held channel (unvanilla; declined /// serving-path). #[cfg(any(feature = "git", feature = "session"))] fn take_stored_channel(&mut self, channel: ChannelId) -> Option> { self.channels.remove(&channel) } - /// The identity this connection currently rides — `Some` only after + /// The identity this connection currently rides, `Some` only after /// a fingerprint resolution accepted a publickey auth (the bridge's /// fail-closed rejecting paths never leave a weakly-authorized /// state behind). The wave-3 seam propagation consumes this. @@ -447,15 +447,15 @@ impl SessionHandler { /// cap (bounded resources, `w2-bounded-resources`): room under /// `Limits::max_concurrent_channels` admits and counts the channel; /// beyond the cap the open is refused fail-closed with a clean - /// wire reason ([`crate::dispatch::cap_exceeded_open_decline`]) — - /// never queued, never half-open. Called exactly at accept sites — + /// wire reason ([`crate::dispatch::cap_exceeded_open_decline`]), + /// never queued, never half-open. Called exactly at accept sites: /// the packet loop owns every admit call (the single admit writer, /// [`ChannelCap`]'s recorded reasoning); a pure-decline path /// (unfeatured, never-feature, the tunnel rows' pre-admit classes) /// never touches the count. Since `w3-tunnel-direct`, the tunnel /// rows admit **at the hook and hold the count across the fabric /// open**: a fabric failure releases inside the spawned bridge - /// task (the admitted-but-rejected shape — no `channel_close` can + /// task (the admitted-but-rejected shape; no `channel_close` can /// ever fire); a success releases when the established channel /// closes ([`Self::channel_close`]). The release sites are disjoint /// per admission by the wire shape. @@ -467,16 +467,16 @@ impl SessionHandler { /// The ADR-004 decision 1 bridge core, structured out of the /// [`Handler::auth_publickey`] hook so the contract tests can drive /// it directly: the hook's russh-owned argument shape - /// (`russh::server::VerifiedPublicKey`) is `#[non_exhaustive]` — - /// only russh constructs it — but this method takes the two facts + /// (`russh::server::VerifiedPublicKey`) is `#[non_exhaustive]`, + /// only russh constructs it, but this method takes the two facts /// the hook receives (the verified key and the signature's /// algorithm) as ordinary arguments. /// - /// Ed25519-only gate first (ADR-002 decision 4 — `SkEd25519` and + /// Ed25519-only gate first (ADR-002 decision 4: `SkEd25519` and /// every other scheme share the non-ed25519 decline, which is /// explicit-over-inherited so it survives a pin bump), then the /// single fingerprint path → the injected provider's - /// `resolve_from_fingerprint`. No username parameter exists — the + /// `resolve_from_fingerprint`. No username parameter exists; the /// user string is never an identity input (OQ-03). `None` is the /// fail-closed reject disposition; `Some` carries the identity the /// hook stores in handler state. @@ -503,7 +503,7 @@ impl SessionHandler { /// The `session` channel-open gate (ADR-003 feature graph): /// session channels open only where a session-serving feature - /// exists — `session` ∨ `git`, because git's parse path lives + /// exists: `session` ∨ `git`, because git's parse path lives /// inside session channels. fn serves_session_channels(&self) -> bool { cfg!(feature = "session") || cfg!(feature = "git") @@ -554,7 +554,7 @@ impl russh::server::Handler for SessionHandler { } } - /// ADR-004 decision 2: accept-and-delegate, explicit — the probe + /// ADR-004 decision 2: accept-and-delegate, explicit; the probe /// hook consumes no auth attempt (POC-1 verified), so keeping it at /// `Auth::Accept` keeps the `max_auth_attempts` counting honest; /// the real disposition is [`Self::auth_publickey`]'s. @@ -566,14 +566,14 @@ impl russh::server::Handler for SessionHandler { Ok(Auth::Accept) } - /// ADR-004 decision 3: explicit family-contract decline — never the + /// ADR-004 decision 3: explicit family-contract decline, never the /// inherited default (a pin bump could silently change it). async fn auth_none(&mut self, _user: &str) -> Result { observe::decline_auth("auth_none", "method-unimplemented"); Ok(Auth::reject()) } - /// ADR-004 decision 3: explicit family-contract decline — password + /// ADR-004 decision 3: explicit family-contract decline; password /// auth does not exist on this door; ADR-005's key custody is the /// whole story. async fn auth_password(&mut self, _user: &str, _password: &str) -> Result { @@ -581,7 +581,7 @@ impl russh::server::Handler for SessionHandler { Ok(Auth::reject()) } - /// ADR-004 decision 3 + OQ-04 (resolved): explicit decline — the + /// ADR-004 decision 3 + OQ-04 (resolved): explicit decline, since the /// CA-trust story does not exist in the family identity model; /// future support is new-ADR territory. async fn auth_openssh_certificate( @@ -604,16 +604,16 @@ impl russh::server::Handler for SessionHandler { Ok(Auth::reject()) } - /// A counted channel closed — the in-crate concurrent-channel + /// A counted channel closed: the in-crate concurrent-channel /// cap's decrement (`w2-bounded-resources`): every fired /// `channel_close` corresponds to exactly one previously-admitted /// open (russh only routes `CHANNEL_CLOSE` for established - /// channels — a declined open never established one — and consumes + /// channels, a declined open never established one, and consumes /// the close at most once), so the count recovers through this /// single release point, saturating in [`ChannelCap::release`] on /// top. The spawned serving paths never touch the count directly: /// their closes ride the cloned handle, the client's close reply - /// cycles back through the packet loop, and this hook fires — the + /// cycles back through the packet loop, and this hook fires; the /// single-writer reasoning in [`ChannelCap`]. async fn channel_close( &mut self, @@ -634,15 +634,15 @@ impl russh::server::Handler for SessionHandler { /// The session-channel open gate (ADR-003 feature graph, /// `session` ∨ `git`), then the in-crate concurrent-channel cap - /// ([`Self::admit_channel_open`] — bounded resources, + /// ([`Self::admit_channel_open`], bounded resources, /// `w2-bounded-resources`): unfeatured builds decline at the open - /// — never a half-open channel — and a featured open beyond the + /// and never a half-open channel; a featured open beyond the /// cap is refused fail-closed with a clean wire reason /// ([`crate::dispatch::cap_exceeded_open_decline`]), never queued. /// A confirmed open accepts the channel and counts it; the count /// releases when the channel closes ([`Self::channel_close`]). The /// parse-only dispatch serves the accepted channel through its - /// requests (nothing serves request-less — ADR-006 as amended). + /// requests (nothing serves request-less, per ADR-006 as amended). async fn channel_open_session( &mut self, channel: Channel, @@ -664,7 +664,7 @@ impl russh::server::Handler for SessionHandler { Ok(()) } - /// The x11 channel open: **always declines** — a never-feature + /// The x11 channel open: **always declines**, a never-feature /// (ADR-003 §5), declined in every build, never feature-gated. The /// cap never applies here: a count is consumed only at an accept /// path, and this hook never has one. @@ -684,14 +684,14 @@ impl russh::server::Handler for SessionHandler { /// The `direct-tcpip` open gate (`tunnel`) and its route-1 bridge /// dispatch (`w3-tunnel-direct`): unfeatured declines at the open; /// featured rows build the bridge target from the SSH open - /// arguments (`SubstrateAddr::HostPort` + `Substrate::Tcp` — an + /// arguments (`SubstrateAddr::HostPort` + `Substrate::Tcp`; an /// out-of-range wire port is an impossible target, declined /// pre-admission) and route to [`Self::dispatch_direct_open`]: /// pre-admit decline classes first (the unset fabric handle - /// declining under the feature — the unset-declines posture — and + /// declining under the feature, the unset-declines posture, and /// the unreachable-in-practice `no-identity` guard), then the cap /// admission **at the hook, held across the fabric open**, then - /// the spawned bridge per spawn-and-return — + /// the spawned bridge per spawn-and-return: /// `TunnelSession::open_direct` → accept only after the fabric /// open succeeds (`ConnectFailed` on failure, the count released /// in the task), `take_halves()` pumped against the taken channel. @@ -737,7 +737,7 @@ impl russh::server::Handler for SessionHandler { } /// The `forwarded-tcpip` open gate (`tunnel`): an **inbound** open - /// of this channel type — arriving *from* the vanilla client — is + /// of this channel type (arriving *from* the vanilla client) is /// not the `-R` leg at all (the `-R` data leg is the door's own /// server-initiated opens via [`crate::tunnel_map`]'s arrival /// pump; a vanilla client never initiates `forwarded-tcpip`, @@ -769,10 +769,10 @@ impl russh::server::Handler for SessionHandler { /// The `direct-streamlocal` open gate (`tunnel`) and its route-1 /// bridge dispatch: the `direct-tcpip` shape with the OQ-11 - /// **runtime-Unix gate** — the row compiles wherever `tunnel` + /// **runtime-Unix gate**: the row compiles wherever `tunnel` /// compiles (universal compile, no per-platform feature fork), but /// off-Unix it declines at the open **before any fabric call** - /// (never a partial bridge — the gate precedes the unset-handle + /// (never a partial bridge; the gate precedes the unset-handle /// check, the identity guard, and the cap admission), and on-Unix /// it rides the same bridge with `SubstrateAddr::Path` + /// `Substrate::Unix`. @@ -821,9 +821,9 @@ impl russh::server::Handler for SessionHandler { /// The exec-grammar dispatch (ADR-006 point 3 as amended; the /// full grammar, `w3-git-mapping`): the per-length cap checks the - /// wire bytes first (pre-parse, pre-allocation — decline first, + /// wire bytes first (pre-parse, pre-allocation; decline first, /// alloc never), then [`crate::dispatch::parse_exec`] routes: - /// a git route to the git row (feature-gated — a session-only + /// a git route to the git row (feature-gated; a session-only /// build declines it as its gate), a grammar declinable to its /// honest request-level decline, anything else to the session /// pipe row. Invalid UTF-8 parses to the pipe row (parse-then- @@ -889,11 +889,11 @@ impl russh::server::Handler for SessionHandler { /// The `pty_request` row (`session`): the args → /// `TerminalParamsWire` (ttymodes → the reserved `{}` JSON, /// OQ-44), stored per channel for the later shell/exec request on - /// the same channel — after the seam check (a pty whose session + /// the same channel, after the seam check (a pty whose session /// can never serve is a declined allocation, /// `seam-unconfigured`). Unfeatured builds decline the /// capability. The successful row answers `channel_success` - /// (POC-3 §D.1's shape — serving starts at the shell/exec + /// (POC-3 §D.1's shape: serving starts at the shell/exec /// request). async fn pty_request( &mut self, @@ -930,11 +930,11 @@ impl russh::server::Handler for SessionHandler { /// The `shell_request` row (`session`): the serve-config shell /// argv, verbatim, as `NegotiateRequest.cmd`; the stored pty - /// params consumed (`None` → pipe-mode shell — decided: a pty-less + /// params consumed (`None` → pipe-mode shell; decided: a pty-less /// shell request is served, `ssh -T host` is legitimate vanilla); /// unset-declines first (OQ-08: `shell_argv` unset → /// `shell-unconfigured`; the seam unset → `seam-unconfigured` - /// — both the spawned serving-path shape). A routed request + /// (both the spawned serving-path shape). A routed request /// answers `channel_success` inline; the exit chunk reports the /// outcome, status-before-close from the spawned task. async fn shell_request( @@ -998,13 +998,13 @@ impl russh::server::Handler for SessionHandler { Ok(()) } - /// `window_change_request` (`session`): the resize control row — + /// `window_change_request` (`session`): the resize control row, /// forwarded into the serving bridge's bounded control surface /// (`try_send`, never awaited on the packet loop); for a channel /// whose pty is stored but not yet serving, the stored params - /// resize instead (the final size wins — vanilla sshd's own + /// resize instead (the final size wins, vanilla sshd's own /// ordering); with neither, the event is dropped. Fire-and-forget - /// on the wire — no SSH reply exists, so a decline sends none + /// on the wire; no SSH reply exists, so a decline sends none /// (the event is the record). Signal names: see [`Self::signal`]. async fn window_change_request( &mut self, @@ -1050,11 +1050,11 @@ impl russh::server::Handler for SessionHandler { Ok(()) } - /// The `signal` row (`session`): accepted verbatim — no + /// The `signal` row (`session`): accepted verbatim, with no /// alkssh-side name filter (the backend owns the semantics; /// alktty's control handle applies its own default kill for /// names it rejects, and the pipe-mode pid-only vs PTY - /// process-group scope is backend semantics) — so there is no + /// process-group scope is backend semantics), so there is no /// decline shape: the request is fire-and-forget on the SSH /// wire, and the bridge's bounded surface is the only path. An /// unfeatured build emits the decline event with no reply. @@ -1082,7 +1082,7 @@ impl russh::server::Handler for SessionHandler { } /// Every subsystem name declines (unimplemented on this door): - /// `subsystem("sftp")` is the OQ-13 placeholder — the feature + /// `subsystem("sftp")` is the OQ-13 placeholder; the feature /// exists, the route does not until alkfs lands; git service /// names carry only a name, never a repository id, so git can /// never dispatch as a subsystem (ADR-006 decision 2, POC-3 @@ -1101,7 +1101,7 @@ impl russh::server::Handler for SessionHandler { } /// `env_request` declines unconditionally (OQ-09: no allowlist - /// ships — wire env is not family config; the assembly supplies + /// ships, since wire env is not family config; the assembly supplies /// the session env through [`crate::ServeConfig::session_env`]). async fn env_request( &mut self, @@ -1132,7 +1132,7 @@ impl russh::server::Handler for SessionHandler { } /// Agent forwarding on a session session-channel: always declines - /// (never-feature, ADR-003 §5 — agent forwarding is the + /// (never-feature, ADR-003 §5; agent forwarding is the /// anti-pattern of the alkvault custody model). `false` is the /// decline; russh replies the channel failure. async fn agent_request( @@ -1146,7 +1146,7 @@ impl russh::server::Handler for SessionHandler { /// The `tcpip-forward` listen request (`-R` ingress, `w3-tunnel- /// listen`): the gate is [`Self::serves_tunnels`]; the real flow - /// rides [`listen_request_dispatch`] (`tunnel` builds) — the + /// rides [`listen_request_dispatch`] (`tunnel` builds), the /// family-ward `TunnelListener::open` dial, the bound-port out-param /// (`port = 0` → the fabric's actually-bound number, the sshd /// parity), the route + listener registration. Unfeatured builds @@ -1179,13 +1179,13 @@ impl russh::server::Handler for SessionHandler { } /// The `cancel-tcpip-forward` cancel form (`-KR`, mux teardown, - /// `ExitOnForwardFailure`): 1:1 into the family listener's teardown — + /// `ExitOnForwardFailure`): 1:1 into the family listener's teardown, /// the pending listen matched by (the wire address as the request /// carried it, the bound port), the route removed **before** any /// teardown (a racing arrival is already the correlation-miss /// class), the listener count released, the fabric channel's /// teardown spawned (`TunnelListener::close`). `false` for a - /// (address, port) pair with no pending listen — the sshd parity + /// (address, port) pair with no pending listen; the sshd parity /// (`cancel of a not-found forward`). async fn cancel_tcpip_forward( &mut self, @@ -1206,7 +1206,7 @@ impl russh::server::Handler for SessionHandler { } /// The `streamlocal-forward` listen request: the same listen flow - /// as `tcpip_forward` over the unix substrate — with the OQ-11 + /// as `tcpip_forward` over the unix substrate, with the OQ-11 /// runtime-Unix gate riding the serving flow it serves (off-Unix /// it declines before any fabric call; universal compile, no /// per-platform feature fork). No port out-param (the unix listen @@ -1271,34 +1271,34 @@ impl russh::server::Handler for SessionHandler { /// gate order is decline-first-alloc-never, each consumer checked /// before the next allocation is taken: /// -/// 1. **The `no-identity` guard** — unreachable on the wire (russh +/// 1. **The `no-identity` guard**: unreachable on the wire (russh /// authorizes before requests serve) and fail-closed: never /// anonymous listens. -/// 2. **The seam checks** — the fabric handle or the listen seam -/// (`listen_router` absent: an egress-only door — the seam unset or +/// 2. **The seam checks**: the fabric handle or the listen seam +/// (`listen_router` absent: an egress-only door, whether the seam unset or /// the registration never ran) decline `seam-unconfigured` before /// any dial. -/// 3. **The OQ-11 unix gate** — the streamlocal variant's off-Unix +/// 3. **The OQ-11 unix gate**: the streamlocal variant's off-Unix /// decline rides its hook (checked before this fn runs, so the /// unreachable-on-Unix-only row never here). -/// 4. **The listener cap** — the listen count's dedicated +/// 4. **The listener cap**: the listen count's dedicated /// `max_concurrent_channels`-ceiling admission; beyond it /// `cap-exceeded`. /// /// Then the family-ward dial ([`crate::tunnel_map::open_listen`], the -/// `resource = ` naming convention) — awaited +/// `resource = ` naming convention), awaited /// inline (the recorded inline decision: the global request's reply + /// the `&mut u32` out-param are the hook's; the fabric answer rides /// the fabric leg, not this session's packet loop; the dial is /// bounded by `LISTEN_DIAL_TIMEOUT`, so the stall is bounded). The /// reply's `bound` port writes the out-param (`port = 0` → the /// actually-bound number, sshd parity); the route registers into the -/// shared router — the register is the collision pre-check +/// shared router; the register is the collision pre-check /// (`w4-router-collision`): a mint on an already-held token refuses /// fail-closed (`token-collision`, the minted listener torn down, the -/// cap released — a collided mint can never steal a live route; the +/// cap released, so a collided mint can never steal a live route; the /// decline rides `Ok(false)`, never the error taxonomy, since a -/// global-request hook's `Err` would kill the whole session) — and +/// global-request hook's `Err` would kill the whole session), and /// the pending listen into the session's /// packet-loop-only map. `Ok(true)`'s answer is the only success /// shape; every decline path answers the vanilla client's @@ -1400,15 +1400,15 @@ async fn listen_request_dispatch( /// listener's teardown. Match rule (sshd parity): the wire endpoint as /// the original request carried it + the bound port for the tcp /// variants (the client sends the same normalized string it sent -/// originally, and the *allocated* port for `port = 0` mints — the +/// originally, and the *allocated* port for `port = 0` mints, the /// value the listen reply carried); the path alone for the unix /// variant. Order: the entry leaves the session map and the route /// leaves the shared router before any family teardown spawns (a /// racing arrival that has not yet cloned its route is already the -/// correlation-miss class — no post-cancel half-serve; one that -/// cloned just before completes independently — the recorded +/// correlation-miss class, so no post-cancel half-serve; one that +/// cloned just before completes independently (the recorded /// caveat), then the listener count releases, then the family -/// teardown spawns (`TunnelListener::close` inside the spawn — a +/// teardown spawns (`TunnelListener::close` inside the spawn, a /// bounded local shutdown + entry reap, not a serving path the hook /// may await). `Ok(true)` iff a pending listen matched. #[cfg(feature = "tunnel")] @@ -1449,7 +1449,7 @@ fn cancel_listen_dispatch( /// The request-level decline shape for an unfeatured/unimplemented /// capability: fail the request and leave the channel usable (POC-1 -/// §5 — session survives declines, no state poisoning). The decline +/// §5: session survives declines, no state poisoning). The decline /// event is emitted by the caller (the hook carries the row/reason /// context); this is the wire shape only. async fn decline_unfeatured_request(channel: ChannelId, session: &mut Session) { @@ -1459,16 +1459,16 @@ async fn decline_unfeatured_request(channel: ChannelId, session: &mut Session) { /// The spawned serving-path decline body (`w3-git-mapping`'s shape, /// reused by `w3-tty-session`'s config-driven declines): fail the /// request and close the channel, through the cloned handle the task -/// was handed — the vanilla-clean shape for a routed row that owns +/// was handed, the vanilla-clean shape for a routed row that owns /// the request's whole outcome. The helper name keeps the wave-3 /// history (the decline IS the path it spawns). Decline-first-alloc- /// never holds structurally: nothing is allocated before the failure -/// lands — the spawn's handle clone is the only resource ever taken. +/// lands; the spawn's handle clone is the only resource ever taken. /// /// The serving-path lifecycle events ride this body /// ([`crate::observe`]): started (the task's first action), the /// serving-path decline (class `serving`, the caller's vocabulary -/// reason), and — after the wire reporting has completed — ended, or +/// reason), and, after the wire reporting has completed, ended, or /// failed when a report send could not complete (the one warn in the /// vocabulary). #[cfg(any(feature = "git", feature = "session"))] @@ -1493,7 +1493,7 @@ async fn seam_stub_decline( /// Spawns a serving-path decline as the row's serving path (ADR-006 /// decision 4): the handle is cloned here, the decline runs on its own -/// task, and the hook returns — no serving path awaits inline. The +/// task, and the hook returns; no serving path awaits inline. The /// row never serves, so the decline *is* the path: failure + close, /// event-shaped ([`crate::observe`]) with the caller's reason. #[cfg(any(feature = "git", feature = "session"))] @@ -1509,14 +1509,14 @@ fn spawn_seam_stub( } /// The git row's routing stage (feature-gated, `w3-git-mapping`): -/// validation of the normalized id ([`crate::git_map::repo_id_validates`] — +/// validation of the normalized id ([`crate::git_map::repo_id_validates`], /// reply-shaped `invalid-repo-id`), the seam-unconfigured decline -/// ([`Self::serves_git_row`] alone configures nothing — the +/// ([`Self::serves_git_row`] alone configures nothing, per the /// unset-declines contract), then the store-and-take handoff and the /// spawned alkgit dispatch ([`crate::git_map::serve_git_row`], the /// resolved identity riding along). A routed exec answers /// `channel_success` inline (the request-reply vocabulary: the request -/// routed; the serving outcome reports through exit-status later — +/// routed; the serving outcome reports through exit-status later, /// the POC-3 §A.5 shape), never awaited serving. #[cfg(feature = "git")] fn git_row_dispatch( @@ -1569,12 +1569,12 @@ fn git_row_dispatch( } /// The session pipe row's dispatch (`w3-tty-session`): unset-declines -/// first (OQ-08 — `exec_wrapper_argv` unset → `wrapper-unconfigured`; +/// first (OQ-08: `exec_wrapper_argv` unset → `wrapper-unconfigured`; /// the seam unset → `seam-unconfigured`; both the spawned serving-path /// shape, never a fallback), then the store-and-take handoff /// (`channel-not-held` → the inline unvanilla decline, the git row's /// shape), the wire command appended to the wrapper argv (`wrapper ++ -/// [cmd]` — never naively split), the stored pty params consumed if a +/// [cmd]`, never naively split), the stored pty params consumed if a /// pty preceded, and the spawned bridge. A routed exec answers /// `channel_success` inline (the request routed; the exit chunk /// reports the serving outcome later). @@ -1637,7 +1637,7 @@ fn pipe_row_dispatch( } /// Installs the per-channel bridge surface, clones the session -/// handle, and spawns the spawned serving path — the session rows' +/// handle, and spawns the serving path, the session rows' /// spawn step (ADR-006 decision 4: the handler returns fast; the /// routed request answers `channel_success` inline). #[cfg(feature = "session")] @@ -1674,24 +1674,24 @@ fn spawn_tty_row( } /// The direct tunnel rows' dispatch (`w3-tunnel-direct`): the -/// pre-admit decline classes first — **decline first, alloc never** -/// applies to the cap budget too, so every consumer is checked before +/// pre-admit decline classes first, because **decline first, alloc +/// never** applies to the cap budget too, so every consumer is checked before /// the admission is taken. Order (the recorded admission mechanics: -/// the admission is taken at the hook — the packet-loop's single -/// admit-writer site, no race window against the cap check — and held +/// the admission is taken at the hook, the packet-loop's single +/// admit-writer site, no race window against the cap check, and held /// across the fabric open): /// /// 1. **The unset fabric handle decline** (`seam-unconfigured`, the -/// unset-declines posture — the feature alone configures nothing): +/// unset-declines posture, the feature alone configures nothing): /// `ConnectFailed` ([`crate::dispatch::connect_failed_open_decline`]) -/// — the bridge cannot be attempted at all. -/// 2. **The `no-identity` guard** — unreachable on the wire (russh +/// as the bridge cannot be attempted at all. +/// 2. **The `no-identity` guard**: unreachable on the wire (russh /// authorizes before channels exist) and fail-closed: never /// anonymous serving (the git/tty rows' shape, discharged here for -/// the tunnel row — the parked `w2-auth-bridge` item; the +/// the tunnel row, the parked `w2-auth-bridge` item; the /// `set_identity` mechanics the rides records live in /// [`crate::tunnel_map`]). -/// 3. **The impossible-target decline** (`invalid-target` — an +/// 3. **The impossible-target decline** (`invalid-target`, an /// out-of-range wire port): `ConnectFailed`. /// /// Then the cap admission ([`Self::admit_channel_open`]; beyond it → diff --git a/src/host_key.rs b/src/host_key.rs index 38c9df6..cbe68de 100644 --- a/src/host_key.rs +++ b/src/host_key.rs @@ -1,27 +1,27 @@ -//! The client-side host-key policy seam (OQ-05 resolution) — the +//! The client-side host-key policy seam (OQ-05 resolution): the //! trust-decision contract the dial surface calls at russh's //! `check_server_key` hook. //! -//! Two cases, one seam — the crate is **policy-blind** +//! Two cases, one seam: the crate is **policy-blind** //! (`docs/architecture/auth.md` §Host-key policy): //! //! 1. **Known beforehand** (trust anchors exist; family-built runners //! mint their host key at assembly time): assembly-supplied pins //! with **hard decline on mismatch**. The crate never hard-codes -//! this — a pin policy is a [`HostKeyPolicy`] implementation the +//! this; a pin policy is a [`HostKeyPolicy`] implementation the //! assembly writes, backed by its own pin store (the host *pin* is //! public config, ADR-005 decision 6; never vault material). //! 2. **Unknown beforehand** (vanilla `sshd` on rental fleets; no //! anchor until first contact): prompt-and-record, //! provider-metadata match, learn-and-record, or accept-and- -//! continue (the ephemeral-fleet shape) — the OpenSSH +//! continue (the ephemeral-fleet shape); the OpenSSH //! "add to known_hosts?" moment is assembly policy, implemented in //! its [`HostKeyPolicy`], never crate behavior. //! //! Crate rules: //! //! - The built-in default policy is **fail-closed**: [`RejectAll`] -//! rejects every presented key — russh's own reject-all default, +//! rejects every presented key, russh's own reject-all default, //! kept. There is **no accept-all built-in crate option**: a //! permissive policy is the assembly's to write when its fleet //! model calls for one. @@ -32,11 +32,11 @@ //! Result`): the bool *is* the trust decision, //! and the handler's `Err` channel stays wire/IO-failure territory. //! A decline is a disposition, not an error (the crate's -//! error-model contract) — decline reasons are the policy's own +//! error-model contract); decline reasons are the policy's own //! record, not a typed crate surface. //! - The [`PresentedHostKey`]'s fingerprint string is the contract- //! invariant format of the crate's single fingerprint path -//! ([`crate::fingerprint`]) — the wave-4 dial wiring computes it +//! ([`crate::fingerprint`]); the wave-4 dial wiring computes it //! there and surfaces it here. //! //! This module is the seam and its default only: the russh @@ -45,17 +45,17 @@ use async_trait::async_trait; -/// The presented host key — the decision input to +/// The presented host key, the decision input to /// [`HostKeyPolicy::decide`]: the endpoint the dial contacted and the /// key that endpoint presented. #[derive(Debug, Clone, PartialEq, Eq)] pub struct PresentedHostKey { - /// The hostname (or IP) the dial targeted — what the assembly's + /// The hostname (or IP) the dial targeted, which the assembly's /// pin store or prompt labels the key against. pub host: String, /// The TCP port the dial targeted. pub port: u16, - /// The presented key's fingerprint — the single fingerprint + /// The presented key's fingerprint, in the single fingerprint /// path's `SHA256:` format ([`crate::fingerprint`]); comparison /// against assembly pins or recorded entries is exact string /// equality by contract. @@ -65,13 +65,13 @@ pub struct PresentedHostKey { /// The trust-decision contract the dial surface calls (OQ-05): the /// crate surfaces the presented host key (host, port, fingerprint) to /// the assembly-provided policy, which decides accept or reject. The -/// crate is policy-blind — it never decides trust itself and carries +/// crate is policy-blind: it never decides trust itself and carries /// no trust model (see the module docs for the two-case model). /// /// The handle shape is the family's injected-handle pattern /// (`Arc`, the alkcall `IdentityProvider` /// precedent): object-safe via `async_trait`, shared by -/// reference — learn-and-record policies hold their state by interior +/// reference; learn-and-record policies hold their state by interior /// mutability so the same handle serves the dial and any inspection. /// /// **Fail-closed posture**: when a policy cannot decide (its pin @@ -81,19 +81,19 @@ pub struct PresentedHostKey { #[async_trait] pub trait HostKeyPolicy: Send + Sync + 'static { /// Decides the trust verdict for one presented host key: `true` - /// accepts the key for this dial, `false` declines it — the dial + /// accepts the key for this dial, `false` declines it; the dial /// connection aborts on decline (russh's `check_server_key` /// `false` → `Error::UnknownKey`, a hard, clean decline; a /// mismatched pin is a hard decline, never a soft failure). async fn decide(&self, presented: &PresentedHostKey) -> bool; } -/// The built-in default host-key policy — **fail-closed**: reject +/// The built-in default host-key policy, **fail-closed**: reject /// every presented key. /// /// russh's own reject-all default, kept as the crate's built-in /// default policy (`docs/architecture/auth.md` §Host-key policy). A -/// dial that ships this policy can never connect — by design: trust +/// dial that ships this policy can never connect, by design: trust /// is the assembly's decision to make, and the crate's default must /// never let a dial through on the crate's authority. There is no /// accept-all counterpart in the crate; the permissive case-2 policy diff --git a/src/key_source.rs b/src/key_source.rs index 1c62716..3eb4d96 100644 --- a/src/key_source.rs +++ b/src/key_source.rs @@ -1,4 +1,4 @@ -//! The vault-backed key sources — ADR-005's custody model in code, +//! The vault-backed key sources: ADR-005's custody model in code, //! both directions (client dial keys, server host keys). //! //! The adapter takes *key sources*, not static keys (the alkhttp @@ -7,14 +7,14 @@ //! implements them over an injected alkvault handle. The crate ships //! the vault-backed implementations for the ADR-005 shape //! ([`VaultKeySource`] for one dial key, [`VaultHostKeySource`] for -//! the host-key set) along with the decrypt-at-use chain they run — +//! the host-key set) along with the decrypt-at-use chain they run: //! the custody machinery is the crate's, the at-rest storage is the //! assembly's. //! //! Crate rules, per ADR-005: //! //! - **`EncryptedData` is opaque** (decision 5): blobs flow through -//! this module to `VaultServiceHandle::decrypt` untouched — no +//! this module to `VaultServiceHandle::decrypt` untouched: no //! `key_version` interpretation, no record-internals access //! anywhere in the crate; version semantics belong to the vault. //! - **At-use lifecycle** (decision 2): `vault.decrypt(blob)` → @@ -24,7 +24,7 @@ //! needed only at use time: locking the vault mid-session keeps //! live sessions streaming while new loads fail (POC-2 §2). //! - **Inner format is OpenSSH private-key PEM, unencrypted** -//! (decision 1) — the source contract assumes it; the decode call +//! (decision 1), which the source contract assumes; the decode call //! is the single conversion. A plaintext that is not that shape is //! a [`KeySourceError::Decode`] refusal, not a fallback. //! - **Failure modes are fail-closed with distinct variants** @@ -35,7 +35,7 @@ //! - **Plaintext never persists** (decision 7): no disk spill on this //! path, ever. //! - Vault lifecycle is the assembly's: this module never unlocks -//! the vault and never retries — a locked vault stays a refusal. +//! the vault and never retries; a locked vault stays a refusal. use alkvault::{EncryptedData, VaultServiceError, VaultServiceHandle}; use async_trait::async_trait; @@ -44,7 +44,7 @@ use zeroize::Zeroizing; use crate::error::KeySourceError; -/// The client dial-key source seam — the handle the wave-4 dial-config +/// The client dial-key source seam, the handle the wave-4 dial-config /// carries (never a static key, never env material). /// /// Produces the decoded [`PrivateKey`] for one dial, decrypt-at-use: @@ -52,12 +52,12 @@ use crate::error::KeySourceError; /// key outlives any vault state change (locking mid-session keeps /// established sessions streaming; POC-2 §2). Implementations must be /// fail-closed: a load that cannot produce key material returns the -/// matching [`KeySourceError`] variant — every variant is a +/// matching [`KeySourceError`] variant; every variant is a /// no-dial outcome, and there is no fallback key shape in the crate. /// /// The handle shape is the family's injected-handle pattern /// (`Arc`, the alkcall `IdentityProvider` precedent): -/// object-safe via `async_trait`, shared by reference — the vault +/// object-safe via `async_trait`, shared by reference; the vault /// handle rides the implementation (the assembly clones its /// [`VaultServiceHandle`] into its source). The crate's ADR-005 /// implementation is [`VaultKeySource`]; an assembly may implement the @@ -65,7 +65,7 @@ use crate::error::KeySourceError; /// contract (OpenSSH-PEM, unencrypted). #[async_trait] pub trait KeySource: Send + Sync + 'static { - /// Loads the dial key — decryption plus the one-time + /// Loads the dial key: decryption plus the one-time /// `decode_secret_key` (ADR-005 decision 2). /// /// This is the only surface where the dial direction touches @@ -75,38 +75,38 @@ pub trait KeySource: Send + Sync + 'static { async fn load(&self) -> Result; } -/// The server host-key source seam — the handle the wave-2 +/// The server host-key source seam, the handle the wave-2 /// serve-config carries (ADR-005 decision 6). /// -/// Produces the decoded host-key set for server construction — +/// Produces the decoded host-key set for server construction, /// decrypt-**at-construction**: the wave-2 `Config` builder calls /// [`HostKeySource::load`] when it assembles the server, and a failure /// means no server is constructed (POC-2 §5; locked vault at /// bootstrap → [`KeySourceError::Locked`] → fail-closed, never a /// half-configured server). The crate is policy-blind on host *pin* -/// trust — that is the [`crate::HostKeyPolicy`] seam's business — this +/// trust (that is the [`crate::HostKeyPolicy`] seam's business); this /// seam is only the *held* material (the client's host pin is public /// config, never vault material). /// /// The set, not a single key: `Config::keys` accepts multiple /// host keys and fleets rotate them. Implementations must be -/// fail-closed in the same shape as [`KeySource`] — see the trait's +/// fail-closed in the same shape as [`KeySource`]; see the trait's /// docs. The crate's ADR-005 implementation is [`VaultHostKeySource`]. #[async_trait] pub trait HostKeySource: Send + Sync + 'static { - /// Loads the host-key set — each blob through the same + /// Loads the host-key set, each blob through the same /// decrypt-at-use chain as [`KeySource::load`]. Order follows the /// source's registration order. async fn load(&self) -> Result, KeySourceError>; } -/// The ADR-005 dial-key source — decrypt-at-use over an injected +/// The ADR-005 dial-key source, decrypt-at-use over an injected /// alkvault handle, backed by one at-rest `EncryptedData` record. /// /// The record is injected at construction, from the assembly's /// registry (`None` = the assembly holds no record at this key's /// location → [`KeySourceError::Absent`], POC-2 §3). The vault handle -/// is a clone of the assembly's — this source never unlocks, locks, or +/// is a clone of the assembly's; this source never unlocks, locks, or /// retries the vault's lifecycle state; every [`VaultKeySource::load`] /// is decrypt-at-usage and a locked vault is a clean /// [`KeySourceError::Locked`] refusal. @@ -134,11 +134,11 @@ impl KeySource for VaultKeySource { } } -/// The ADR-005 host-key source — decrypt-at-construction over an +/// The ADR-005 host-key source, decrypt-at-construction over an /// injected alkvault handle, backed by the injected at-rest record set. /// /// Each element of the set flows through the same decrypt-and-decode -/// chain as [`VaultKeySource`] (one model, both directions — +/// chain as [`VaultKeySource`] (one model, both directions; /// POC-2 §5). An empty set is [`KeySourceError::Absent`] (a host key /// registration gap), which the wave-2 config builder treats exactly /// like every other load failure: no server is constructed. @@ -175,7 +175,7 @@ impl HostKeySource for VaultHostKeySource { /// The plaintext leaves the vault as /// [`KeySourceError`]-mapped failure or as alkvault 0.2's /// `Zeroizing` return (the pre-wrap unfenced window ADR-005 -/// decision 3 recorded is closed upstream — the vault fences the +/// decision 3 recorded is closed upstream: the vault fences the /// plaintext from its return onward, zeroized on drop, including the /// vault's own UTF-8 failure path; OQ-07's upstream ask is resolved, /// amending the ADR's decision 3 note). The decode is the single @@ -189,28 +189,28 @@ fn decrypt_and_decode( decode_key_arm(&plaintext) } -/// The at-use chain's decode arm — the one-time +/// The at-use chain's decode arm: the one-time /// [`decode_secret_key`] conversion of [`decrypt_and_decode`] /// (ADR-005 decision 2's single conversion; this function is byte-for- /// byte that arm, extracted so the arm is the *only* shape the fuzz /// target drives). `#[doc(hidden)]` fuzz-visible surface -/// (`w5-fuzz-harness`; the recorded exposure decision — the ingress is +/// (`w5-fuzz-harness`; the recorded exposure decision: the ingress is /// production-private, so the exposure is the production arm itself, /// not a fork). Not documented API: the vault-facing surface is /// exactly [`VaultKeySource`] / [`VaultHostKeySource`]. /// /// The `Zeroizing` posture rides the signature: the plaintext -/// arrives already zeroized (alkvault 0.2's return type — decision +/// arrives already zeroized (alkvault 0.2's return type, decision /// 3's ownership moved upstream), the decode reads -/// it once, and nothing is retained — `Ok` carries the decoded +/// it once, and nothing is retained: `Ok` carries the decoded /// [`PrivateKey`], `Err` carries only the typed [`KeySourceError`] /// class (never the plaintext). /// /// The typed `Decode` payload is crate-owned fixed text, deliberately /// *not* the underlying machinery's message (the `w5-fuzz-harness` /// finding, 2026-10-30): russh's/`ssh-key`'s PPK parse path -/// (`PpkParseError::Header`) interpolates raw header bytes — the -/// plaintext's own material — into its Display, so a machinery message +/// (`PpkParseError::Header`) interpolates raw header bytes, the +/// plaintext's own material, into its Display, so a machinery message /// riding the typed payload would echo decrypted-record material /// exactly the no-persist posture (decision 7) forbids. The upstream /// echo ask is recorded with the task; if the machinery gains an @@ -219,7 +219,7 @@ fn decrypt_and_decode( pub fn decode_key_arm(plaintext: &Zeroizing) -> Result { decode_secret_key(plaintext, None).map_err(|_| { KeySourceError::Decode( - "the plaintext is not OpenSSH private-key PEM material — the decode machinery \ + "the plaintext is not OpenSSH private-key PEM material; the decode machinery \ refused it (the machinery's message is not carried: it can echo plaintext \ material; the upstream echo ask is recorded)" .to_owned(), @@ -228,18 +228,18 @@ pub fn decode_key_arm(plaintext: &Zeroizing) -> Result KeySourceError { @@ -273,14 +273,14 @@ mod tests { use crate::error::KeySourceError; use crate::fingerprint::fingerprint; - /// The committed test-key fixtures (`tests/vectors/`) — the + /// The committed test-key fixtures (`tests/vectors/`), the /// wave-1 fixture set, read by this `#[cfg(test)]` module through /// `include_str!` (the `tests/common/mod.rs` double module is the /// tests/-side owner; src-unit tests never own fixture copies). /// Throwaway `ssh-keygen`-minted keys, never registered anywhere /// real (`ALPHA` is the client-dial fixture; `BRAVO`/`CHARLIE` /// the host-key pair). Their `ssh-keygen -lf` fingerprints are - /// recorded in `tests/vectors/fingerprints.txt` — the fixture + /// recorded in `tests/vectors/fingerprints.txt`; the fixture /// parity row below asserts this module sees the same values. const ALPHA_PEM: &str = include_str!("../tests/vectors/alpha.key"); const BRAVO_PEM: &str = include_str!("../tests/vectors/bravo.key"); diff --git a/src/lib.rs b/src/lib.rs index 400ca56..ed40afa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,61 +1,61 @@ -//! alkssh — the alk family's SSH adapter (the alkhttp-style door for the +//! alkssh, the alk family's SSH adapter (the alkhttp-style door for the //! SSH protocol): a thin wrapper around russh terminating the vanilla-ssh //! wire and bridging to/from alkcall channels (the `alk/ssh` ALPN). //! //! No SSH framing is authored in-family (family ADR-003): russh owns the -//! wire, and the crate's substance is the channel-type mappings — +//! wire, and the crate's substance is the channel-type mappings: //! session/pty → alktty, direct/forwarded-tcpip → alktunnels, git exec → //! alkgit, sftp → alkfs later (a declining placeholder until then), each //! behind its cargo feature. Git over SSH is exec-only (ADR-006): a //! subsystem request can never carry the repository, so it declines. A //! client opening an unfeatured or unimplemented channel type gets a -//! clean decline — never a half-capability, never a silent fallback; the +//! clean decline, never a half-capability, never a silent fallback; the //! default build (no features) is structurally incapable of serving //! anything but declines. //! //! Identity is the family's, not SSH's: a verified key's fingerprint → //! alkcall `IdentityProvider`. Keys the crate holds (client dial keys, -//! host keys) come from alkvault-backed sources — vault-encrypted at +//! host keys) come from alkvault-backed sources, vault-encrypted at //! rest, decrypted at use (ADR-005), never env vars. //! -//! Architecture: `docs/architecture/` (phase 1 — ADRs 001–006 accepted; +//! Architecture: `docs/architecture/` (phase 1: ADRs 001–006 accepted; //! the foundations, the server stack, the server-direction mappings, and -//! the client direction — dial, op rows, the `-R` acceptor leg, and the -//! lifecycle primitives — are landed through wave 4; the validation +//! the client direction (dial, op rows, the `-R` acceptor leg, and the +//! lifecycle primitives) are landed through wave 4; the validation //! suite and the release are wave 5). See also `docs/research/`, //! `docs/plans/implementation.md`, and family ADR-003. //! -//! # The feature graph (ADR-003 — flat, independent, fail-closed) +//! # The feature graph (ADR-003: flat, independent, fail-closed) //! //! Every channel-type mapping is a cargo feature; a session opening an -//! unfeatured or unimplemented channel type is declined fail-closed — +//! unfeatured or unimplemented channel type is declined fail-closed, //! never a half-capability, never a silent fallback. **A default build //! (no features) has no capabilities**: it can serve nothing but clean //! declines. No feature implies another; the graph is flat. //! -//! - (default, no features) — serves declines only: every open, exec, +//! - (default, no features) serves declines only: every open, exec, //! listen request answers a clean, channel-scoped refusal. -//! - `session` — pty/shell/exec rows → the `RemoteSession` chunk +//! - `session` maps the pty/shell/exec rows → the `RemoteSession` chunk //! plane (alktty). -//! - `git` — the exec-only git rows (`git-{upload,receive}-pack`) → +//! - `git` carries the exec-only git rows (`git-{upload,receive}-pack`) → //! alkgit; a git *subsystem* request always declines (the repository //! can never ride a subsystem channel). -//! - `tunnel` — `direct-tcpip` / `direct-streamlocal` and the `-R` +//! - `tunnel` covers `direct-tcpip` / `direct-streamlocal` and the `-R` //! legs (listen, `forwarded-tcpip` / `forwarded-streamlocal`) → //! alktunnels. -//! - `sftp` — a reserved, currently-empty placeholder (OQ-13): the +//! - `sftp`, a reserved, currently-empty placeholder (OQ-13): the //! `sftp` subsystem request still declines in every build until the //! alkfs mapping lands; the feature exists so the decline stays //! contract territory (tested in every matrix build). //! //! Advertisement is honest: an unfeatured channel type is never //! advertised, only declined (`docs/architecture/mapping.md` §Decline -//! matrix — the fail-closed invariant is contract territory on both +//! matrix; the fail-closed invariant is contract territory on both //! sides of every feature). //! //! # Known limits (recorded dispositions riding the published docs) //! -//! The records below are deliberate dispositions — documented limits +//! The records below are deliberate dispositions: documented limits //! with their reasons, mirrored in the module docs and the //! architecture spec, not defects awaiting a fix: //! @@ -64,29 +64,29 @@ //! per-channel window, the client's own flow control) and liveness //! is covered by the always-set //! [`Limits::inactivity_timeout`]; a deadline here would be a -//! behavior change (a slow client may stall its stream — vanilla +//! behavior change (a slow client may stall its stream, vanilla //! sshd's posture included). (`tty_map.rs` module docs.) //! - **The PTY path's exit-signal fidelity is limited by upstream** //! (exit-currency rule 5): signal-terminated PTY sessions surface as //! `exit-status(1)` because the backend's reap surface loses the //! signal number; the pipe path encodes negatives faithfully. An -//! alktty/portable-pty ask — the contract adapts automatically +//! alktty/portable-pty ask; the contract adapts automatically //! when upstream conforms. //! - **The port-0 mint is the only bound-port echo the wire carries** //! (russh/sshd parity): a `tcpip_forward` success reply carries the //! allocated port only for a `port = 0` request; an explicit-port -//! request's bound port is by definition the requested one — the +//! request's bound port is by definition the requested one; the //! crate surfaces it as such, never a fabricated number. //! - **No reconnect/restore policy.** The client direction ships //! lifecycle *primitives* (bound ports, cancellable handles, clean //! [`SshConnection::close`]); reconnect-and-restore (rebinding -//! persisted tunnel ports) is assembly composition over them — the +//! persisted tunnel ports) is assembly composition over them; the //! crate never owns the policy. Drop is never the clean path at //! this russh pin: only an explicit `close` sends the clean //! disconnect. //! - **No accept-all host-key policy exists in the crate.** The //! built-in default is [`RejectAll`] (a dial with it can never -//! connect — by design); the crate is policy-blind and any +//! connect, by design); the crate is policy-blind and any //! permissive trust policy is the assembly's to write. A //! fail-closed policy posture: when a policy cannot decide, it must //! decline. @@ -96,10 +96,10 @@ //! The crate is a door, not a deployment: an assembly embeds it, //! enables the features it wants, and injects the seams (identity, //! key sources, the per-feature family handles). The examples are -//! compile-checked (`no_run`) doctests — honest sketches, not +//! compile-checked (`no_run`) doctests, honest sketches, not //! executable code. //! -//! A server mount (the default build — a decline-only door; the +//! A server mount (the default build, a decline-only door; the //! assembly's real sources are the vault-backed [`VaultKeySource`] / //! [`VaultHostKeySource`] shapes): //! @@ -151,7 +151,7 @@ //! ``` //! //! A dial (the client direction; the built-in [`RejectAll`] -//! host-key policy connects to nothing — by design, the assembly's +//! host-key policy connects to nothing, by design, and the assembly's //! policy replaces it): //! //! ```rust,no_run @@ -182,7 +182,7 @@ //! # { //! # let _ = conn.exec("uptime"); // the op rows (feature-gated) //! # } -//! conn.close().await; // clean disconnect — drop is never the clean path +//! conn.close().await; // clean disconnect; drop is never the clean path //! # Ok::<(), alkssh::DialError>(()) //! # })?; //! # Ok(()) @@ -225,7 +225,7 @@ pub use client::dial; pub use client::russh_client_config; /// The `-R` leg's acceptor registry + the reverse-listen rows' /// payload/acceptor types + the listener handles (`w4-reverse-listen` -/// / `w4-lifecycle` — under `tunnel`; the recorded decisions live in +/// / `w4-lifecycle`, under `tunnel`; the recorded decisions live in /// the `client_accept` module docs). #[cfg(feature = "tunnel")] pub use client_accept::{ @@ -235,14 +235,14 @@ pub use client_accept::{ #[doc(hidden)] pub use client_handler::ClientHandler; /// The client op rows' surfaces (`w4-op-rows`): -/// [`RemoteSession`] — the exec/pty rows' +/// [`RemoteSession`]; the exec/pty rows' /// family chunk plane (under `session`), -/// [`TunnelChannel`] — the direct +/// [`TunnelChannel`]; the direct /// rows' byte duplex (under `tunnel`), -/// [`GitPackSession`] — the upstream git +/// [`GitPackSession`]; the upstream git /// row's pack duplex + consumed exit (under `git`). The op methods /// live on [`SshConnection`] (the op-row surface). Not a re-export -/// here: the `sftp` row is [`SshConnection::sftp`] itself — the +/// here: the `sftp` row is [`SshConnection::sftp`] itself, the /// every-build OQ-13 decline placeholder. #[cfg(feature = "git")] pub use client_ops::GitPackSession; @@ -258,7 +258,7 @@ pub use config::SessionSeam; pub use config::TunnelListenSeam; pub use config::{DialConfig, Limits, ServeConfig}; /// Fuzz-visible surface (`#[doc(hidden)]`, `w5-fuzz-harness`): the exec -/// grammar's parse path (`dispatch.rs`) — the `fuzz/` sidecar's +/// grammar's parse path (`dispatch.rs`); the `fuzz/` sidecar's /// `exec_parse` target drives the production parse, never a fork. Not /// documented API: the grammar is the dispatch seam's, not a public-API /// promise. @@ -267,7 +267,7 @@ pub use dispatch::{ExecDecline, ExecRoute, GitServiceRoute, parse_exec}; pub use error::{AdapterError, DialError, KeySourceError, OpError, OpenDeclineReason}; pub use fingerprint::fingerprint; /// Contract-test surface (`#[doc(hidden)]`): the per-connection auth -/// bridge handler — constructible so the tests drive its hooks directly +/// bridge handler, constructible so the tests drive its hooks directly /// against the wave-1 doubles (see `handler.rs` §Test surface). Not /// documented API: the wire-facing surface is exactly `SshAdapter` + /// the config/error/host/key-source types. @@ -281,7 +281,7 @@ pub use host_key::{HostKeyPolicy, PresentedHostKey, RejectAll}; pub use key_source::decode_key_arm; pub use key_source::{HostKeySource, KeySource, VaultHostKeySource, VaultKeySource}; /// Contract-test surface (`#[doc(hidden)]`): the spawn-and-return -/// plumbing (`ADR-006 decision 4`, see `serve.rs`) — the mechanics the +/// plumbing (`ADR-006 decision 4`, see `serve.rs`), the mechanics the /// mechanics-proof rows in `tests/spawn_return.rs` compose over the /// real wire to pin the constraint as tests. Not documented API. #[doc(hidden)] diff --git a/src/observe.rs b/src/observe.rs index 23fcbcf..b578731 100644 --- a/src/observe.rs +++ b/src/observe.rs @@ -1,5 +1,5 @@ //! The decline-path + serving-path event vocabulary -//! (`w3-decline-tracing` — the wave-2 gate's booked finding): the +//! (`w3-decline-tracing`, the wave-2 gate's booked finding): the //! observability surface every decline site in `src/` emits through, //! and the serving-path lifecycle skeleton ([`serving_path_started`] / //! [`serving_path_ended`] / [`serving_path_failed`]) the wave-3 @@ -7,7 +7,7 @@ //! //! ## The family posture read (2026-10-28) //! -//! Read before choosing this shape — no alkssh-private dialect: +//! Read before choosing this shape; no alkssh-private dialect: //! //! - `alktty` (`adapter.rs`, `session.rs`, `local/pipe.rs`, //! `local/pty.rs`): free `tracing::{debug, warn}` imports, @@ -18,7 +18,7 @@ //! (`listen = …`, `error = %e`, `reason = …`), levels `debug` for //! structural observations, `warn` for recoverable failures, //! `error` for abnormal pump terminations. -//! - `alkcall` (`protocol/*`, `channels/*`): the widest use — the same +//! - `alkcall` (`protocol/*`, `channels/*`): the widest use, with the same //! fields convention (`channel_id`, `request_id`, `error = %e`), //! component-prefixed messages (`"channel client: …"`, //! `"open wrapper: …"`), `debug`/`warn` only. @@ -27,7 +27,7 @@ //! - `alkgit`: no tracing at all at this writing. //! //! Never observed in the family: `info!` / `trace!` events, subscriber -//! setup in library code, macro or span wrappers — so none here +//! setup in library code, macro or span wrappers, so none here //! either. Adopted verbatim: free `tracing` fn calls, message-last //! lowercase with the `"decline: …"` / `"serving path …"` phrasing, //! flat per-event fields (`feature_build`, `row`, `channel_id`, @@ -37,91 +37,91 @@ //! //! Every event carries exactly: //! -//! - `feature_build = FEATURE_BUILD` — the crate's compile-time +//! - `feature_build = FEATURE_BUILD`: the crate's compile-time //! feature set as a stable string (`"none"`, `"git"`, //! `"session+git"`, …; features joined in the order `session, git, //! tunnel, sftp`), so a captured event is self-describing per //! build. The `sftp` feature gates no route, but ships in the //! build string: it is part of what the assembly deployed. -//! - `row` — the greppable wire row the event is about: the channel +//! - `row`: the greppable wire row the event is about, the channel //! type for open-level (e.g. `"session"`, `"direct-tcpip"`, `"x11"`), //! the request name for request-level (e.g. `"pty_request"`, //! `"tcpip_forward"`), the handler hook name for auth (e.g. //! `"auth_publickey"`), the session-row hook names for the //! serving-path lifecycle. -//! - `channel_id` — the wire channel id (u32), on every event of a +//! - `channel_id`: the wire channel id (u32), on every event of a //! channel; the auth class has none (the auth hooks carry no //! channel at this surface). //! //! Decline events additionally carry exactly: //! -//! - `decline_class` — `"open"` | `"request"` | `"serving"` | +//! - `decline_class`: `"open"` | `"request"` | `"serving"` | //! `"arrival"` | `"auth"`: //! the two wire decline classes of `mapping.md` §Wire decline //! reasons, plus the serving-path class (this wave the seam stub's //! decline *is* the serving path; the wave-3 mappings emit the same //! class from their real spawned paths) and the auth class (the //! disposition declines of ADR-004). -//! - `reason` — the decline cause, mirroring the architecture's own +//! - `reason`: the decline cause, mirroring the architecture's own //! classifications: `"unfeatured"` (feature-gate absence), //! `"never-feature"` (ADR-003 §5 rows), `"cap-exceeded"`, //! `"connect-failed"` (`w3-tunnel-direct`: the tunnel rows' -//! cannot-bridge class — the failed fabric open, the wave-2 seam +//! cannot-bridge class: the failed fabric open, the wave-2 seam //! stub's reason surviving as the real decline; also the //! `forwarded-tcpip` stub's standing decline class), -//! `"seam-unconfigured"` (the config-driven row decline — the git +//! `"seam-unconfigured"` (the config-driven row decline: the git //! row and, now, the session rows (feature on, seam unset; //! `w3-git-mapping` / `w3-tty-session`) and the tunnel rows' absent //! fabric handle even under the feature (`w3-tunnel-direct`; the //! unset-declines posture)), //! `"shell-unconfigured"` / `"wrapper-unconfigured"` (`w3-tty- -//! session`: the OQ-08 unset-field rows — feature on, the +//! session`: the OQ-08 unset-field rows (feature on, the //! serve-config field unset, never a fallback), //! `"negotiation-failed"` (`w3-tty-session`: the alktty -//! negotiation error frame the bridge received — the session never +//! negotiation error frame the bridge received; the session never //! started; the frame's JSON detail stays alktty-side), //! `"unknown-service"` / `"service-only"` / `"invalid-repo-id"` -//! (the exec grammar's git declinables — the parse core's two and +//! (the exec grammar's git declinables: the parse core's two and //! the git row's validation gate; no service token or repo string -//! ever rides — only the vocabulary value), +//! ever rides, only the vocabulary value), //! `"exec-oversize"` (the pre-parse `max_exec_command_len` cap), //! `"invalid-target"` (`w3-tunnel-direct`: the direct rows' -//! impossible wire target — an out-of-range `direct-tcpip` port), +//! impossible wire target, an out-of-range `direct-tcpip` port), //! `"unix-unavailable"` (`w3-tunnel-direct`: the OQ-11 runtime-Unix -//! gate — the off-Unix `direct-streamlocal` decline, answered +//! gate: the off-Unix `direct-streamlocal` decline, answered //! before any fabric call), //! `"no-identity"` / `"channel-not-held"` (the git row's serving- -//! path guards — unreachable in practice, fail-closed; the tunnel -//! rows' open-level `no-identity` guard rides the same value — +//! path guards (unreachable in practice, fail-closed); the tunnel +//! rows' open-level `no-identity` guard rides the same value, //! reachable never, on the wire, for the same reason), -//! `"unimplemented"` (the subsystem rows — OQ-13), +//! `"unimplemented"` (the subsystem rows, OQ-13), //! `"declined-by-design"` (env, OQ-09), //! `"correlation-miss"` / `"cap-exceeded"` / `"accept-refused"` / //! `"unvanilla-inbound"` (`w3-tunnel-listen`: the `-R` leg's arrival -//! declines — the class whose events carry the minted `listen` token -//! instead of a channel id — and the unvanilla inbound +//! declines, the class whose events carry the minted `listen` token +//! instead of a channel id, and the unvanilla inbound //! `forwarded-tcpip` open), //! `"listen-failed"` / `"no-such-listen"` (`w3-tunnel-listen`: the //! listen dial's failed/bounded outcome and the cancel forms' -//! not-found pair) — the global-request and arrival rows, and on the -//! auth class `"method-unimplemented"` / `"cert-unsupported"` / +//! not-found pair), belonging to the global-request and arrival +//! rows; on the auth class, `"method-unimplemented"` / `"cert-unsupported"` / //! `"non-ed25519"` / `"fingerprint-unresolved"`. //! Client-side (the dial handler's `server_channel_open_*` -//! skeleton, `w4-dial`): `"no-acceptor"` (the decline-all default — +//! skeleton, `w4-dial`): `"no-acceptor"` (the decline-all default: //! a server-initiated open with no registered acceptor; the //! registry is `w4-reverse-listen`'s) and `"never-feature"` (the -//! x11/agent rows — ADR-003 §5). -//! - `exec_route` — only on `exec_request`-row events: the dispatch +//! x11/agent rows, ADR-003 §5). +//! - `exec_route` rides only `exec_request`-row events: the dispatch //! route the parse routed to (`"git"` | `"pipe"`), so a git row's //! decline is distinguishable from a pipe row's in combined builds. //! Other rows carry none (a `None` field is not recorded by //! `tracing`). //! //! Levels: declines and the lifecycle's started/ended emit at -//! `debug` — a decline is the door's normal, honest posture (vanilla +//! `debug`: a decline is the door's normal, honest posture (vanilla //! clients probe unfeatured rows routinely; nothing abnormal //! happened), matching the family's structural-observation level. -//! Only [`serving_path_failed`] is `warn` — a serving path that could +//! Only [`serving_path_failed`] is `warn`: a serving path that could //! not complete its wire reporting is a real failure (the family's //! recoverable-failure level). //! @@ -129,11 +129,11 @@ //! //! **No secret material ever enters an event; never the username.** //! Structurally enforced, not recalled: the helpers take only -//! `&'static str` vocabulary values and the wire channel id — there +//! `&'static str` vocabulary values and the wire channel id; there //! is no parameter a username, command string, env name/value, repo //! path, key, or fingerprint could ride. In particular *the //! fingerprint stays out of the events* (`auth.md` §Dispositions: log -//! exposure is deployment policy — the crate's events are +//! exposure is deployment policy; the crate's events are //! safe-by-default at every level, so the fingerprint is a //! deployer-side computation over its own logs, never crate-emitted). //! The `error` field carries only russh protocol errors. The wire @@ -141,7 +141,7 @@ //! appears in any captured field. If a future decline site needs //! request-argument detail (e.g. the git grammar's decline reasons in //! `w3-git-mapping`), it must add an explicitly-vocabulary'd field and -//! record its safety reasoning — dynamic strings do not ride this +//! record its safety reasoning; dynamic strings do not ride this //! module by default. /// The compile-time feature set, as a stable string (`"none"`, @@ -194,7 +194,7 @@ pub(crate) fn decline_open(row: &'static str, reason: &'static str, channel_id: /// build does not serve (`subsystem` / `env` / `x11` / agent, an /// unfeatured parse route) or a not-yet-landed listen form. The wire /// answer is `channel_failure` (the channel stays usable) or the -/// denied-request reply — the event is the deciding context. +/// denied-request reply; the event is the deciding context. pub(crate) fn decline_request( row: &'static str, reason: &'static str, @@ -214,7 +214,7 @@ pub(crate) fn decline_request( /// An auth-class decline: a disposition of the ADR-004 bridge turned /// the method away. No channel id exists at this surface; the -/// *fingerprint never rides the event* (see §Safety posture) — the +/// *fingerprint never rides the event* (see §Safety posture); the /// `reason` codes distinguish the decline causes without exposing who. pub(crate) fn decline_auth(row: &'static str, reason: &'static str) { tracing::debug!( @@ -226,7 +226,7 @@ pub(crate) fn decline_auth(row: &'static str, reason: &'static str) { ); } -/// A request-level decline on a **global** request — the `-R` listen +/// A request-level decline on a **global** request: the `-R` listen /// forms (`mapping.md` §Global-request rows). No channel id exists at /// this surface; the fields are otherwise the `request` vocabulary. pub(crate) fn decline_global_request(row: &'static str, reason: &'static str) { @@ -241,12 +241,12 @@ pub(crate) fn decline_global_request(row: &'static str, reason: &'static str) { /// A decline on the `-R` leg's **arrival** surface (`w3-tunnel- /// listen`): a fabric inbound forwarded open that cannot become an -/// SSH channel — `correlation-miss` (no route for the minted token — +/// SSH channel: `correlation-miss` (no route for the minted token, /// teardown-at-birth), `cap-exceeded` (the per-arrival admission), or -/// `accept-refused` (the vanilla client rejected the SSH open — the +/// `accept-refused` (the vanilla client rejected the SSH open; the /// count released, never a half-open channel). No SSH channel id /// exists yet at this surface (that is the point of the declines), so -/// the minted `listen` token — the correlation key itself — rides +/// the minted `listen` token (the correlation key itself) rides /// instead; the token is bookkeeping metadata (the producer's minted /// correlation number), never secret material. #[cfg(feature = "tunnel")] @@ -265,7 +265,7 @@ pub(crate) fn decline_arrival(row: &'static str, reason: &'static str, listen: u /// failure-then-close rather than serving. This wave that is the seam /// stub (the wire shape pinned in `tests/spawn_return.rs`); the wave-3 /// mappings emit it from their real spawned paths wherever serving -/// itself cannot proceed — the class the spawned paths inherit. +/// itself cannot proceed, the class the spawned paths inherit. #[cfg(any(feature = "git", feature = "session"))] pub(crate) fn decline_serving( row: &'static str, @@ -284,7 +284,7 @@ pub(crate) fn decline_serving( ); } -/// Spawned-path started — emitted as the spawned task's first action, +/// Spawned-path started, emitted as the spawned task's first action, /// so "started" is the task's own honest start, not the hook's spawn /// call. The mapping tasks' serving paths inherit this shape. #[cfg(any(feature = "git", feature = "session", feature = "tunnel"))] @@ -302,7 +302,7 @@ pub(crate) fn serving_path_started( ); } -/// Spawned-path ended — the serving future finished (cleanly, or with +/// Spawned-path ended: the serving future finished (cleanly, or with /// the decline it was wired to answer); emitted *after* the path's /// wire reporting has completed. #[cfg(any(feature = "git", feature = "session", feature = "tunnel"))] @@ -320,14 +320,14 @@ pub(crate) fn serving_path_ended( ); } -/// Spawned-path failure — the serving path could not complete its +/// Spawned-path failure: the serving path could not complete its /// wire reporting (the session handle's sends failed: the session is -/// gone, or the report never landed). The vocabulary's one `warn` — +/// gone, or the report never landed). The vocabulary's one `warn`, /// the family's recoverable-failure level. Only russh protocol errors /// ride the `error` field (§Safety posture); the mapping tasks emit /// this from their real paths when serving fails before reporting. /// (The tunnel bridge never calls this: its wire reporting is -/// open-level — `accept`/`reject` cannot fail send-wise — so the fn +/// open-level (`accept`/`reject` cannot fail send-wise), so the fn /// stays gated to the git/session rows.) #[cfg(any(feature = "git", feature = "session"))] pub(crate) fn serving_path_failed( @@ -350,7 +350,7 @@ pub(crate) fn serving_path_failed( mod tests { use tracing::subscriber::with_default; - /// A fake error shape — the failure row only pins that a Debug + /// A fake error shape; the failure row only pins that a Debug /// error value rides the `error` field. #[derive(Debug)] #[cfg(any(feature = "git", feature = "session"))] @@ -362,10 +362,10 @@ mod tests { /// A minimal field-capturing visitor shared by these rows and the /// wire rows in `tests/observe.rs` (the test convention recorded - /// in the task notes — the family has no event-capture precedent, + /// in the task notes: the family has no event-capture precedent, /// only alktunnels' fmt-subscriber dev-dep for debug output, so /// the convention is a hand-rolled minimal [`tracing::Subscriber`] - /// — no `tracing-subscriber` dependency). + /// with no `tracing-subscriber` dependency). struct Visitor(Vec<(String, String)>); impl tracing::field::Visit for Visitor { @@ -379,7 +379,7 @@ mod tests { } /// Captures the fields of the one event the emit fn fires, via - /// the thread-local default subscriber (`with_default` — these + /// the thread-local default subscriber (`with_default`; these /// are direct helper rows; the spawned-task surfaces are driven /// over the wire in `tests/observe.rs` against the global /// capture). @@ -425,8 +425,8 @@ mod tests { .unwrap_or_else(|| panic!("no field {name} in {fields:?}")) } - /// - *Contract stamp:* the event vocabulary (`w3-decline-tracing`) - /// — an open decline carries exactly the base shape, values + /// - *Contract stamp:* the event vocabulary (`w3-decline-tracing`): + /// an open decline carries exactly the base shape, values /// included. #[test] fn decline_open_carries_the_full_vocabulary() { @@ -449,11 +449,11 @@ mod tests { "reason".to_owned(), ], "an open decline carries exactly the vocabulary, nothing else \ - (the message field first — the event! macro's shape)" + (the message field first, per the event! macro's shape)" ); } - /// - *Contract stamp:* the `exec_route` field — present on the + /// - *Contract stamp:* the `exec_route` field: present on the /// exec row, absent elsewhere (a `None` field is not recorded /// by `tracing`). #[test] @@ -480,7 +480,7 @@ mod tests { assert_eq!(field(&fields, "reason"), "method-unimplemented"); } - /// - *Contract stamp:* the `exec_route` field — present on the + /// - *Contract stamp:* the `exec_route` field: present on the /// exec row, absent elsewhere (a `None` field is not recorded /// by `tracing`). The pty/shell lifecycle rows carry no route. #[cfg(any(feature = "git", feature = "session"))] @@ -503,9 +503,9 @@ mod tests { assert_eq!(field(&fields, "error"), "Probe"); } - /// - *Contract stamp:* the arrival vocabulary (`w3-tunnel-listen`) - /// — an arrival decline carries the minted `listen` token - /// instead of a channel id (none exists yet — that is the point + /// - *Contract stamp:* the arrival vocabulary (`w3-tunnel-listen`): + /// an arrival decline carries the minted `listen` token + /// instead of a channel id (none exists yet; that is the point /// of the declines; the token is bookkeeping metadata, never /// secret material). #[cfg(feature = "tunnel")] @@ -530,7 +530,7 @@ mod tests { /// The feature-build string: every enabled feature appears; a /// featureless build reads `none`. The expected half is derived - /// from `cfg!` independently of the crate's match — divergence + /// from `cfg!` independently of the crate's match, so divergence /// breaks this row loudly. #[test] fn feature_build_string_reflects_the_cfgs() { diff --git a/src/serve.rs b/src/serve.rs index 97ac288..2d6a56d 100644 --- a/src/serve.rs +++ b/src/serve.rs @@ -1,22 +1,22 @@ -//! The spawn-and-return plumbing (`w2-spawn-return`) — ADR-006 +//! The spawn-and-return plumbing (`w2-spawn-return`): ADR-006 //! decision 4, the structural constraint of the whole spine, in code. //! //! russh at this pin runs server handler callbacks **inline inside the -//! session's packet loop** — a blocking handler suspends all packet +//! session's packet loop**: a blocking handler suspends all packet //! routing for the connection and deadlocks against the peer's //! immediate follow-up bytes (POC-3 proved by construction with //! receive-pack). The crate's answer is mechanical, not conventional: //! -//! - **Every serving path is spawned** ([`spawn_serving_path`]) — the +//! - **Every serving path is spawned** ([`spawn_serving_path`]): the //! handler hook clones the session handle //! (`Session::handle()`), hands it into its serving future, spawns, //! and returns. No serving path is ever awaited inline; the dispatch //! seam stubs ([`crate::handler`]) hang off this helper, so the //! wave-3 mappings inherit the pattern mechanically from the stubs. -//! The serving-path *events* (started / ended / failure — +//! The serving-path *events* (started / ended / failure, via //! [`crate::observe`]) are the spawned task's own actions: the stub //! body emits them, the mappings' real paths will too. -//! - **Exit/status reporting rides the cloned handle** — the spawned +//! - **Exit/status reporting rides the cloned handle**: the spawned //! task's only report surface is the handle clone it was handed; //! [`report_exit_status_then_close`] preserves the wire ordering the //! `mapping.md` `exit_status` row pins: `exit-status` sent **before** @@ -28,7 +28,7 @@ //! //! ## Test surface //! -//! Both helpers are re-exported `#[doc(hidden)]` from the crate root — +//! Both helpers are re-exported `#[doc(hidden)]` from the crate root, //! the `handler.rs` §Test surface pattern: the mechanics-proof rows in //! `tests/spawn_return.rs` compose them over the real wire (a minimal //! proof handler standing in for the crate's own auth/dispatch hooks, @@ -41,7 +41,7 @@ use russh::ChannelId; use russh::server::Handle; /// Spawns one serving path on its own task (ADR-006 decision 4): the -/// caller — the handler hook — clones the session handle, hands it +/// caller (the handler hook) clones the session handle, hands it /// into the serving future, calls this, and returns immediately. /// Nothing here is ever awaited inline: an inline serve deadlocks /// against the peer's follow-up bytes (POC-3 proved by construction). @@ -50,7 +50,7 @@ pub fn spawn_serving_path(serving: impl Future + Send + 'static) { } /// The spawned task's exit report through the cloned handle: -/// `exit-status(N)` then close — the ordering contract +/// `exit-status(N)` then close; the ordering contract /// (`mapping.md`'s `exit_status` row: sent **before** close, from the /// spawned task). A failed send means the session is gone; nothing is /// reportable then. @@ -67,8 +67,8 @@ mod tests { use super::spawn_serving_path; /// - *Contract stamp:* ADR-006 decision 4 (spawn-and-return: the - /// handler call returns while the serving path is still running - /// — handler-returns-fast is structural). + /// handler call returns while the serving path is still running, + /// so handler-returns-fast is structural). #[tokio::test] async fn spawn_returns_while_the_serving_path_is_still_pending() { let (release, waited) = tokio::sync::oneshot::channel::<()>(); @@ -82,7 +82,7 @@ mod tests { assert!( !done.load(Ordering::Acquire), - "the spawn call returned while the serving path was still gated — \ + "the spawn call returned while the serving path was still gated; \ no serving path is awaited inline" ); diff --git a/src/tty_map.rs b/src/tty_map.rs index 9e68f38..ce9c626 100644 --- a/src/tty_map.rs +++ b/src/tty_map.rs @@ -1,11 +1,11 @@ -//! The session mapping (`w3-tty-session`) — the biggest single-row +//! The session mapping (`w3-tty-session`), the biggest single-row //! surface of the spine ([`crate::dispatch::ExecRoute::Pipe`] + the //! `pty_request`/`shell_request` rows): pty/shell/pipe-exec serve //! through the published alktty seam //! (`drive_session_pre_negotiated(writer, reader, req, backends, //! ownership, identity)`) over a **translation bridge, not a byte //! pump** (POC-3 §D.1): alktty's data plane is chunk-framed both -//! directions (`alktty::wire` — 5-byte header + payload), the SSH +//! directions (`alktty::wire`, 5-byte header + payload), the SSH //! channel is a plain byte plane, so the bridge wraps the channel //! with small adapters around a pair of in-memory duplexes. //! @@ -15,7 +15,7 @@ //! //! - `pty_request` args → `alktty::negotiation::TerminalParamsWire` //! (`term`/`cols`/`rows`/pixel dims; SSH ttymodes → the **reserved -//! modes JSON `{}`** — alktty OQ-44's reservation: backends must +//! modes JSON `{}`** per alktty OQ-44's reservation: backends must //! ignore modes in v1, so the door writes `{}` and defers //! faithfully). Stored per channel (the POC-3 accepted-but-held //! shape, [`crate::handler`]'s store) and consumed by the later @@ -24,29 +24,29 @@ //! - `shell_request` → `NegotiateRequest{carriage: "raw", backend: //! the seam selector, tty: the consumed pty params, cmd: the //! serve-config shell argv **verbatim**, cwd: session_cwd, env: -//! session_env}` — the wire never carries command, args, cwd or +//! session_env}`, and the wire never carries command, args, cwd or //! env (OQ-08/OQ-09; the `env_request` row stays declined //! unconditionally). **A `shell_request` without a preceding pty -//! serves pipe-mode (`tty = None`)** — decided: vanilla sshd serves +//! serves pipe-mode (`tty = None`)**, decided: vanilla sshd serves //! a shell without a terminal too (`ssh -T host` is legitimate //! vanilla), so a pty-less shell request is served, never declined. //! - `exec_request` (pipe row) → `cmd = exec_wrapper_argv ++ [cmd]` -//! (the OQ-08 argv append — vanilla quoting semantics; the wire +//! (the OQ-08 argv append, vanilla quoting semantics; the wire //! command string is **never naively split**), `tty = //! Some(consumed pty)` when a pty preceded, else `None` (pipe //! mode). //! - **Unset-declines** (OQ-08, never a fallback): `shell_argv` //! unset → `shell_request` declines; `exec_wrapper_argv` unset → //! the pipe row declines. Wire shape (decided + recorded): the -//! **serving-path shape — `channel_failure` then channel close, +//! **serving-path shape: `channel_failure` then channel close, //! from a spawned task** ([`crate::serve`]'s mechanics; the same -//! spawned-stub body the git row uses) — the class of a routable +//! spawned-stub body the git row uses), the class of a routable //! row that owns the request's whole outcome; the session channel //! closes the way it would when the request itself cannot exist. //! `session_seam` unset (feature on, seam absent) → the same //! shape, reason `seam-unconfigured` (the decline matrix's -//! config-driven note); `pty_request` checks the seam too — a pty -//! whose session can never serve is a doomed allocation. Field +//! config-driven note); `pty_request` checks the seam too, since a +//! pty whose session can never serve is a doomed allocation. Field //! checks precede the seam check (the row's own unset field is the //! first decline); the decline never takes the channel and never //! consumes stored pty state. @@ -63,10 +63,10 @@ //! - **SSH → chunks** (the `client_recv` side of alktty's session): //! a bounded [`tokio::sync::mpsc`] (the //! [`CONTROL_SURFACE_BOUND`] bound) feeds a framing task that -//! writes `alktty::wire::Chunk`s into the duplex — the same mpsc +//! writes `alktty::wire::Chunk`s into the duplex, the same mpsc //! the control rows ride ([`BridgeSurface`], §below). SSH `data` → //! `Chunk::stdin`; SSH channel EOF → **the zero-length -//! stdin-chunk sentinel** — decided (verified against alktty 0.8.1's +//! stdin-chunk sentinel**, decided (verified against alktty 0.8.1's //! adapter pump, `adapter.rs::pump_client_to_backend`): a //! zero-length stdin chunk shuts the backend's stdin, *identical //! in effect* to `ControlMessage::Eof` on `STREAM_CTRL_IN`; the @@ -80,9 +80,9 @@ //! *error frame* is length-prefixed JSON whose first length byte //! is `0x00`; a raw chunk's first byte is a `stream_type` ≤ 4). //! stdout chunks → SSH `data`; stderr chunks → SSH -//! `extended_data(1)` (PTY mode merges upstream — the backend's -//! stderr stream is `None` there, so the translation is universal: -//! no mode-switch exists); the exit chunk (`STREAM_CTRL_OUT`) → +//! `extended_data(1)` (PTY mode merges upstream; the backend's +//! stderr stream is `None` there, so the translation is universal +//! and no mode-switch exists); the exit chunk (`STREAM_CTRL_OUT`) → //! the derivation contract (§below). No unbounded buffering in //! either adapter (AGENTS.md convention 9). //! - **The negotiation-error frame is the bridge's serving-path @@ -91,23 +91,24 @@ //! ownership), and a failure answers a length-prefixed error //! frame instead of chunks. Decided + recorded: the bridge maps //! that frame to a serving-path decline event -//! (`negotiation-failed`) and an **`exit-status(255)` then close** -//! — the one place this door claims 255: the session **never +//! (`negotiation-failed`) and an **`exit-status(255)` then close**, +//! the one place this door claims 255: the session **never //! started** (no exit chunk exists, nothing ran, so 255 is the -//! honest could-not-start semantic — contrast the git row, whose +//! honest could-not-start semantic, contrasted with the git row, +//! whose //! service *runs* its substrate and honestly reports `1`). The //! error frame's JSON detail stays alktty-side; only the //! vocabulary value rides the event. //! - A bridge read that ends **without** an exit chunk reports //! nothing (the chunk is the sole fidelity input; its absence is -//! neither 0 nor 255 — no fabricated report): plain close, and +//! neither 0 nor 255, no fabricated report): plain close, and //! the lifecycle's ended event. //! - **Known limit (recorded disposition, wave-3 gate booked item 3): //! the stdout [`tokio::io::AsyncWriteExt::write_all`] carries no //! deadline.** Backpressure is bounded (the bounded bridging duplex, //! russh's per-channel window and the client's own flow control bound //! what can pile up) and liveness is covered by the inactivity -//! timeout ([`crate::Limits::inactivity_timeout`], always set) — a +//! timeout ([`crate::Limits::inactivity_timeout`], always set); a //! deadline here would be a behavior change (a slow client may stall //! its stream, vanilla sshd's posture included), not a coverage //! minor. So the limit is recorded, not "fixed". @@ -116,7 +117,7 @@ //! //! The requests arrive on the packet loop after the serving task //! owns the wire, and reach the spawned bridge through the -//! **per-channel control surface** ([`BridgeSurface`] — handler +//! **per-channel control surface** ([`BridgeSurface`], handler //! state while the row serves): a bounded mpsc whose send half //! forward_control `try_send`s the control chunk (never awaited on //! the packet loop). `window_change_request` → @@ -124,23 +125,23 @@ //! (alktty's uppercase-name vocabulary). Decisions, recorded: //! the SSH control rows are fire-and-forget (no reply exists on //! the wire), so **a full or closed surface drops the control -//! event** — the bound keeps a stalled bridge from stalling the +//! event**; the bound keeps a stalled bridge from stalling the //! packet loop (bounded resources, convention 9); **signal names -//! are accepted verbatim** — no alkssh-side name filter: the +//! are accepted verbatim**, no alkssh-side name filter: the //! backend owns the rejection semantics (alktty passes the name to //! the backend's control handle, whose semantics decide), and the //! pipe-mode pid-only vs PTY process-group *scope* is backend //! semantics (the mapping row note), so there is **no decline -//! shape** for a name — nothing on the wire can answer. A resize +//! shape** for a name; nothing on the wire can answer. A resize //! arriving for a channel whose pty is stored but not yet serving -//! updates the stored params instead (the final size wins — +//! updates the stored params instead (the final size wins, //! vanilla sshd's own ordering); a resize with neither a serving //! bridge nor a stored pty is dropped. //! //! ## The exit derivation contract (mapping.md §Exit chunk, rules 1–6) //! //! Normative text and the whole derivation machinery now live in -//! [`crate::exit_code`] — the shared exit-currency module consumed by +//! [`crate::exit_code`], the shared exit-currency module consumed by //! *both* directions (`w4-op-rows` extracted it out of this module: //! the client rows consume wire exit reports back into the family's //! `i32` exit-code convention, the exact inverse arm of the same @@ -156,11 +157,11 @@ //! //! The serving task watches two signals: the **per-channel cancel** //! (fired by `channel_close`, or surfaced by the surface's drop) and -//! the **connection teardown** ([`Teardown`] — fired by the +//! the **connection teardown** ([`Teardown`], fired by the //! handler's `Drop`; the russh session ended, however it ended). On -//! either, the task aborts the alktty session task — dropping its -//! not-yet-resolved `exit_code` future, which is alktty's -//! kill-on-drop contract firing (its ADR-056) — then closes the SSH +//! either, the task aborts the alktty session task, dropping its +//! not-yet-resolved `exit_code` future (alktty's +//! kill-on-drop contract firing, its ADR-056), then closes the SSH //! channel and ends. Nothing is fabricated on a cancel. The //! detached stdin/framing tasks are bounded by their duplex/mpsc/ //! russh-window bounds and end on the same signals' effects. @@ -182,7 +183,7 @@ use crate::config::SessionSeam; use crate::exit_code::{ExitReport, derive_exit, sig_from_name}; use crate::observe; -/// The negotiation frame the bridge speaks locally — every locally +/// The negotiation frame the bridge speaks locally; every locally /// constructed request reads `"raw"` (alktty's v1 carriage). pub(crate) const CARRIAGE: &str = "raw"; @@ -192,11 +193,11 @@ pub(crate) const CARRIAGE: &str = "raw"; /// (§the control rows). The shim's scripted rows exercise a handful. pub(crate) const CONTROL_SURFACE_BOUND: usize = 64; -/// The translation bridge duplex capacity — the wave-2 loopback +/// The translation bridge duplex capacity, the wave-2 loopback /// harness's per-direction convention, kept for the bridge pairs. const BRIDGE_DUPLEX_CAPACITY: usize = 65_536; -/// The stdin pump's read buffer — the SSH-side chunk granularity +/// The stdin pump's read buffer, the SSH-side chunk granularity /// (per-chunk payloads are bounded in practice by russh's /// `maximum_packet_size`, here by [`MAX_CHUNK_LEN`] on the frame). const STDIN_PUMP_BUF: usize = 16 * 1024; @@ -210,7 +211,7 @@ pub(crate) fn clamp_u16(value: u32) -> u16 { /// The `pty_request` args → `TerminalParamsWire` conversion (§the /// negotiation section): SSH ttymodes → the **reserved modes JSON -/// `{}`** (alktty OQ-44's reservation — the map is honest: nothing +/// `{}`** (alktty OQ-44's reservation; the map is honest: nothing /// is carried, exactly what the reservation asks). pub fn terminal_params( term: &str, @@ -251,15 +252,15 @@ pub(crate) fn negotiate_request( } } -/// One parsed bridge-side frame from alktty's `client_send` half — +/// One parsed bridge-side frame from alktty's `client_send` half: /// the 4-byte first-window disambiguation's outcome (§the /// translation bridge). pub(crate) enum BridgeFrame { /// A raw alktty chunk (data or server→client control). Chunk(Chunk), - /// The length-prefixed negotiation error frame — the session + /// The length-prefixed negotiation error frame: the session /// failed validation/allocation/ownership at the seam. The bytes - /// are alktty-side detail (never read here — only the + /// are alktty-side detail (never read here, only the /// vocabulary value rides the decline event). NegotiationError, /// The half ended (alktty's task completed or was cancelled) @@ -269,10 +270,10 @@ pub(crate) enum BridgeFrame { Break, } -/// Reads one bridge frame — the disambiguation invariant: the first +/// Reads one bridge frame (the disambiguation invariant: the first /// byte `0x00` is a negotiation error frame's length-prefix high -/// byte; anything ≤ 4 is a chunk `stream_type`. Bounds-checked -/// against [`MAX_CHUNK_LEN`] both directions — a rogue length never +/// byte; anything ≤ 4 is a chunk `stream_type`). Bounds-checked +/// against [`MAX_CHUNK_LEN`] both directions, so a rogue length never /// triggers an oversized read. pub(crate) async fn read_bridge_frame( reader: &mut (impl tokio::io::AsyncRead + Unpin), @@ -318,8 +319,8 @@ pub(crate) async fn read_bridge_frame( /// The exit chunk's JSON payload → the derived code /// (`{"type":"exit","code":N}`). Anything else on `STREAM_CTRL_OUT` -/// has no contract meaning — and an exit chunk that cannot parse has -/// no fidelity input — both map to `None` (no report; the plain +/// has no contract meaning, and an exit chunk that cannot parse has +/// no fidelity input; both map to `None` (no report; the plain /// close posture). fn exit_chunk_code(payload: &[u8]) -> Option { ControlMessage::from_slice(payload) @@ -330,7 +331,7 @@ fn exit_chunk_code(payload: &[u8]) -> Option { }) } -/// The per-channel bridge surface — handler state while a session row +/// The per-channel bridge surface: handler state while a session row /// serves (§the control rows). The handler's `window_change_request` /// / `signal` hooks reach the spawned bridge **through this struct** /// (the requests arrive on the packet loop after the serving task @@ -338,17 +339,17 @@ fn exit_chunk_code(payload: &[u8]) -> Option { /// per-channel cancel signal `channel_close` fires. Packet-loop only /// (single-writer; no lock). pub(crate) struct BridgeSurface { - /// The control-surface send half — the same bounded mpsc the + /// The control-surface send half, the same bounded mpsc the /// serving task's stdin pump feeds. pub(crate) sender: mpsc::Sender, - /// The per-channel cancel signal — `channel_close` fires it. The + /// The per-channel cancel signal (`channel_close` fires it). The /// serving task interprets the fire *or* the half's drop as the /// cancel. pub(crate) cancel: watch::Sender, } impl BridgeSurface { - /// Forwards one control row into the bridge — `try_send`, never + /// Forwards one control row into the bridge via `try_send`, never /// awaited on the packet loop (§the control rows); a full or /// closed surface drops the event. pub(crate) fn forward_control(&self, message: &ControlMessage) -> bool { @@ -404,12 +405,12 @@ impl Teardown { } } -/// Reads the SSH half of the channel and feeds stdin chunks — the +/// Reads the SSH half of the channel and feeds stdin chunks, the /// SSH `data` → `Chunk::stdin` adapter (§the translation bridge). /// On EOF or a read error it sends **the zero-length stdin-chunk /// sentinel** (the EOF translation decision: identical in effect to -/// alktty's `ControlMessage::Eof` — the backend's stdin shuts while -/// the session keeps pumping) and ends. +/// alktty's `ControlMessage::Eof`, with the backend's stdin shut +/// while the session keeps pumping) and ends. async fn stdin_pump( ssh_read: impl tokio::io::AsyncRead + Unpin + 'static, chunks: mpsc::Sender, @@ -450,9 +451,9 @@ async fn stdin_pump( } /// Consumes the framed-input mpsc and writes alktty chunks into the -/// session's `client_recv` duplex half — the framing task. Ends after +/// session's `client_recv` duplex half, the framing task. Ends after /// the EOF sentinel is written (nothing rides the data path past -/// SSH EOF), on a mpsc close (every sender gone — the cancelled or +/// SSH EOF), on a mpsc close (every sender gone, the cancelled or /// completed session), or on a framing failure. async fn framing_task(mut chunks: mpsc::Receiver, writer: tokio::io::DuplexStream) { let mut writer = ChunkWriter::new(writer); @@ -468,7 +469,7 @@ async fn framing_task(mut chunks: mpsc::Receiver, writer: tokio::io::Dupl /// The exit report + close + lifecycle event, in the ADR-006 /// decision-4 order: **status before close, from the spawned task**. -/// A failed send means the session is gone — the lifecycle's one +/// A failed send means the session is gone; the lifecycle's one /// `warn` records it (the report that could not land). async fn report_exit( handle: &Handle, @@ -501,7 +502,7 @@ async fn report_exit( } } -/// Fails the request and closes the channel from the serving path — +/// Fails the request and closes the channel from the serving path, /// the serving-path decline shape ([`crate::serve`]'s mechanics) with /// the lifecycle events and the given reason. Used for `no-identity`. async fn fail_and_close( @@ -528,7 +529,7 @@ async fn fail_and_close( /// [`alktty::drive_session_pre_negotiated`]; the alktty session task /// and the SSH→chunks pump are spawned here, and *this* future drives /// the chunks→SSH direction inline so the exit report is the path's -/// own final act (status before close — ADR-006 decision 4). The +/// own final act (status before close, per ADR-006 decision 4). The /// channel was taken by the dispatch; the spawned task owns the /// stream and its report surface. #[allow(clippy::too_many_arguments)] @@ -688,14 +689,14 @@ async fn drive_chunks_to_ssh( #[cfg(test)] mod tests { /// - *Contract stamp:* the no-exit-chunk close family's frame - /// classification (`w4-tty-coverage` — the wire row in + /// classification (`w4-tty-coverage`; the wire row in /// `tests/tty_mapping.rs` lands the family's serving outcome): a /// clean read-end classifies `Closed`, an oversized claimed - /// length classifies `Break` — bounds-checked both directions, - /// never an oversized read. `Break`'s serving arm is one body + /// length classifies `Break` (bounds-checked both directions, + /// never an oversized read). `Break`'s serving arm is one body /// with `Closed`'s; through alktty's own validated `ChunkWriter` /// a `Break` frame is unreachable on the duplex (the drainer - /// rejects the oversized chunk locally and the read sees EOF — + /// rejects the oversized chunk locally and the read sees EOF, /// the wire row's construction), so the classification rows pin /// the defensive arm at the frame layer. #[tokio::test] diff --git a/src/tunnel_map.rs b/src/tunnel_map.rs index a4b51bf..8181714 100644 --- a/src/tunnel_map.rs +++ b/src/tunnel_map.rs @@ -1,23 +1,23 @@ -//! The `direct-tcpip` / `direct-streamlocal` mapping — the tunnel +//! The `direct-tcpip` / `direct-streamlocal` mapping, the tunnel //! branch's route-1 bridge (`w3-tunnel-direct`, ADR-006 decision 1): //! the adapter-side bridge POC-3 stage C proved, re-landed as contract //! against published alktunnels 0.4.1, with the forwarded serving //! surface adopted to alktunnels 0.5.0's establisher shape (the -//! review-003 W2 adoption — the `ForwardedGate` correlation gate). +//! review-003 W2 adoption, the `ForwardedGate` correlation gate). //! //! ## The route-1 bridge (ADR-006 decision 1) //! //! alkssh holds the assembly-supplied `Arc` into the -//! family fabric (the serve-config's `channel_client` — the wave-1 +//! family fabric (the serve-config's `channel_client`, the wave-1 //! config field's consuming code). Per accepted `direct-tcpip` / //! `direct-streamlocal` open, the target/substrate are constructed //! from the SSH open arguments (`direct-tcpip`(host, port) → //! `SubstrateAddr::HostPort` + `Substrate::Tcp`; //! `direct-streamlocal`(socket path) → `SubstrateAddr::Path` + -//! `Substrate::Unix` — the mapping.md row's treatment) and the flow is +//! `Substrate::Unix`, the mapping.md row's treatment) and the flow is //! exactly the POC recipe: **`TunnelSession::open_direct(&client, //! target, substrate)` → accept only after the fabric open succeeds** -//! (`ChannelOpenHandle::accept` consumes the handle — the reject shape +//! (`ChannelOpenHandle::accept` consumes the handle; the reject shape //! is only possible pre-accept, which is what makes accept-after-open //! the only honest flow) → on success `take_halves()` pumped against //! the taken channel's stream ([`alkcall::channels::pump::pump_bidi`], @@ -25,20 +25,20 @@ //! the spawn-and-return constraint. The open hook returns fast with //! the fabric open in flight. //! -//! **Fabric failure → the explicit `ConnectFailed` reject** — the +//! **Fabric failure → the explicit `ConnectFailed` reject**; the //! wave-2 seam stub's reason surviving as the real decline //! ([`crate::dispatch::connect_failed_open_decline`]; the stub itself //! is retired). The channel is never established, so the SSH client //! observes a clean, channel-scoped open refusal (POC-1 §5 posture) -//! — vanilla clients retry-observe a down forward instead of a hang. +//! : vanilla clients retry-observe a down forward instead of a hang. //! -//! ## The `-R` listen flow (`w3-tunnel-listen` — the fabric listens, +//! ## The `-R` listen flow (`w3-tunnel-listen`: the fabric listens, //! the client dials) //! //! The server direction of the route-1 bridge (`mapping.md` //! §Channel-type rows, the `forwarded-tcpip` row + §Global-request -//! rows). Per the family door semantics: the door owns nothing local -//! — **the fabric listens**; per arrival the data flows back toward +//! rows). Per the family door semantics: the door owns nothing local, +//! **the fabric listens**; per arrival the data flows back toward //! the vanilla SSH client, which dials its own target. Three moving //! parts, all decided against alktunnels 0.4.1's actual surfaces with //! POC-3 §C.4 as the template (the gate adoption rides 0.5.0's @@ -47,36 +47,36 @@ //! 1. **The listen dial** (`tcpip_forward` / `streamlocal_forward`): //! the door maps the vanilla listen request family-ward as //! `TunnelParams { resource: , -//! substrate: Tcp/Unix }` — the **resource-naming convention +//! substrate: Tcp/Unix }`; the **resource-naming convention //! recorded** (the one open surface this flow's composition had): //! ADR-001 keeps the wire field a *resource identifier*, and a //! fabric serving vanilla `-R` opt into dynamic-address binding by //! its own establisher/bind-closure treating the mapped string as //! its bind endpoint (`bindfirst_establisher` + //! `register_openable_with_establisher`, the alkcall ADR-049 -//! establisher shape — who may bind what is the fabric's ACL + +//! establisher shape: who may bind what is the fabric's ACL + //! its bind closure, assembly policy at the family's provider, -//! never the door's). The dial is the published consumer surface — +//! never the door's). The dial is the published consumer surface, //! `TunnelListener::open(client, params)` on the held -//! `ChannelClient` — bounded by [`LISTEN_DIAL_TIMEOUT`]; the +//! `ChannelClient`, bounded by [`LISTEN_DIAL_TIMEOUT`]; the //! reply's `bound` + minted `listen` token (the alkcall ADR-049 //! amendment-3 establisher fields) are read through //! `parse-listen-reply`-class accessors; **a reply without both is //! a declined listen with the fabric listener torn down -//! immediately** (never a minted-but-uncorrelatable listen — a +//! immediately** (never a minted-but-uncorrelatable listen; a //! declined listen never left a half state). -//! 2. **The door-side arrival surface** — the composition decision +//! 2. **The door-side arrival surface**, the composition decision //! (the task's second `w3-seam-config` course correction): the //! fabric dials `tunnel/forwarded` *toward the door* per alktunnels' //! bind-first dispatch (`make_bindfirst_accept_handler` + -//! `ForwardedOpener` — the producer calls the op on the channel-0 +//! `ForwardedOpener`): the producer calls the op on the channel-0 //! call plane toward the listen opener, and the door reply carries //! the door-allocated channel id the producer adopts; alkcall's //! odd/even split keeps the two open directions collision-free). -//! Serving that op needs the door's channel-0 serving loop — an +//! Serving that op needs the door's channel-0 serving loop, an //! alkcall `ChannelClient` built with -//! `from_connection_with_serving`, whose registry the assembly owns -//! — so the serve-config carries [`crate::config::TunnelListenSeam`] +//! `from_connection_with_serving`, whose registry the assembly owns, +//! so the serve-config carries [`crate::config::TunnelListenSeam`] //! (the same `Arc` the assembly wired); alkssh //! registers the forwarded openable itself in //! [`install_forwarded_surface`] (called from @@ -85,7 +85,7 @@ //! client's manager + alktunnels' `tunnel_forwarded_spec()` + //! `make_forwarded_op_handler` over the crate's arrival pump, the //! wire-level ACL (`tunnel:forwarded` scope) and the per-connection -//! channel budget enforced inside alkcall's dispatch — registered +//! channel budget enforced inside alkcall's dispatch, registered //! in the **establisher variant** (alktunnels 0.5.0's //! `register_tunnel_forwarded_openable_with_establisher`, the //! review-003 W2 adoption): the router's correlation lookup rides @@ -94,25 +94,25 @@ //! `unknown_resource`) before any channel is born; the handler's //! re-lookup keeps the residual-race + //! cap-admission teardown-at-birth fallback. -//! 3. **The arrival pump** — the `forwarded-tcpip` data leg: the +//! 3. **The arrival pump**, the `forwarded-tcpip` data leg: the //! registered [`ForwardedHandler`]-closure correlates the //! arrival's `listen` token through [`ListenRouter`] (the route was //! registered at listen acceptance with the owning session's -//! handle + cap); a miss here is the gate-pass residual race — +//! handle + cap); a miss here is the gate-pass residual race, //! still **teardown-at-birth** (drop the fabric //! half, never a half-open SSH channel). On a hit, per vanilla `-R` //! convention: the door opens a `forwarded-tcpip` channel *toward -//! the client* echoing **the listen request's own args** — the +//! the client* echoing **the listen request's own args**, the //! connected address as the wire `tcpip_forward` request carried it //! verbatim (the OpenSSH client matches that exact string; for //! `port = 0` mints the *actually bound* port from the fabric's -//! `bound` reply — the sshd parity recorded in -//! [`ListenRoute`]) — with the `TunnelForwardedParams.peer` arrival +//! `bound` reply, the sshd parity recorded in +//! [`ListenRoute`]), with the `TunnelForwardedParams.peer` arrival //! mapped to the originator fields (`HostPort` → address/port; -//! `Path` → path + port 0 — the degenerate but typed mapping, +//! `Path` → path + port 0, the degenerate but typed mapping, //! unreachable for a TCP-minted listen). The accepted-or-rejected //! decision is the in-crate cap (the wave-2 gate's booked acceptor -//! vocabulary — the per-arrival admission; a client-side rejection +//! vocabulary, the per-arrival admission; a client-side rejection //! or a dead session releases the count, the established channel's //! release rides [`crate::handler`]'s `channel_close` like every //! established channel). Accept → the fabric `BiStream` pumped @@ -125,7 +125,7 @@ //! //! **The inline listen dial (recorded decision):** the //! spawn-and-return rule keeps *serving paths* out of the packet -//! loop — but the `tcpip_forward` global request's reply is bound to +//! loop, but the `tcpip_forward` global request's reply is bound to //! the hook itself (russh answers the want-reply from the hook's //! return + the `&mut u32` out-param; no handle surface responds to a //! global request from a spawned task at this pin), so the listen @@ -136,18 +136,18 @@ //! packet loop), and its stall is bounded: other channels of the //! connection pause only for [`LISTEN_DIAL_TIMEOUT`], and the //! fabric-dial failure answers a denied listen. All serving below the -//! reply (none — the listen returns) and all arrival paths stay +//! reply (none, since the listen returns) and all arrival paths stay //! spawned. //! //! ## Bounded bookkeeping (AGENTS.md convention 9) //! //! - **The per-session listener map** (the session-handler's -//! `listeners` — packet-loop-only writer, like the `channels`/ +//! `listeners`, packet-loop-only writer, like the `channels`/ //! `ptys` stores) maps the minted token → the pending listen (wire //! args, bound port, the [`alktunnels::consumer::TunnelListener`] //! whose `close`/`Drop` perform the fabric teardown). Its bound: //! the listen count shares the `Limits::max_concurrent_channels` -//! *ceiling* in a dedicated counter — a listen is at least one +//! *ceiling* in a dedicated counter; a listen is at least one //! future channel's potential, sessions minting unbounded listeners //! would mint an unbounded fabric-channel map on the shared leg. //! - **The route map** ([`ListenRouter`], shared with the registered @@ -155,29 +155,29 @@ //! bounded by construction: entries are minted exactly at accepted //! listens (listener-cap gated), removed 1:1 at the cancel forms //! and at the owning session's teardown (the handler's `Drop` -//! removes its tokens — a stale route to a dead handle only ever +//! removes its tokens; a stale route to a dead handle only ever //! costs one failed open that returns teardown-at-birth, never a //! half-open SSH channel). //! - **A cancelled / torn-down listen never half-serves**: the cancel //! path removes the route before any teardown (a racing arrival //! misses → teardown-at-birth), and `cancel_*` of an unknown -//! (address, bound-port) pair answers `false` — the vanilla +//! (address, bound-port) pair answers `false`, the vanilla //! cancel contract (sshd parity: match by the raw wire string + //! the bound port). One recorded caveat: an arrival that *cloned* //! its route just before the cancel removes it still completes its //! open + pump (the forwarded channel is independent of the -//! listener's teardown — the arrival is never half-open, but a +//! listener's teardown; the arrival is never half-open, but a //! cancelled listen can deliver one already-accepted connection; //! sshd parity). //! //! ## The runtime-Unix gate (OQ-11) //! //! `direct-streamlocal` compiles wherever `tunnel` compiles (universal -//! compile — no per-platform feature fork); **serving is runtime-Unix- +//! compile, no per-platform feature fork); **serving is runtime-Unix- //! gated**: off-Unix a clean open-decline **before any fabric call** //! (never a partial bridge), on-Unix the real bridge. The gate lives //! in the dispatch hook ([`crate::handler`]'s `direct-streamlocal` -//! row), before the cap admission — a platform-refused open consumes +//! row), before the cap admission; a platform-refused open consumes //! nothing. The gate rides the `streamlocal_forward` listen row the //! same way (`w3-tunnel-listen`). //! @@ -185,25 +185,25 @@ //! //! The resolved SSH identity is the auth bridge's ride-along in //! handler state (`auth_publickey` stores; the row dispatches never -//! serve anonymously — the `no-identity` guard, unreachable on the +//! serve anonymously, the `no-identity` guard, unreachable on the //! wire because russh authorizes before channels exist, fail-closed //! like the git/tty rows' `w2-auth-bridge` parked item discharged //! there). The guard gates every tunnel open **at the door**; the //! open that proceeds then rides the channels connection into the //! fabric, whose own `AccessControl::check(peer_identity)` gates the -//! mapped `channels/tunnel/direct` open (alkcall CF-005/CF-006) — +//! mapped `channels/tunnel/direct` open (alkcall CF-005/CF-006); //! the composed-gate witness is the harness's identity rows. The //! `-R` leg composes the same gates on both of its directions: the -//! listen dial rides the fabric leg's identity (`tunnel:open` scope — +//! listen dial rides the fabric leg's identity (`tunnel:open` scope, //! the assembly's dial-identity composition, unchanged), and the //! arrivals are gated by the door-side registry's ACL //! (`tunnel:forwarded` scope, per arrival) exactly when the assembly's //! fabric leg carries it. //! -//! **`set_identity` mechanics (recorded — `w3-tunnel-direct`'s decided +//! **`set_identity` mechanics (recorded: `w3-tunnel-direct`'s decided //! point, carried unchanged):** the alkhub `hub_leg.rs` one-time-set //! precedent (`channel0_conn.set_identity(identity)`) is a -//! **serving-side** set — the identity the fabric leg dials with, and +//! **serving-side** set: the identity the fabric leg dials with, and //! against which the fabric's ACL gates alkssh's mapped opens, is the //! assembly-supplied `ChannelClient`'s own dial identity (CF-005: set //! once at dial, propagated to channel 0 at `from_connection`); the @@ -246,10 +246,10 @@ use crate::{config, dispatch, observe}; pub(crate) type WireChannel = Channel; /// The spawned route-1 bridge (`w3-tunnel-direct`, the POC-3 §C -/// recipe): the fabric open runs here — accept only after it succeeds, +/// recipe): the fabric open runs here; accept only after it succeeds, /// `take_halves()` pumped against the taken channel on completion, and /// on failure the explicit `ConnectFailed` reject **with the cap count -/// released** (the recorded release mechanism — the admitted open this +/// released** (the recorded release mechanism: the admitted open this /// task holds was never established, so no `channel_close` can ever /// fire; the count recovers here, in the task that knows the failure, /// exactly once: a success never releases). The channel closes on @@ -283,7 +283,7 @@ pub(crate) async fn serve_direct_row( } /// The open hook's spawn step (ADR-006 decision 4): the handler clones -/// the cap `Arc` (the failure-path release's handle — the count was +/// the cap `Arc` (the failure-path release's handle; the count was /// admitted at the hook and is held across the fabric open) and hands /// the rest over; the hook returns fast with the fabric open in /// flight. @@ -307,29 +307,29 @@ pub(crate) fn spawn_direct_row( /// The wall-clock bound on the family-ward listen dial (`TunnelListener:: /// open`): the fabric's establisher is already bound by alkcall's own -/// establisher deadline (10 s, alkcall ADR-049 §2), so this matches it — +/// establisher deadline (10 s, alkcall ADR-049 §2), so this matches it, /// a fabric that never answers a listen dial cannot hold the packet /// loop longer than a bounded dial. pub(crate) const LISTEN_DIAL_TIMEOUT: Duration = Duration::from_secs(10); -/// One route in the listen-arrival bookkeeping — registered at listen +/// One route in the listen-arrival bookkeeping, registered at listen /// acceptance, consulted per arrival. The echo fields are the vanilla /// `-R` convention decoded (sshd parity, recorded on [`ListenRouter`]): /// the connected address rides the wire `tcpip_forward` string /// **verbatim** (the OpenSSH client sent that exact string and matches /// the open's address field against it exactly), the port is the -/// **actually bound** one (the fabric's `bound` reply — the sshd +/// **actually bound** one (the fabric's `bound` reply, the sshd /// `get_local_port`-of-accepted-socket parity, which is what makes /// `port = 0` mints round-trip), and the unix path rides the /// `streamlocal_forward` request verbatim. #[derive(Clone, Debug)] pub(crate) struct ListenRoute { - /// The SSH args the arrivals' opens echo — keyed by the route's + /// The SSH args the arrivals' opens echo, keyed by the route's /// substrate (`Tcp`/`Udp` → the vanilla `-R` trio's first two /// fields; `Unix` → the `forwarded-streamlocal` path). pub(crate) echo: RouteEcho, pub(crate) substrate: Substrate, - /// The owning session's packet-loop handle — the arrival's SSH + /// The owning session's packet-loop handle: the arrival's SSH /// channel opens through it; a session that died fails the open /// (the arrival's teardown-at-birth path). pub(crate) handle: Arc, @@ -355,10 +355,10 @@ pub(crate) enum RouteEcho { /// `Drop`). A mint on an already-held token is refused fail-closed /// ([`ListenRouter::register`], `w4-router-collision`). Arrivals /// that find no route are the correlation-miss -/// class — teardown-at-birth, never a half-open SSH channel. +/// class (teardown-at-birth, never a half-open SSH channel). /// /// The map is behind a `parking_lot::Mutex` because arrivals arrive on -/// alkcall serving tasks while the packet loop mints/removes — the +/// alkcall serving tasks while the packet loop mints/removes; the /// held region is a HashMap op, never an await. pub(crate) struct ListenRouter { routes: Mutex>, @@ -367,21 +367,21 @@ pub(crate) struct ListenRouter { impl ListenRouter { /// Minted-entry registration (the listen-acceptance step), /// fail-closed on token collision (the wave-3 gate's booked item - /// 4, `w4-router-collision` — the same posture the same gate + /// 4, `w4-router-collision`, the same posture the same gate /// landed inline for a duplicate `tunnel/forwarded` /// registration): safety rests on the fabric's ADR-008 mint /// discipline upstream, and this defends in depth against a - /// collided mint — a `register` on an already-held token returns + /// collided mint, a `register` on an already-held token returns /// `Err` and **never replaces** the held route, so a colliding /// mint can never steal a live adapter's arrival routes. The /// caller declines the listen (the fabric listener is then torn - /// down — a refused registration never left a half state). + /// down; a refused registration never left a half state). /// /// Error surface (decided, `w4-router-collision`): the refusal /// rides [`String`]-carried detail surfaced as the request-time /// **decline disposition** (`RequestDenied`, reason /// `token-collision`), not a distinct [`AdapterError`](crate::AdapterError) - /// variant — a global-request hook's `Err` would kill the whole + /// variant, since a global-request hook's `Err` would kill the whole /// russh session (russh 0.65 answers the decline from the hook's /// `Ok(false)`, and `Err` propagates out of the packet loop), and /// the taxonomy's rule holds that wire decline reasons are never @@ -393,7 +393,7 @@ impl ListenRouter { let mut routes = self.routes.lock(); if routes.contains_key(&token) { return Err(format!( - "listen token {token} is already routed — a collided \ + "listen token {token} is already routed; a collided \ mint may not replace a live adapter's route" )); } @@ -401,7 +401,7 @@ impl ListenRouter { Ok(()) } - /// The per-arrival lookup — cloned out, never taken: one route + /// The per-arrival lookup, cloned out, never taken: one route /// serves unboundedly many arrivals; only the cancel forms and /// session teardown remove. pub(crate) fn route_for(&self, token: u32) -> Option { @@ -409,7 +409,7 @@ impl ListenRouter { } /// The cancel-form removal (1:1 into the family listener's - /// teardown): removes first, so a racing arrival already misses — + /// teardown): removes first, so a racing arrival already misses, /// teardown-at-birth, never a post-cancel half-serve. pub(crate) fn cancel(&self, token: &u32) -> bool { self.routes.lock().remove(token).is_some() @@ -417,7 +417,7 @@ impl ListenRouter { /// The owning session's teardown (the handler's `Drop`): remove /// the session's tokens; any listener objects left drop with the - /// handler (the fabric-side reap — see `PendingListen`). + /// handler (the fabric-side reap, see `PendingListen`). pub(crate) fn remove_tokens(&self, tokens: &[u32]) { let mut routes = self.routes.lock(); for token in tokens { @@ -438,24 +438,24 @@ impl Default for ListenRouter { /// [`crate::SshAdapter::new`] when the fabric leg + seam are both /// present): builds the router, registers alktunnels' forwarded /// openable into the seam's shared registry over a `ChannelCore` -/// wrapping a clone of the held `ChannelClient`'s manager — the +/// wrapping a clone of the held `ChannelClient`'s manager, the /// alkcall shape whose wrapper performs the door-side arrival's /// channel allocation, ACL (`tunnel:forwarded`, per call) and budget /// (alkcall's secure default per-identity policy, `256`, plus the -/// `DEFAULT_MAX_CHANNELS` per-connection bound — alkssh composes no +/// `DEFAULT_MAX_CHANNELS` per-connection bound; alkssh composes no /// deployment policy; an assembly wanting a different per-identity /// cap shapes it through its own `ServingConfig`/`registry` -/// composition upstream) — and spawns alktunnels' forward-op handler +/// composition upstream), and spawns alktunnels' forward-op handler /// over the crate's arrival pump. /// /// The registration shape is the **establisher variant** -/// (`register_tunnel_forwarded_openable_with_establisher` — alktunnels +/// (`register_tunnel_forwarded_openable_with_establisher`, alktunnels /// 0.5.0, review 003 W2's adoption, ADR-008 Amendment 2's recommended /// form): the router's correlation lookup rides a [`ForwardedGate`] /// capturing the router, so a stale/missing `listen` token fails the /// open at alkcall's call plane as a typed `channel:open_failed` /// (`details.reason == "unknown_resource"`) **before any channel is -/// born** — the phantom-channel class (call-plane success, then +/// born**; the phantom-channel class (call-plane success, then /// handler-side decline) is closed at the open; door-side arrival /// correlations that pass the gate but lose the narrow gate-pass→ /// handler-run race, plus every cap-admission decline, still take the @@ -466,14 +466,14 @@ impl Default for ListenRouter { /// /// The registration is /// one-per-op-id-per-registry: alkcall's `register` silently -/// replaces an existing entry, so the door **pre-checks the op** — +/// replaces an existing entry, so the door **pre-checks the op**: /// a `tunnel/forwarded` registration that already exists (e.g. a /// second adapter over the same shared registry) is a failed -/// construction (fail-closed — never a route to a handler the door +/// construction (fail-closed; never a route to a handler the door /// does not own). /// /// On success the router rides back into the serve-config (the -/// session handlers read it) — `Ok` with the router installed, `Err` +/// session handlers read it): `Ok` with the router installed, `Err` /// is the caller's constructor failure. pub(crate) fn install_forwarded_surface(serve: &mut config::ServeConfig) -> Result<(), String> { let Some(seam) = serve.tunnel_listen_seam.as_mut() else { @@ -490,8 +490,8 @@ pub(crate) fn install_forwarded_surface(serve: &mut config::ServeConfig) -> Resu Ok(()) } else { Err(TunnelEstablishError::UnknownResource(format!( - "no accepted listen routes the arrival's token {} \ - — the forwarding session is gone or was never minted \ + "no accepted listen routes the arrival's token {}, \ + the forwarding session is gone or was never minted \ (alkssh: stale/missing `-R` token)", params.listen ))) @@ -515,7 +515,7 @@ pub(crate) fn install_forwarded_surface(serve: &mut config::ServeConfig) -> Resu { return Err(format!( "the tunnel/forwarded op ({}) is already registered in the \ - seam's registry — a conflicting registration would silently \ + seam's registry; a conflicting registration would silently \ replace the door's arrival route", alktunnels::params::OP_TUNNEL_FORWARDED )); @@ -532,34 +532,34 @@ pub(crate) fn install_forwarded_surface(serve: &mut config::ServeConfig) -> Resu Ok(()) } -/// The registered arrival pump — the `forwarded-tcpip` data leg +/// The registered arrival pump, the `forwarded-tcpip` data leg /// (mapping.md's row, "hand the channel duplex to the handler"): the /// alkcall openable registration hands every fabric arrival here with /// the parsed [`TunnelForwardedParams`] and the arrival's `BiStream`; /// the flow is the recorded shape: /// -/// 1. **Correlation** — the route for the arrival's minted token; +/// 1. **Correlation**: the route for the arrival's minted token; /// a miss is teardown-at-birth (drop the fabric half; the alkcall /// wrapper's awaited join ends, the channel reaps). The gate /// (the establisher's call-plane correlation) misses a stale /// token before any channel is born; this handler-side re-lookup -/// is the narrow gate-pass→handler-run **residual race** — the -/// same miss class, past the open — and the never-established cap +/// is the narrow gate-pass→handler-run **residual race**, the +/// same miss class, past the open, and the never-established cap /// declines below take the same path. /// 2. **The in-crate cap admission** (bounded resources at the accept -/// surface — the wave-2 gate's booked acceptor vocabulary): no +/// surface, the wave-2 gate's booked acceptor vocabulary): no /// room → the fabric half drops, the arrival never opens an SSH /// channel. The count releases here on every never-established /// path; an established one releases at its close (the packet /// loop's release site), the direct rows' disjoint-release shape. -/// 3. **The SSH open toward the client** — the echoed listen args +/// 3. **The SSH open toward the client**, the echoed listen args /// (`forwarded-tcpip` for the tcp/udp substrates with the originator /// fields mapped from `TunnelForwardedParams.peer`; `forwarded- -/// streamlocal@openssh.com` with the echoed path for `Unix`) — per +/// streamlocal@openssh.com` with the echoed path for `Unix`); per /// the spawn-and-return constraint this runs on this spawned task; /// a rejected/dead-open releases the count and drops the fabric /// half (never a half-open SSH channel). -/// 4. **The pump** — the fabric `BiStream` ↔ the SSH channel duplex +/// 4. **The pump**: the fabric `BiStream` ↔ the SSH channel duplex /// (the route-1 bridge's primitive, reversed). async fn pump_forwarded_arrival( router: Arc, @@ -609,7 +609,7 @@ async fn pump_forwarded_arrival( } (RouteEcho::Tcp { address, port }, SubstrateAddr::Path { path }) => { // The degenerate-but-typed mapping (a path-shaped peer on - // a tcp listen — unreachable from a well-behaved producer): + // a tcp listen, unreachable from a well-behaved producer): // the path rides the originator string, port 0. route .handle @@ -638,12 +638,12 @@ async fn pump_forwarded_arrival( } } -/// A minted listen — the door-side outcome of a `tcpip_forward` / +/// A minted listen, the door-side outcome of a `tcpip_forward` / /// `streamlocal_forward` request's family-ward dial (the published /// `TunnelListener::open`, bounded by [`LISTEN_DIAL_TIMEOUT`], with /// the reply's `bound` + `listen` establisher fields required: a /// producer that minted no correlation token or no bound report -/// cannot serve — [`Result`]'s `Err` declines the SSH request before +/// cannot serve; [`Result`]'s `Err` declines the SSH request before /// anything registers). pub(crate) struct MintedListen { pub(crate) listener: TunnelListener, @@ -653,9 +653,9 @@ pub(crate) struct MintedListen { /// The listen dial (the mapping.md §Global-request rows' family-ward /// step): `TunnelParams { resource: , substrate }` -/// — the wire-named bind endpoint as the resource, the recorded +/// : the wire-named bind endpoint as the resource, the recorded /// door-side naming convention whose fabric-side interpretation is -/// the assembly's establisher — then the reply projection. Called +/// the assembly's establisher; then the reply projection. Called /// inline from the handler hook (see the recorded inline-decision in /// the module doc). pub(crate) async fn open_listen( @@ -690,7 +690,7 @@ pub(crate) async fn open_listen( /// The bound port the listen request's out-param carries /// (the `&mut u32` sshd parity): the fabric's bound report's port. -/// Unix listens have no port semantics — the tcp variants only. +/// Unix listens have no port semantics; the tcp variants only. pub(crate) fn bound_port(bound: &SubstrateAddr) -> Option { match bound { SubstrateAddr::HostPort { port, .. } => Some(u32::from(*port)), @@ -698,12 +698,12 @@ pub(crate) fn bound_port(bound: &SubstrateAddr) -> Option { } } -/// The family-ward resource string for a listen request — the wire +/// The family-ward resource string for a listen request: the wire /// bind endpoint verbatim (`"localhost"` / `"0.0.0.0"` / explicit /// host: the OpenSSH client has already normalized the no-address case -/// to `"localhost"` and `""` before this surface exists — sshd +/// to `"localhost"` and `""` before this surface exists; sshd /// `channel_rfwd_bind_host` parity), with the requested port for the -/// tcp substrates (`host:port`; port `0` stays `0` — the OS-picking is +/// tcp substrates (`host:port`; port `0` stays `0`, since the OS-picking is /// the fabric's bind step, whose bound report feeds the out-param). pub(crate) fn listen_resource(endpoint: &str, substrate: Substrate, port: Option) -> String { match substrate { @@ -715,9 +715,9 @@ pub(crate) fn listen_resource(endpoint: &str, substrate: Substrate, port: Option /// The per-session pending listen (the packet-loop-only store, like /// the `channels`/`ptys` stores): the minted token is the map's key; /// the entry carries what the cancel forms match on (the wire endpoint -/// verbatim + the bound port — the sshd `c->path == host && +/// verbatim + the bound port, the sshd `c->path == host && /// c->listening_port == port` parity) over the substrate (a unix -/// entry's port is 0-carrying and never matched — the unix cancel +/// entry's port is 0-carrying and never matched; the unix cancel /// forms match on the path alone) and the session-owned /// [`TunnelListener`] whose close/Drop performs the family teardown. pub(crate) struct PendingListen { @@ -727,16 +727,16 @@ pub(crate) struct PendingListen { pub(crate) listener: TunnelListener, } -/// The listen count's dedicated bound — the same mechanism as +/// The listen count's dedicated bound, the same mechanism as /// [`ChannelCap`], instantiated per session next to it, against the /// same `Limits::max_concurrent_channels` ceiling: listeners and /// channels stay independently bounded while their mix stays -/// unconstrained (AGENTS.md convention 9 — no unbounded listener +/// unconstrained (AGENTS.md convention 9: no unbounded listener /// map). Admits are packet-loop-only (the listen hooks are the only /// mint site); releases fire at the cancel forms, the listen-dial -/// failures (admitted-but-never-minted — the route 1 bridge's +/// failures (admitted-but-never-minted, the route 1 bridge's /// release-site shape), and nowhere else (a minted listener's release -/// is... never — listeners hold until cancel or session teardown, so +/// is... never: listeners hold until cancel or session teardown, so /// the session's count dies with the handler, per the channels /// cap's same posture). pub(crate) type ListenerCap = ChannelCap; @@ -750,7 +750,7 @@ mod tests { /// The arrival pump's handler-side miss (the narrow gate-pass→ /// handler-run residual race the establisher shape retains) still /// teardown-at-births: a token with no route at handler time drops - /// the fabric half — the adoptee reads EOF, never a half-served + /// the fabric half; the adoptee reads EOF, never a half-served /// arrival. #[tokio::test] async fn the_pump_residual_miss_teardown_at_births_the_fabric_half() { diff --git a/tests/auth_bridge.rs b/tests/auth_bridge.rs index 1ecaad4..ec8b860 100644 --- a/tests/auth_bridge.rs +++ b/tests/auth_bridge.rs @@ -1,20 +1,20 @@ -//! The wave-2 auth-bridge contract tests (`w2-auth-bridge`) — the +//! The wave-2 auth-bridge contract tests (`w2-auth-bridge`): the //! ADR-004 dispositions at the handler level and over the wire. //! //! Two vehicles, each for a structural reason: //! //! - **Wire rows** (the adapter's tokio-duplex mount + russh's own //! client, the `w2-server-mount` wire-smoke precedent) drive the full -//! `auth_publickey` hook end to end — the hook's +//! `auth_publickey` hook end to end (the hook's //! `VerifiedPublicKey`/`PublicKeyOffer` argument shapes are //! `#[non_exhaustive]` (only russh constructs them, post-verification), -//! so wire traffic is the only way to observe the full hook — exactly +//! so wire traffic is the only way to observe the full hook, exactly //! where POC-1 observed it. These rows are the thin in-process //! precursor of the dedicated `w2-loopback-harness` vehicle (which //! records the transport choice and the helpers' vocabulary). //! - **Direct-hook rows** (the wave-1 doubles against //! [`alkssh::SessionHandler`] constructed directly) drive every hook -//! whose arguments are constructible outside russh — the four +//! whose arguments are constructible outside russh: the four //! non-publickey declines, and the bridge core //! ([`alkssh::SessionHandler::resolve_bridge`], structured out of the //! `#[non_exhaustive]`-arg hook on purpose) with fixture keys + @@ -39,7 +39,7 @@ use russh::server::{Auth, Handler}; use alkssh::{AdapterError, Limits, ServeConfig, SessionHandler, SshAdapter, fingerprint}; use alkssh::{HostKeySource, KeySourceError}; -/// The client-side handler double for the wire rows — accept every +/// The client-side handler double for the wire rows; it accepts every /// host key (the test choice; the crate never embeds this posture). struct AcceptAllHostKeys; @@ -55,7 +55,7 @@ impl russh::client::Handler for AcceptAllHostKeys { } /// Mounts the real adapter stack over an in-process duplex pair and -/// connects a russh client to it — the wire rows' vehicle. +/// connects a russh client to it, the wire rows' vehicle. async fn mount( provider: Arc, limits: Limits, @@ -109,7 +109,7 @@ fn registered_provider(fingerprints: &[&str]) -> Arc { } /// - *Contract stamp:* ADR-004 decision 1 (fingerprint → -/// `resolve_from_fingerprint` → `Some` → `Auth::Accept` — the bridge +/// `resolve_from_fingerprint` → `Some` → `Auth::Accept` (the bridge /// accepts the identity's key with the arbitrary username attached). #[tokio::test] async fn known_fingerprint_accepts_over_the_wire() { @@ -132,7 +132,7 @@ async fn known_fingerprint_accepts_over_the_wire() { } /// - *Contract stamp:* ADR-004 decision 5 + OQ-03 (the username is not -/// identity and carries no semantics — keys resolve independently of +/// identity and carries no semantics; keys resolve independently of /// the username string, POC-1's `ssh anything@host` observation). #[tokio::test] async fn username_is_never_an_identity_input() { @@ -149,15 +149,15 @@ async fn username_is_never_an_identity_input() { .expect("auth exchange completes over the wire"); assert!( result.success(), - "every username authenticates identically — {username}: {result:?}" + "every username authenticates identically: {username}: {result:?}" ); unmount(client, server_task).await; } } -/// - *Contract stamp:* ADR-004 decision 1 (`None` → reject — the +/// - *Contract stamp:* ADR-004 decision 1 (`None` → reject; the /// fail-closed path never creates a weakly authorized session) and -/// the advertisement honesty (ADR-004 decision 4 — exactly +/// the advertisement honesty (ADR-004 decision 4, exactly /// `{publickey}` remains advertised on the decline). #[tokio::test] async fn unknown_fingerprint_rejects_fail_closed() { @@ -188,7 +188,7 @@ async fn unknown_fingerprint_rejects_fail_closed() { } /// - *Contract stamp:* ADR-004 decision 1 (resolution happens at auth -/// time — a post-resolution revocation rejects the *next* attempt; +/// time (a post-resolution revocation rejects the *next* attempt); /// nothing is cached into a session credential). #[tokio::test] async fn resolved_fingerprint_can_be_revoked_between_attempts() { @@ -220,7 +220,7 @@ async fn resolved_fingerprint_can_be_revoked_between_attempts() { } /// - *Contract stamp:* ADR-004 decision 3 (`auth_none` is an explicit -/// family-contract decline — non-advertised methods are never +/// family-contract decline; non-advertised methods are never /// *advertised*, but the disposition is every attempted method's own /// hook, not the advertisement's). #[tokio::test] @@ -258,7 +258,7 @@ async fn auth_password_rejects_over_the_wire() { } /// - *Contract stamp:* ADR-004 decision 3 + OQ-04 (the OpenSSH -/// certificate decline is the standing disposition — no CA-trust +/// certificate decline is the standing disposition; no CA-trust /// story exists in the family identity model). #[tokio::test] async fn auth_openssh_certificate_rejects_over_the_wire() { @@ -286,7 +286,7 @@ fn handler_with(provider: Arc) -> SessionHandler { } /// - *Contract stamp:* ADR-004 decision 3 (each non-publickey method is -/// an *implemented* decline, never the inherited default — the +/// an *implemented* decline, never the inherited default; the /// dispositions are family contract, and each one is its own hook). #[tokio::test] async fn every_non_publickey_hook_rejects_explicitly() { @@ -345,11 +345,11 @@ async fn bridge_core_resolves_registered_fingerprints() { assert_eq!(resolved.id, "user-0", "the identity rides to the handler"); assert!( handler.resolved_identity().is_none(), - "resolve_bridge only resolves — the hook stores; an unwired bridge leaves no state" + "resolve_bridge only resolves (the hook stores; an unwired bridge leaves no state)" ); } -/// - *Contract stamp:* ADR-004 decision 1 (`None` → reject — the +/// - *Contract stamp:* ADR-004 decision 1 (`None` → reject; the /// unknown / revoked fingerprint never resolves; fail-closed, no /// weakly-authorized session, no cached resolution). #[tokio::test] @@ -375,18 +375,18 @@ async fn bridge_core_rejects_unknown_and_revoked_fingerprints() { provider.revoke(fixture("delta").fingerprint); assert!( handler.resolve_bridge(&key, &Algorithm::Ed25519).is_none(), - "the revocation takes — no cached resolution survives" + "the revocation takes; no cached resolution survives" ); } /// - *Contract stamp:* ADR-002 decision 4 (ed25519-only: the /// non-ed25519 decline is explicit-over-inherited and precedes any -/// resolution — a registered fingerprint under a non-ed25519 +/// resolution: a registered fingerprint under a non-ed25519 /// algorithm still declines). The sk-variant and `Other` stand-ins /// cover the scheme classes the in-tree build cannot even parse /// (rsa/dsa are dropped from the dependency tree and ssh-key ships /// without ecdsa/dsa/rsa features here, so no wire row can drive a -/// non-ed25519 key at this pin — recorded in the task notes; the +/// non-ed25519 key at this pin (recorded in the task notes); the /// gate is the explicit-over-inherited posture for the bump). #[tokio::test] async fn bridge_core_gates_non_ed25519_algorithms_before_resolution() { @@ -419,7 +419,7 @@ async fn bridge_core_gates_non_ed25519_algorithms_before_resolution() { /// - *Contract stamp:* ADR-004 decision 1 (the fingerprint the bridge /// computes is byte-format identical to the independent-issuer -/// registrations — the wave-1 parity vectors pin the string; this row +/// registrations; the wave-1 parity vectors pin the string, and this row /// pins that the bridge resolves against exactly those values). #[tokio::test] async fn bridge_core_fingerprint_is_the_registered_value() { @@ -437,7 +437,7 @@ async fn bridge_core_fingerprint_is_the_registered_value() { } /// - *Contract stamp:* ADR-004 decision 1 (`SHA256:` + unpadded -/// standard-alphabet base64 — the wave-1 record, re-asserted against +/// standard-alphabet base64 (the wave-1 record), re-asserted against /// every committed fixture's `ssh-keygen -lf` value). #[test] fn every_fixture_fingerprint_format_stays_the_contract_invariant_shape() { @@ -452,7 +452,7 @@ fn every_fixture_fingerprint_format_stays_the_contract_invariant_shape() { } /// - *Contract stamp:* ADR-005 decision 6 (host-key loading is the -/// construction's business, never the auth hooks' — the bridge +/// construction's business, never the auth hooks'; the bridge /// handler builds over an absent host-key source and never loads it, /// and the absent shape still refuses fail-closed if it were). #[tokio::test] diff --git a/tests/bounded_resources.rs b/tests/bounded_resources.rs index 116eb2d..7ed74f4 100644 --- a/tests/bounded_resources.rs +++ b/tests/bounded_resources.rs @@ -1,4 +1,4 @@ -//! The `w2-bounded-resources` contract rows — the bounded-resources +//! The `w2-bounded-resources` contract rows: the bounded-resources //! policy enforced through the real wire via the loopback harness: the //! in-crate concurrent-channel cap at every `channel_open_*` accept //! path, its recovery on close, its `Limits` tunability, and the @@ -8,7 +8,7 @@ //! `channel_buffer_size`), the inactivity wall clock and the remaining //! auth-counting posture ride the config-mapping tests //! (`adapter.rs` `#[cfg(test)]` + the harness's own -//! `client_config_maps_the_limits_postures`) — recorded, not +//! `client_config_maps_the_limits_postures`); recorded, not //! re-proven on the wire here. //! //! The cap rows are feature-gated to the builds whose opens can be @@ -41,7 +41,7 @@ fn registered_provider(fingerprints: &[&str]) -> Arc { } /// Mounts an authenticated loopback session over the doubles with the -/// row's [`Limits`] — the bounded-resources rows' driver. +/// row's [`Limits`], the bounded-resources rows' driver. async fn authenticated_with(limits: Limits) -> LoopbackSession { let provider = registered_provider(&[fixture("alpha").fingerprint]); let adapter = SshAdapter::new(serve_config( @@ -67,7 +67,7 @@ async fn authenticated_with(limits: Limits) -> LoopbackSession { session } -/// Matches an open failure's SSH reason — the wire decline reason the +/// Matches an open failure's SSH reason, the wire decline reason the /// cap-gate rows assert. fn open_failure(err: Error, expected: ChannelOpenFailure, context: &str) { assert!( @@ -80,7 +80,7 @@ fn open_failure(err: Error, expected: ChannelOpenFailure, context: &str) { } /// - *Contract stamp:* `overview.md` §Bounded-resources policy (the -/// auth-attempts row — the `max_auth_attempts` knob is behavioral, +/// auth-attempts row; the `max_auth_attempts` knob is behavioral, /// verified where cheap: the ceiling disconnects an exceeding /// client) + ADR-004 decision 6 (the mapping in `adapter.rs` makes /// the knob the counting ceiling; within the ceiling, failures stay @@ -91,7 +91,7 @@ fn open_failure(err: Error, expected: ChannelOpenFailure, context: &str) { /// three unregistered keys. The first two rejections stay ordinary /// failures with the advertisement intact; the third request past the /// ceiling is answered with the server's -/// `Disconnect::NoMoreAuthMethodsAvailable` — client-side, the +/// `Disconnect::NoMoreAuthMethodsAvailable`. Client-side, the /// in-flight attempt sees russh's synthesized `Failure` with the /// **empty** remaining-methods set (no reply ever came; the /// advertisement is gone). The session ends cleanly server-side. @@ -165,7 +165,7 @@ async fn auth_attempt_ceiling_disconnects_an_exceeding_client() { ); } Err(_) => { - // The client loop already exited on the disconnect — the + // The client loop already exited on the disconnect, the // equally-valid torn-down shape (the send side is gone). } } @@ -177,7 +177,7 @@ async fn auth_attempt_ceiling_disconnects_an_exceeding_client() { .expect("the ceiling disconnect ends the session cleanly"); } -/// The remaining-methods set of an [`AuthResult`] — `None` on success +/// The remaining-methods set of an [`AuthResult`]; `None` on success /// (the within-ceiling vs past-ceiling observation shape). fn remaining_ads(result: &russh::client::AuthResult) -> Option { match result { @@ -208,7 +208,7 @@ async fn concurrent_channel_cap_declines_and_recovers_over_the_wire() { let err = open_session_channel(&session.client) .await - .expect_err("the third open is refused at the cap — never queued"); + .expect_err("the third open is refused at the cap, never queued"); open_failure( err, ChannelOpenFailure::AdministrativelyProhibited, @@ -219,13 +219,13 @@ async fn concurrent_channel_cap_declines_and_recovers_over_the_wire() { // The close reply is not observable client-side at this pin: russh // removes a locally-closed channel from its map before the - // server's CHANNEL_CLOSE arrives back, so no message — and no - // `None` — is ever delivered (the harness's `await_close` only + // server's CHANNEL_CLOSE arrives back; no message, and no + // `None`, is ever delivered (the harness's `await_close` only // observes *server-initiated* closes). The recovery observation is // the open itself, and it is deterministic: close and open ride // the client loop's single FIFO event queue, they are written in // that order on the wire, and the server's packet loop processes - // them in order — the counted close releases before the recovery + // them in order; the counted close releases before the recovery // open is admitted. Had the release not happened, this open // declines and this expect fails. let _third = open_session_channel(&session.client) @@ -249,7 +249,7 @@ async fn zero_cap_refuses_every_open_and_poisons_nothing() { for attempt in 1..=2 { let err = open_session_channel(&session.client) .await - .expect_err("a zero cap refuses the very first open — no half-open, no queue"); + .expect_err("a zero cap refuses the very first open: no half-open, no queue"); open_failure( err, ChannelOpenFailure::AdministrativelyProhibited, @@ -262,8 +262,8 @@ async fn zero_cap_refuses_every_open_and_poisons_nothing() { /// - *Contract stamp:* `w3-tunnel-direct`'s recorded admission /// mechanics (decline-first-alloc-never applies to the cap budget -/// too): the tunnel row's pre-admit classes — here the **absent -/// fabric handle** under the feature — answer before the admission +/// too): the tunnel row's pre-admit classes (here the **absent +/// fabric handle** under the feature) answer before the admission /// is taken, so under an exhausted cap the absent-handle class /// (`ConnectFailed`, the cannot-bridge wire class) wins over the cap /// reason. The cap class on a *configured* direct row rides @@ -281,7 +281,7 @@ async fn the_tunnel_rows_pre_admit_class_answers_before_the_cap_gate() { let _first = open_session_channel(&session.client) .await - .expect("the first open admits — the cap is now exhausted"); + .expect("the first open admits, so the cap is now exhausted"); let err = open_direct_tcpip(&session.client, "internal.example", 5432) .await diff --git a/tests/client_dial.rs b/tests/client_dial.rs index c9f7f3a..09336f0 100644 --- a/tests/client_dial.rs +++ b/tests/client_dial.rs @@ -1,4 +1,4 @@ -//! The dial surface's contract rows (`w4-dial`) — driven through the +//! The dial surface's contract rows (`w4-dial`), driven through the //! in-process fake `sshd` ([`sshd_double`](common::sshd_double), the //! client-direction vehicle) plus the crate-to-crate smoke against //! the alkssh server direction. The row/stamp discipline @@ -21,7 +21,7 @@ use russh::{ChannelOpenFailure, Error}; use sshd_double::SshdDouble; -/// A vault-backed key source over the alpha fixture — the standard +/// A vault-backed key source over the alpha fixture, the standard /// custody posture (the fixture PEM sealed, decrypt-at-dial behind /// the production source). fn alpha_key_source() -> Arc { @@ -91,10 +91,10 @@ fn postured_key_source(posture: &'static str) -> (Arc, KeySourceE } /// - *Contract stamp:* `client.md` §Lifecycle primitives (the -/// explicit-vs-drop boundary, the OQ-12 primitives-only posture) — -/// **drop is never the clean path**: dropping the (feature-free, +/// explicit-vs-drop boundary, the OQ-12 primitives-only posture): +/// **drop is never the clean path**. Dropping the (feature-free, /// last) wire-stack handle ends the runner and the transport goes -/// down abruptly — the double's serving outcome is the error wire +/// down abruptly; the double's serving outcome is the error wire /// class, never the clean session end only `close()` produces (see /// `dial_success_lands_an_authenticated_connection`'s `Ok`). #[tokio::test] @@ -117,14 +117,14 @@ async fn dropping_the_connection_is_an_abrupt_teardown_close_is_the_only_clean_p let outcome = double.next_session_outcome().await; assert!( matches!(outcome, Some(Err(_))), - "the un-closed drop tears the peer's session down abruptly — \ + "the un-closed drop tears the peer's session down abruptly; \ never the clean `Ok`, got {outcome:?}" ); double.shutdown(); } /// - *Contract stamp:* the dial surface's success row: decrypt-at-dial -/// → the policy accept → the single publickey attempt — an +/// → the policy accept → the single publickey attempt: an /// authenticated connection, the dial data carried on its surface, /// and the clean close the peer observes. #[tokio::test] @@ -171,7 +171,7 @@ async fn dial_success_lands_an_authenticated_connection() { } /// `127.0.0.1:9` is deliberately unbound in the no-dial rows: a dial -/// that reached the socket would fail with a wire class — only a +/// that reached the socket would fail with a wire class; only a /// refused key load can produce the key-source classes here. /// /// - *Contract stamp:* ADR-005 decision 2 (decrypt-at-*dial*) + @@ -200,7 +200,7 @@ async fn every_key_source_posture_is_a_no_dial_outcome() { } /// - *Contract stamp:* OQ-05 resolution (`host_key.rs`): the crate's -/// built-in default policy connects to nothing — the dial refuses +/// built-in default policy connects to nothing; the dial refuses /// as the decline class (`DialError::HostKeyRejected`), never a /// wire crash class, never a fallback. #[tokio::test] @@ -224,7 +224,7 @@ async fn the_crate_default_policy_connects_to_nothing() { } /// - *Contract stamp:* OQ-05 resolution, case 1 (known beforehand): -/// an assembly pin **hard-declines on mismatch** — the dial aborts; +/// an assembly pin **hard-declines on mismatch** (the dial aborts); /// the policy's own log carries the context (the presented key's /// real fingerprint rode the policy; the crate never second-guesses). #[tokio::test] @@ -257,7 +257,7 @@ async fn pin_mismatch_hard_declines() { } /// - *Contract stamp:* OQ-05 resolution, case 2 (unknown beforehand): -/// a permissive assembly policy decides — the dial proceeds; the +/// a permissive assembly policy decides and the dial proceeds; the /// crate ships no accept-all of its own (the permissive posture /// was this row's explicit choice, `MemHostKeyPolicy:: /// with_default(true)`). @@ -285,7 +285,7 @@ async fn case2_policy_decides_and_the_dial_proceeds() { /// - *Contract stamp:* the publickey-only family contract: the /// remote end refusing the single attempt is the dial's -/// [`DialError::AuthRejected`] — no retry, no fallback method, the +/// [`DialError::AuthRejected`]: no retry, no fallback method, the /// attempt closed behind the refusal. #[tokio::test] async fn refused_authentication_is_the_dials_no_connection_outcome() { @@ -324,8 +324,8 @@ async fn malformed_address_refuses_at_the_dial() { /// - *Contract stamp:* the bounded-config wiring (the task's /// acceptance): the dial's russh `Config` carries the -/// [`Limits`]-mapped knobs — the keepalive 15 s / 3 posture, the -/// always-set wall clock, the window/packet/buffer knobs verbatim — +/// [`Limits`]-mapped knobs (the keepalive 15 s / 3 posture, the +/// always-set wall clock, the window/packet/buffer knobs verbatim) /// observed from outside the crate through the doc-hidden mapping. #[test] fn the_bounded_config_wiring_is_observable() { @@ -341,7 +341,7 @@ fn the_bounded_config_wiring_is_observable() { /// - *Contract stamp:* ADR-003 §4 (the client-side fail-closed /// acceptor): the dialed client's skeleton declines **every** -/// server-initiated open on the wire — the double's initiator +/// server-initiated open on the wire (the double's initiator /// observes each open as an unconfirmed refusal, never russh's /// accept-and-drop default; the never-feature rows (x11, agent) /// decline too; the declines consulted no host-key policy; and the @@ -351,7 +351,7 @@ fn the_bounded_config_wiring_is_observable() { /// (`should_accept_unknown_server_channel` has no wire row: russh's /// server surface exposes no initiator for an unknown type and the /// `ChannelId` is deliberately unconstructible outside the library -/// — the skeleton's explicit `false` is code-pinned, not +/// while the skeleton's explicit `false` is code-pinned, not /// row-pinned; recorded in the task.) #[tokio::test] async fn server_initiated_opens_decline_cleanly_on_the_wire() { @@ -398,7 +398,7 @@ async fn server_initiated_opens_decline_cleanly_on_the_wire() { assert_eq!( policy.decisions().len(), 1, - "the declines consulted no host-key policy — one decision, the dial's" + "the declines consulted no host-key policy: one decision, the dial's" ); let forwarded = event_capture::await_event(&[ @@ -440,7 +440,7 @@ async fn server_initiated_opens_decline_cleanly_on_the_wire() { /// The smoke posture (`w4-dial`'s decided + recorded item): the /// alkssh client ↔ alkssh server in-process loopback over a real TCP -/// socket — the cheap real-stack smoke (both russh stacks, the full +/// socket, the cheap real-stack smoke (both russh stacks, the full /// auth bridge server-side, the full custody + policy chain /// client-side). A real-`sshd` dial is wave-5 e2e territory. /// diff --git a/tests/client_ops.rs b/tests/client_ops.rs index a3fb2fc..616b297 100644 --- a/tests/client_ops.rs +++ b/tests/client_ops.rs @@ -1,10 +1,10 @@ -//! The op rows' contract rows (`w4-op-rows`) — driven through the +//! The op rows' contract rows (`w4-op-rows`), driven through the //! in-process fake `sshd` grown with the op-row script //! ([`sshd_double`](common::sshd_double), the client-direction //! vehicle): featured + working rows (exec exit-status, pty //! window-change riding the live pump, the direct-tcpip pump, the git //! exec round trip), the decline rows (server-rejected opens, the -//! sftp placeholder, the off-Unix streamlocal twin — OQ-11), and the +//! sftp placeholder, the off-Unix streamlocal twin (OQ-11), and the //! connection-stays-usable row after each decline class. The //! row/stamp discipline (`tests/common/mod.rs`'s doc) applies //! verbatim. @@ -13,8 +13,8 @@ //! rows' cheap real-stack smoke is the alkssh-client-op-row ↔ //! alkssh-server-direction loopback (both russh stacks; the client //! exec row driven against the server direction's *real* session rows -//! — the chunk bridge's two arms meeting over one live wire), gated -//! on tooling like the wave-3 smokes — skipped-with-reason when +//! and the chunk bridge's two arms meeting over one live wire), gated +//! on tooling like the wave-3 smokes (skipped-with-reason when //! absent, never silently green. A real-vanilla-`sshd` dial is wave-5 //! e2e territory explicitly (see the task's Notes). @@ -37,7 +37,7 @@ use common::sshd_double::DblExit; use common::sshd_double::{SshdDouble, SshdObserved, SshdScript, spawn_scripted}; use common::{MemHostKeyPolicy, TestVault, fixture}; -/// A vault-backed key source over the alpha fixture — the dial +/// A vault-backed key source over the alpha fixture, the dial /// posture (the fixture PEM sealed, decrypt-at-dial). fn alpha_key_source() -> Arc { let vault = TestVault::unlocked(); @@ -45,7 +45,7 @@ fn alpha_key_source() -> Arc { Arc::new(alkssh::VaultKeySource::new(vault.handle(), Some(blob))) } -/// Dials a fresh double under the given script — one dial per row per +/// Dials a fresh double under the given script (one dial per row per /// double. Returns the connection, the double (its outcome channel /// for the clean-close rows) and the double's observations. async fn dial_scripted(script: SshdScript) -> (SshConnection, SshdDouble, SshdObserved) { @@ -76,7 +76,7 @@ async fn dial_scripted_limits( } /// The clean-close observable: the explicit close leaves the double's -/// session `Ok` — the decline rows' "the connection stays usable" +/// session `Ok`, the decline rows' "the connection stays usable" /// final act. async fn expect_clean_close(connection: SshConnection, mut double: SshdDouble) { assert!(!connection.is_closed()); @@ -102,12 +102,12 @@ async fn no_open_observed(double: &mut SshdDouble, within: &str) { /// OQ-13's client mirror: the sftp op declines cleanly in **every** /// build (the `sftp` feature ships in the build string but gates no -/// route — the featured-build variant below pins that half too, +/// route; the featured-build variant below pins that half too, /// `--all-features` running both). /// /// - *Contract stamp:* OQ-13 (the decline placeholder is the shipped /// behavior, both directions) + `client.md` §op rows (row 5) + §What -/// the crate does *not* include — before any wire op: no session +/// the crate does *not* include: before any wire op, no session /// channel ever opens at the peer, no subsystem request ever rides, /// and the connection stays usable (the clean close is the double's /// clean session end). @@ -135,7 +135,7 @@ async fn sftp_feature_on_the_placeholder_still_declines() { let err = connection .sftp() .await - .expect_err("the feature never serves the route (OQ-13 — the placeholder ships)"); + .expect_err("the feature never serves the route (OQ-13, the placeholder ships)"); assert!(matches!(err, OpError::SftpNotServed), "got {err:?}"); assert!(observed.execs().is_empty()); no_open_observed(&mut double, "the featured placeholder's decline").await; @@ -150,7 +150,7 @@ mod session_rows { use tokio::io::AsyncWriteExt; /// Frames one chunk by hand (`stream_type` byte + the big-endian - /// `u32` length + payload — the published header format, read + /// `u32` length + payload, the published header format read /// back only through alktty's own [`ChunkReader`]). fn frame(stream_type: u8, payload: &[u8]) -> Vec { let mut out = vec![stream_type]; @@ -159,14 +159,14 @@ mod session_rows { out } - /// Frames one control chunk — the family currency's own + /// Frames one control chunk; the family currency's own /// serializer builds the payload. async fn control_frame(message: &ControlMessage) -> Vec { let payload = message.to_json().expect("the control serializes"); frame(STREAM_CTRL_IN, &payload) } - /// Drains the hub's chunk plane until the exit chunk or the end — + /// Drains the hub's chunk plane until the exit chunk or the end; /// returns (stdout, stderr, the exit code in-band, if any). async fn read_to_exit(mut session: alkssh::RemoteSession) -> (Vec, Vec, Option) { let mut stdout = Vec::new(); @@ -206,7 +206,7 @@ mod session_rows { } /// - *Contract stamp:* `client.md` §op rows (row 1, the exec - /// translation + the family plane) — the wire carries the + /// translation + the family plane): the wire carries the /// family command verbatim (`exec()`, never `request_exec`); /// stdout/stderr come back as distinct chunks and the exit /// status rides the family chunk in-band, last. @@ -241,7 +241,7 @@ mod session_rows { expect_clean_close(connection, double).await; } - /// - *Contract stamp:* POC-3 §D.3 (the Success/Failure semantics — + /// - *Contract stamp:* POC-3 §D.3 (the Success/Failure semantics: /// **the Failure reply surfaces on the channel queue's drain, /// not as `Err` from the request call**) → /// [`OpError::RequestRefused`]; the refused row closes its @@ -271,7 +271,7 @@ mod session_rows { /// (the server direction's pre-parse cap, `Limits:: /// max_exec_command_len`, mirrored at the command-construction /// gate): a beyond-budget command declines **before any wire - /// op** — no channel, no request, bounded by construction. + /// op**; no channel, no request, bounded by construction. #[tokio::test] async fn oversized_exec_declines_before_any_wire_op() { let limits = Limits { @@ -295,7 +295,7 @@ mod session_rows { } /// - *Contract stamp:* `client.md` §op rows (row 1, the pty/shell - /// translation) — the family [`TerminalParamsWire`] rides the + /// translation): the family [`TerminalParamsWire`] rides the /// wire `pty_request` verbatim (the reserved modes never ride: /// the double sees the params, and the wire request carries the /// empty terminal-modes set), and the shell request launches @@ -326,7 +326,7 @@ mod session_rows { } /// - *Contract stamp:* the pipe-mode shell parity (mirroring the - /// server direction's decided row — a pty-less shell is + /// server direction's decided row: a pty-less shell is /// legitimate vanilla and served, never declined): the /// `params: None` shell carries **no** pty request. #[tokio::test] @@ -348,7 +348,7 @@ mod session_rows { /// - *Contract stamp:* the pty control rows riding the **live /// pump** (the POC-3 §D.3 window-change/signal mechanics', /// client arm): the session never `into_stream()`s, so the - /// fire-and-forget rows ride the write half mid-session — the + /// fire-and-forget rows ride the write half mid-session; the /// `CTRL_IN` `Resize` translates to the wire `window_change` /// and `Signal` to the wire `signal` (the double's /// observations are the witnesses). @@ -418,7 +418,7 @@ mod session_rows { } /// - *Contract stamp:* the family exit-currency's signal mirror - /// (mapping.md's derivation contract, the client arm — consumed + /// (mapping.md's derivation contract, the client arm, consumed /// not re-derived): a wire `exit-signal("TERM")` reports the /// family code `−15` in-band (rule 2's value, the table read /// backwards; the derivation never invents). @@ -447,8 +447,8 @@ mod session_rows { } /// - *Contract stamp:* the never-half-capability posture (ADR-003 - /// decision 3, client mirror) — a **refused pty refuses the - /// whole row**: the exec behind it never rides the wire (the + /// decision 3, client mirror): a **refused pty refuses the + /// whole row**; the exec behind it never rides the wire (the /// double's exec observations stay empty). #[tokio::test] async fn refused_pty_refuses_the_whole_row_never_half_serves() { @@ -482,8 +482,8 @@ mod session_rows { /// class, `client.md` §Correctness facts): the session open /// refused (the scripted count) → `OpenDeclined(Prohibited)`, /// then a later launch on the *same connection* succeeds and - /// pumps — the usable-after-decline posture — and everything - /// closes clean. + /// pumps; that is the usable-after-decline posture, and + /// everything closes clean. #[tokio::test] async fn server_rejected_open_declines_and_the_connection_stays_usable() { let script = SshdScript { @@ -526,7 +526,7 @@ mod session_rows { /// - *Contract stamp:* the task's smoke item (the §module docs' /// decided posture; like the wave-3 smokes, skipped-with-reason /// when the tooling is absent): the client exec row driven - /// against the alkssh *server direction*'s real session rows — + /// against the alkssh *server direction*'s real session rows, /// both russh stacks over one live wire, the chunk bridge's two /// arms meeting (the client's family plane consuming the /// server's family plane), data and the exit-status @@ -539,7 +539,7 @@ mod session_rows { .output() .is_err() { - eprintln!("SKIPPED (with reason): the op-row smoke — sh is unavailable"); + eprintln!("SKIPPED (with reason): the op-row smoke, sh is unavailable"); return; } @@ -622,8 +622,8 @@ mod tunnel_rows { use tokio::io::{AsyncReadExt, AsyncWriteExt}; /// - *Contract stamp:* `client.md` §op rows (row 2, the typed - /// `channel_open_direct_tcpip` open — the alksocks `DialFn` - /// composes over this surface) + POC-3 §C.1's recipe reversed — + /// `channel_open_direct_tcpip` open; the alksocks `DialFn` + /// composes over this surface) + POC-3 §C.1's recipe reversed: /// the pump is the raw byte duplex, round-tripping, no channel /// queue consumed anywhere between the open and the /// `into_stream()` conversion. @@ -654,7 +654,7 @@ mod tunnel_rows { } /// - *Contract stamp:* the server-rejected open's family mirror - /// (POC-1 §6 — the typed open resolves `Err` on the reject, + /// (POC-1 §6: the typed open resolves `Err` on the reject, /// family-mapped) + the connection-stays-usable row **per /// decline class**: after the `ConnectFailed` class the /// streamlocal twin still opens and pumps through the same @@ -700,7 +700,7 @@ mod tunnel_rows { } /// - *Contract stamp:* OQ-11 (the streamlocal twin's runtime-Unix - /// gate, client arm — universal compile, clean off-Unix decline + /// gate, client arm: universal compile, clean off-Unix decline /// **before any wire op**): this row compiles only off-Unix; /// the on-Unix builds ride the usable-after-decline row's /// success half. @@ -729,7 +729,7 @@ mod git_rows { /// writes (a placeholder pack-side payload for the pump row). const ADVERT: &[u8] = b"0008version 2\n0000"; - /// - *Contract stamp:* `client.md` §op rows (row 4 — the shared + /// - *Contract stamp:* `client.md` §op rows (row 4; the shared /// exec grammar's command, *reused, not forked*; the wire /// carries `git-upload-pack '/owner/demo'` byte-verbatim) + the /// pack duplex pump + the exit-status consumption. @@ -793,7 +793,7 @@ mod git_rows { } /// - *Contract stamp:* the per-length cap's client mirror (the - /// shared grammar's verdict — `Limits:: + /// shared grammar's verdict, `Limits:: /// max_exec_command_len`): before any wire op. #[tokio::test] async fn oversized_git_command_declines_before_any_wire_op() { @@ -814,7 +814,7 @@ mod git_rows { } /// - *Contract stamp:* the upstream's own refusal is the - /// request-refusal class (the drain's `Failure` — POC-3 §D.3's + /// request-refusal class (the drain's `Failure`, POC-3 §D.3's /// git-row shape): declined cleanly, the connection intact. #[tokio::test] async fn refused_git_exec_surfaces_the_request_refusal() { diff --git a/tests/client_reverse_listen.rs b/tests/client_reverse_listen.rs index 853f501..77f39b3 100644 --- a/tests/client_reverse_listen.rs +++ b/tests/client_reverse_listen.rs @@ -1,5 +1,5 @@ //! The `-R` leg's contract rows (`w4-reverse-listen` + the listener -//! handles' lifecycle rows — `w4-lifecycle`) — driven through the +//! handles' lifecycle rows, `w4-lifecycle`), driven through the //! in-process fake `sshd` grown with the reverse-forward surfaces //! ([`sshd_double`](common::sshd_double): the `tcpip-forward` / //! `streamlocal-forward` hooks that bind **real** sockets and open the @@ -7,7 +7,7 @@ //! the listen rows (featured + registered → served, the port-0 mint, //! the cancels + the listener-cap ceiling), the acceptor-registry rows //! (featured + unregistered → clean decline; late-install across a -//! live connection — decline-before-install, serve-after; uninstall; +//! live connection: decline-before-install, serve-after; uninstall; //! the data-leg pump round trip), the off-Unix streamlocal rows //! (OQ-11), and the connection-stays-usable row after every decline //! class. The lifecycle rows pin the handles' posture: the actually- @@ -20,12 +20,12 @@ //! //! **Per-build matrix note (recorded):** this file is the //! `tunnel`-featured build's rows (the only build whose surface can -//! issue the reverse rows at all — the unfeatured build's compile-time +//! issue the reverse rows at all, the unfeatured build's compile-time //! mirror); the wire decline rows for the *unfeatured* builds run in //! every build through `tests/client_dial.rs`'s //! `server_initiated_opens_decline_cleanly_on_the_wire` (the //! decline-all skeleton the dial carries in a build without `tunnel` -//! — no registry exists there, every hook declines). +//! (no registry exists there, every hook declines). #![cfg(feature = "tunnel")] mod common; @@ -42,7 +42,7 @@ use common::sshd_double::{DblListen, SshdDouble, SshdObserved, SshdScript, spawn use common::{MemHostKeyPolicy, TestVault, fixture}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; -/// A vault-backed key source over the alpha fixture — the dial +/// A vault-backed key source over the alpha fixture, the dial /// posture (the fixture PEM sealed, decrypt-at-dial). fn alpha_key_source() -> Arc { let vault = TestVault::unlocked(); @@ -50,7 +50,7 @@ fn alpha_key_source() -> Arc { Arc::new(alkssh::VaultKeySource::new(vault.handle(), Some(blob))) } -/// Dials a fresh double under the given script — one dial per row. +/// Dials a fresh double under the given script: one dial per row. async fn dial_scripted_limits( script: SshdScript, limits: alkssh::Limits, @@ -76,7 +76,7 @@ async fn dial_scripted(script: SshdScript) -> (SshConnection, SshdDouble, SshdOb } /// The clean-close observable: the explicit close leaves the double's -/// session `Ok` — the "the connection stays usable" final act. +/// session `Ok`, the "the connection stays usable" final act. async fn expect_clean_close(connection: SshConnection, mut double: SshdDouble) { assert!(!connection.is_closed()); connection.close().await; @@ -89,7 +89,7 @@ async fn expect_clean_close(connection: SshConnection, mut double: SshdDouble) { } /// A free loopback port the row's listen asks for exactly (the probe -/// binds, then frees — a tiny race, as everywhere a fixed port is +/// binds, then frees (a tiny race, as everywhere a fixed port is /// picked; the rows mostly mint dynamic ports instead). async fn pick_port() -> u16 { let probe = tokio::net::TcpListener::bind("127.0.0.1:0") @@ -98,7 +98,7 @@ async fn pick_port() -> u16 { probe.local_addr().expect("addr").port() } -/// The byte round trip the acceptor double's echo pump runs — the +/// The byte round trip the acceptor double's echo pump runs; the /// data leg's plain duplex (the bytes back through the accepted /// channel; the pump is the assembly's). async fn echo_pump(mut stream: alkssh::TunnelChannel) { @@ -115,7 +115,7 @@ async fn echo_pump(mut stream: alkssh::TunnelChannel) { } } -/// What the acceptor double records per accepted open — the payload's +/// What the acceptor double records per accepted open (the payload's /// echo/originator fields (the duplex rides the type, never recorded). #[derive(Clone, Debug, PartialEq)] struct OpenRecord { @@ -125,7 +125,7 @@ struct OpenRecord { originator_port: u32, } -/// The acceptor double — records the payload's fields and, when the +/// The acceptor double: it records the payload's fields and, when the /// row asks, pumps the duplex as an echo (the family handler shape: /// the assembly owns the pump). #[derive(Clone)] @@ -152,7 +152,7 @@ impl TcpipForwardedAcceptor for AcceptorDouble { } } -/// The streamlocal acceptor double — the unix slot's shape. +/// The streamlocal acceptor double, the unix slot's shape. #[derive(Clone)] struct UnixAcceptorDouble { opens: tokio::sync::mpsc::UnboundedSender, @@ -171,7 +171,7 @@ impl StreamlocalForwardedAcceptor for UnixAcceptorDouble { } } -/// The next accepted open's fields — the row's payload observation +/// The next accepted open's fields, the row's payload observation /// (bounded await: a wrong row must not hang). async fn next_open( opens: &mut tokio::sync::mpsc::UnboundedReceiver, @@ -184,8 +184,8 @@ async fn next_open( } /// - *Contract stamp:* `client.md` §op rows row 4 (the `-R` leg's -/// listen + ingest row) + the module docs' listen-gate record — -/// featured + registered → served: the +/// listen + ingest row) + the module docs' listen-gate record: +/// featured + registered → served; the the /// `reverse_listen` request rides the wire (the double's /// `tcpip-forward` hook observes it verbatim), the actually-bound /// port returns, and the **data leg** round-trips: a connection to @@ -219,7 +219,7 @@ async fn reverse_listen_serves_and_the_data_leg_pumps() { assert_eq!( listener.endpoint().bound_port(), Some(port), - "an explicit port binds exactly that port — the handle carries it" + "an explicit port binds exactly that port; the handle carries it" ); let mut conn = @@ -255,7 +255,7 @@ async fn reverse_listen_serves_and_the_data_leg_pumps() { } /// - *Contract stamp:* `client.md` §Lifecycle primitives (the -/// bound-port spec) — `port = 0` mint: the peer picks and the +/// bound-port spec) the `port = 0` mint: the peer picks and the /// surfaced number is the actually-bound one (the row connects to /// it; the double's listener is the real socket, so the mint is the /// real shape sshd's `get_local_port` parity rides). @@ -306,7 +306,7 @@ async fn port_zero_mint_surfaces_the_actually_bound_port() { } /// - *Contract stamp:* ADR-003 §4's issuing-side mirror + the module -/// docs' listen-gate record — a reverse listen with no registered +/// docs' listen-gate record: a reverse listen with no registered /// acceptor declines **before any wire op** (`NoAcceptor`; the /// half-capability posture: a bound-but-unserveable listener is /// never asked for), and the connection stays usable. @@ -327,13 +327,13 @@ async fn reverse_listen_without_an_acceptor_declines_before_any_wire_op() { ); assert!( observed.listens().is_empty(), - "nothing rode the wire — the gate answered before the request" + "nothing rode the wire; the gate answered before the request" ); expect_clean_close(connection, double).await; } -/// - *Contract stamp:* ADR-003 §4 — featured + unregistered → clean +/// - *Contract stamp:* ADR-003 §4: featured + unregistered → clean /// decline: a server-initiated `forwarded-tcpip` open on a /// live connection with an empty registry answers /// `AdministrativelyProhibited` (never russh's accept-and-drop @@ -381,8 +381,8 @@ async fn unregistered_forwarded_open_declines_cleanly() { } /// - *Contract stamp:* the late-install dynamic (reverse-runner fact -/// 2 — consumers turn capabilities on/off per connection) + the -/// arrival-time gate — the same live connection: the pre-install +/// 2, consumers turn capabilities on/off per connection) + the +/// arrival-time gate, the same live connection: the pre-install /// arrival declines, the post-install arrival serves (never /// buffered, never half-served), and the acceptor double's late /// install is the registry's whole surface. @@ -444,7 +444,7 @@ async fn late_install_serves_after_a_pre_install_arrival_declined() { expect_clean_close(connection, double).await; } -/// - *Contract stamp:* the late-install toggle's off half — the +/// - *Contract stamp:* the late-install toggle's off half: the /// uninstall takes the capability off mid-connection: the /// post-uninstall arrival declines at arrival time (fail-closed; /// the already-accepted open's channel is the acceptor's business). @@ -501,7 +501,7 @@ async fn uninstall_takes_the_capability_off_before_a_later_arrival() { } /// - *Contract stamp:* `client.md` §Lifecycle primitives (every -/// listener explicitly cancellable) + the double's sshd parity — +/// listener explicitly cancellable) + the double's sshd parity: /// the cancel tears the real listener down (the bound port /// reconnects as refused), a cancel of an unknown listener is the /// peer's refusal (`ListenRefused`), and the connection stays @@ -557,7 +557,7 @@ async fn cancel_tears_the_forward_down_and_unknown_cancels_refuse() { } assert!( refused, - "the forward is torn down — the bound port refuses a reconnect" + "the forward is torn down; the bound port refuses a reconnect" ); let again = connection.reverse_listen_cancel("127.0.0.1", port).await; @@ -572,16 +572,16 @@ async fn cancel_tears_the_forward_down_and_unknown_cancels_refuse() { .await, Err(OpError::ListenRefused) ), - "no match by endpoint either — the raw-string parity holds" + "no match by endpoint either; the raw-string parity holds" ); expect_clean_close(connection, double).await; } /// - *Contract stamp:* `client.md` §Lifecycle primitives (the -/// explicit-vs-drop boundary, `w4-lifecycle`) — **no drop-timing -/// wire state**: dropping the listener handle without a cancel -/// frees nothing — the peer's listen keeps serving (the arrival +/// explicit-vs-drop boundary, `w4-lifecycle`): **no drop-timing +/// wire state**. Dropping the listener handle without a cancel +/// frees nothing; the peer's listen keeps serving (the arrival /// still hands off through the registered acceptor); only the /// explicit cancel tears the forward down (the bound port then /// refuses a reconnect). The `ReverseListener` carries no `Drop` @@ -662,11 +662,11 @@ async fn dropping_the_listener_handle_leaves_no_drop_timing_wire_state() { /// - *Contract stamp:* `client.md` §Lifecycle primitives (the /// cancel-release relation) + the cap relation with the -/// dedicated listener counter — the handle's `cancel()` is the +/// dedicated listener counter: the handle's `cancel()` is the /// confirmed teardown **which releases the listener count**: beyond /// the ceiling the listens refuse pre-wire, the handle's cancel /// (not the stateless form) recovers the budget, the next listen -/// admits again. The handle is consumed by its cancel — the one +/// admits again. The handle is consumed by its cancel: the one /// cancel through it; a second cancel rides the connection row and /// refuses (the unknown-listener wire answer, no release). #[tokio::test] @@ -733,7 +733,7 @@ async fn the_listener_handle_cancel_tears_the_forward_down_and_releases_the_budg .map(|(_, _, port)| *port) .collect::>(), vec![first, third], - "each handle's cancel rode the wire — one confirmed cancel per \ + "each handle's cancel rode the wire; one confirmed cancel per \ admitted listener" ); @@ -742,7 +742,7 @@ async fn the_listener_handle_cancel_tears_the_forward_down_and_releases_the_budg connection.reverse_listen_cancel("127.0.0.1", third).await, Err(OpError::ListenRefused) ), - "the stateless form's repeat is the unknown-listener refusal — \ + "the stateless form's repeat is the unknown-listener refusal; \ the confirmed release ran exactly once (the budgets never \ manufactured out of a repeated cancel)" ); @@ -751,12 +751,12 @@ async fn the_listener_handle_cancel_tears_the_forward_down_and_releases_the_budg } /// - *Contract stamp:* `client.md` §Lifecycle primitives (the row's -/// recorded contract) + the teardown-mid-connection posture — the +/// recorded contract) + the teardown-mid-connection posture: the /// cancel lands **while a data leg is live**: the confirmed cancel /// tears the forward down (the bound port refuses a reconnect), the /// connection stays usable (the `cancel` row's channel-scoped /// honesty) and ends clean despite the live leg (the peer observes -/// the clean session end — no half-open channels). +/// the clean session end, no half-open channels). #[tokio::test] async fn cancel_mid_data_leg_tears_the_forward_down_mid_connection() { let scripted = SshdScript { @@ -814,14 +814,14 @@ async fn cancel_mid_data_leg_tears_the_forward_down_mid_connection() { } assert!( refused, - "the forward is torn down while the leg was live — no more arrivals" + "the forward is torn down while the leg was live; no more arrivals" ); expect_clean_close(connection, double).await; } /// - *Contract stamp:* the module docs' recorded cap relation (the -/// server-side listener-counter posture mirrored) — the dedicated +/// server-side listener-counter posture mirrored): the dedicated /// listener count against the `max_concurrent_channels` ceiling: /// beyond it the listen declines **before any wire op** /// (`ListenCapExceeded`), and a confirmed cancel recovers the @@ -886,7 +886,7 @@ async fn the_listener_ceiling_bounds_the_listen_map_and_recovers_on_cancel() { } /// - *Contract stamp:* the module docs' refuse-never-replace posture -/// through the connection accessor — the second install is declined +/// through the connection accessor: the second install is declined /// (`AcceptorHeld`), the first acceptor stays served, and the /// uninstall/uninstall-again cycle reports honestly. #[tokio::test] @@ -1002,7 +1002,7 @@ async fn streamlocal_listen_serves_arrivals_and_cancels_through_the_unix_gate() let reconnect = tokio::net::UnixStream::connect(&socket_path).await; assert!( reconnect.is_err(), - "the unix forward is torn down — the socket path refuses a reconnect, got {reconnect:?}" + "the unix forward is torn down; the socket path refuses a reconnect, got {reconnect:?}" ); assert!( matches!( @@ -1017,7 +1017,7 @@ async fn streamlocal_listen_serves_arrivals_and_cancels_through_the_unix_gate() } /// - *Contract stamp:* OQ-11 (the runtime-Unix gate; universal -/// compile, clean off-Unix decline) + the module docs' gate record — +/// compile, clean off-Unix decline) + the module docs' gate record: /// off-Unix the unix listen declines **before any wire op** /// (`UnixUnavailable`; the platform-refused request consumes /// nothing). @@ -1044,7 +1044,7 @@ async fn streamlocal_declines_off_unix_before_any_wire_op() { ); assert!( observed.listens().is_empty(), - "nothing rode the wire — the gate answered before the request" + "nothing rode the wire; the gate answered before the request" ); expect_clean_close(connection, double).await; diff --git a/tests/common/event_capture.rs b/tests/common/event_capture.rs index 3f56e8b..1b9c1b5 100644 --- a/tests/common/event_capture.rs +++ b/tests/common/event_capture.rs @@ -5,13 +5,13 @@ //! module) against. The recorded test convention (see //! `tests/observe.rs`'s module docs) applies verbatim: no //! `tracing-subscriber` dependency (the hand-rolled shape needs none), -//! and the **global** default is the only capture shape that works — -//! the server side runs on spawned tasks, so a thread-local default +//! and the **global** default is the only capture shape that works +//! (the server side runs on spawned tasks, so a thread-local default //! never sees their events. //! //! Rows install once per binary with [`install`], then match events by -//! field pairs ([`await_event`]) — parallel rows never order against -//! each other — and pin the decline event's exact vocabulary with +//! field pairs ([`await_event`], so parallel rows never order against +//! each other) and pin the decline event's exact vocabulary with //! [`assert_request_decline`] (the exact-field-set assertion is the //! safety posture: no dynamic extra fields exist). @@ -28,7 +28,7 @@ pub struct Captured { } impl Captured { - /// The field's value by name — the rows' matching input. + /// The field's value by name, the rows' matching input. pub fn field(&self, name: &str) -> Option<&str> { self.fields .iter() @@ -89,7 +89,7 @@ impl tracing::Subscriber for GlobalCapture { } } -/// The installed capture — one per binary (the [`OnceLock`] makes the +/// The installed capture, one per binary (the [`OnceLock`] makes the /// exactly-once shape explicit). fn capture() -> &'static Arc { static CAPTURE: OnceLock> = OnceLock::new(); @@ -108,7 +108,7 @@ pub fn install() { let _ = capture(); } -/// The non-blocking peek — `Some` when a matching event is already on +/// The non-blocking peek; `Some` when a matching event is already on /// record, `None` otherwise. The e2e rows poll this alongside their /// bounded curls (the awaiting rows' `await_event` stays fixed-window; /// a slow CI host turns the wait-then-window shape into a flake, the @@ -125,7 +125,7 @@ pub fn captured_with(want: &[(&str, &str)]) -> Option { } /// Waits until an event matching every field pair appears, then -/// returns it — the spawned-task surfaces land their events +/// returns it (the spawned-task surfaces land their events /// asynchronously (the deadline loop is the observe-suite convention). pub async fn await_event(want: &[(&str, &str)]) -> Captured { let capture = capture(); @@ -143,7 +143,7 @@ pub async fn await_event(want: &[(&str, &str)]) -> Captured { } /// The expected `feature_build` value, derived from `cfg!` -/// independently of the crate's match — divergence breaks this loudly. +/// independently of the crate's match; divergence breaks this loudly. pub fn expected_build() -> &'static str { match ( cfg!(feature = "session"), @@ -171,7 +171,7 @@ pub fn expected_build() -> &'static str { } /// The request-decline vocabulary assertion: a captured request-level -/// decline carries exactly the vocabulary (sorted-name-set comparison — +/// decline carries exactly the vocabulary (a sorted-name-set comparison, /// nothing more; the dynamic-free shape is the safety posture), the /// build self-describing, the message shape, and the `debug` level (a /// decline is the door's normal, honest posture). `exec_route` present @@ -179,7 +179,7 @@ pub fn expected_build() -> &'static str { pub fn assert_request_decline(event: &Captured, exec_route: bool) { assert_eq!( event.level, "DEBUG", - "a decline emits at debug — the vocabulary's level posture" + "a decline emits at debug, the vocabulary's level posture" ); assert_eq!( event.field("feature_build"), diff --git a/tests/common/git_doubles.rs b/tests/common/git_doubles.rs index df99c8e..2da639d 100644 --- a/tests/common/git_doubles.rs +++ b/tests/common/git_doubles.rs @@ -1,21 +1,21 @@ -//! alkssh's git-seam doubles (`w3-git-mapping`) — the hand-rolled +//! alkssh's git-seam doubles (`w3-git-mapping`): the hand-rolled //! in-memory alkgit backend quartet, shaped per //! `alkgit/src/backend.rs:164-254`'s noop impls (the shapes that file //! itself pins for dyn compatibility), with recording accessors the //! rows assert through. alkgit's own `Mem*` constructions are -//! test-private to that crate — this module hand-rolls the minimal +//! test-private to that crate, so this module hand-rolls the minimal //! surface the git rows need, never a sibling-checkout path, never a //! copy of alkgit's doubles' *code*. //! //! State/accessor split: the doubles are configurable per row (repo //! records with visibility + grants; advertised ref lines) and //! record every seam call the serving path makes (resolutions, -//! applied CAS updates, prepared pushes' updates, generated packs) — +//! applied CAS updates, prepared pushes' updates, generated packs); //! the dispatch fidelity (which id was resolved, which updates were //! applied) is observable without alkgit's own test surface. //! //! Feature gating: this module is `git`-gated at the include site -//! (`tests/common/mod.rs`) — a non-git build compiles none of it, and +//! (`tests/common/mod.rs`); a non-git build compiles none of it, and //! alkgit types never appear outside. use std::collections::{BTreeMap, HashMap}; @@ -33,13 +33,13 @@ use async_trait::async_trait; use gix_hash::ObjectId; use parking_lot::{Mutex, RwLock}; -/// A test oid — deterministic bytes (the row-assertable hex shape). +/// A test oid, deterministic bytes (the row-assertable hex shape). pub fn oid(byte: u8) -> ObjectId { ObjectId::from([byte; 20]) } /// One repo the registry double serves: grants keyed by the resolved -/// identity id (alkgit's `authorize` input — the identity-ride +/// identity id (alkgit's `authorize` input, the identity-ride /// witness), the advertised ref set the refs double lists. pub struct RepoSetup { pub repo_id: String, @@ -116,7 +116,7 @@ pub struct GeneratedPack { /// One per-repo serve gate (the `w4-git-exit-close` row's /// serve-timing control): the double's `GitRefs::list_refs` for the -/// gated repo id pends on it until [`MemGate::release`] — the serving +/// gated repo id pends on it until [`MemGate::release`]; the serving /// task stalls at that call with its channel's reader parked, so the /// row schedules the serve's later stages (the answer flood, the /// serve tail) against a prepared wire state. Race-safe by @@ -152,7 +152,7 @@ impl MemGate { } } -/// The in-memory quartet: one struct, four trait impls — the +/// The in-memory quartet: one struct, four trait impls; the /// [`GitSeam`](alkssh::GitSeam) takes a separate `Arc` per backend /// trait and the rows share this state. #[derive(Default)] @@ -199,7 +199,7 @@ impl MemGit { self.generated.lock().clone() } - /// Installs a serve gate for one repo id — [`GitRefs::list_refs`] + /// Installs a serve gate for one repo id, so [`GitRefs::list_refs`] /// calls for it pend until the returned gate's `release`. The /// rows use the gate to prepare wire state (saturated queues, /// blocked clients) for the serve's later stages. @@ -212,7 +212,7 @@ impl MemGit { } } -/// The record for a resolved id — the RepoRecord the seam hands the +/// The record for a resolved id: the RepoRecord the seam hands the /// backend traits. fn record(id: &str, repos: &RepoRegistry) -> Result { match repos.get(id) { @@ -325,7 +325,7 @@ impl GitPackIngest for MemGit { } /// Assembles the recording quartet into a -/// [`GitSeam`](alkssh::GitSeam) — one shared `Arc`, the +/// [`GitSeam`](alkssh::GitSeam) taking one shared `Arc`, the /// default alkgit budget, the push-options gate off (the v1 default). pub fn git_seam(mem: &Arc) -> alkssh::GitSeam { alkssh::GitSeam { diff --git a/tests/common/harness.rs b/tests/common/harness.rs index ce90203..9b119b6 100644 --- a/tests/common/harness.rs +++ b/tests/common/harness.rs @@ -1,4 +1,4 @@ -//! alkssh's loopback harness (`w2-loopback-harness`) — the in-process +//! alkssh's loopback harness (`w2-loopback-harness`), the in-process //! client/server pair that is *the* contract-test vehicle for the //! crate: the wave-2 decline matrix, every wave-3 mapping's contract //! tests, and the client-direction smokes all drive the crate through @@ -8,7 +8,7 @@ //! the server-side [`SshAdapter::handle`](alkssh::SshAdapter::handle) //! mount runs over a **tokio duplex pair** ([`tokio::io::duplex`], //! [`DUPLEX_CAPACITY`] bytes each direction), and the client side -//! connects with [`russh::client::connect_stream`] — russh's real +//! connects with [`russh::client::connect_stream`]; russh's real //! codec, kex and transport run over the pair verbatim, so the wire //! path is fully exercised. The one thing it deliberately does not //! carry is OS-socket semantics; TCP loopback (`127.0.0.1:0`) was the @@ -16,13 +16,13 @@ //! lifecycle, loopback timing, accept-loop flakiness under slow CI) //! buys only what the real-tool smokes of the mapping waves and the //! e2e wave already cover cheaply. The duplex pair is deterministic, -//! needs no port, and cannot collide — the no-TCP-port-dependency +//! needs no port, and cannot collide, the no-TCP-port-dependency //! shape the acceptance criteria name. //! //! **Placement decision (recorded, the `w2-loopback-harness` //! counterpart of the wave-1 doubles' location decision):** the //! harness lives as a sibling module of the wave-1 doubles, under -//! `tests/common/`, reached with the same `mod common;` convention — +//! `tests/common/`, reached with the same `mod common;` convention: //! test surface, test-versioned freely, never a public API export //! (no re-export from `lib.rs`, no feature gate). Unlike the doubles //! it is a *vehicle* convention, not just a seam: later waves' @@ -37,7 +37,7 @@ //! `check_server_key` hook ([`HarnessClientHandler`]), and the //! keepalive / wall-clock posture from [`alkssh::Limits`] //! ([`client_config`]). The permissive posture for routine rows is -//! the double's `with_default(true)` — an explicit test choice; the +//! the double's `with_default(true)`, an explicit test choice; the //! accept-all posture exists only here, never as a crate built-in, //! and the fail-closed rows construct `with_default(false)`. //! @@ -46,11 +46,11 @@ //! [`LOOPBACK_HOST`] and [`LOOPBACK_PORT`]; host-key policy rows pin //! rules against those values verbatim. The presented key's //! fingerprint is the crate's single fingerprint path -//! ([`alkssh::fingerprint`]) — exactly the decision input the wave-4 +//! ([`alkssh::fingerprint`]), exactly the decision input the wave-4 //! dial wiring will compute at russh's own hook, so this bridge is //! that wiring's rehearsal. //! -//! Helpers stay thin — the russh client API is the vocabulary; these +//! Helpers stay thin (the russh client API is the vocabulary); these //! remove boilerplate (config assembly, mount/spawn, fixture-key //! plumbing, drain loops), never semantics: every observation is a //! russh-verbatim shape ([`AuthResult`], [`Error`], @@ -60,7 +60,7 @@ //! landed the auth/session/exec/shell/subsystem vocabulary, and //! `w2-dispatch-decline-core` extended it with the decline-matrix //! vocabulary (the tunnel/x11 opens, the pty/env/x11/agent-forward -//! requests, the listen requests) — its recorded expectation that the +//! requests, the listen requests); its recorded expectation that the //! "session-request and exit-status/close helpers are exercised by //! construction this wave ... their live rows arrive with //! `w2-dispatch-decline-core`" is discharged by exactly that @@ -86,20 +86,20 @@ use alkssh::{ use super::{FixtureKey, MemHostKeyPolicy, MemHostKeySource}; -/// The host label the loopback presents to the host-key policy — a +/// The host label the loopback presents to the host-key policy: a /// duplex pair has no endpoint, so every decision is labeled with /// this constant (see the module docs §Host identity). pub const LOOPBACK_HOST: &str = "loopback"; -/// The port label for the loopback's presented host key — `0`, the +/// The port label for the loopback's presented host key (`0`), the /// no-port marker: the transport has no TCP port by design. pub const LOOPBACK_PORT: u16 = 0; -/// Each duplex direction's buffer — the `w2-server-mount` wire-smoke +/// Each duplex direction's buffer, the `w2-server-mount` wire-smoke /// precedent's capacity, kept as the harness convention. pub const DUPLEX_CAPACITY: usize = 65_536; -/// The harness's russh client config — the keepalive / wall-clock +/// The harness's russh client config; the keepalive / wall-clock /// posture from [`Limits`]: `keepalive_interval` / `keepalive_max` /// mapped verbatim, `inactivity_timeout` carried as always-set (the /// crate never constructs a session with no wall clock, @@ -115,12 +115,12 @@ pub fn client_config(limits: Limits) -> Arc { } /// One server-initiated forwarded open the rows observe at the -/// harness client (`w3-tunnel-listen`'s accept-hook harness row — the +/// harness client (`w3-tunnel-listen`'s accept-hook harness row; the /// `-R` data leg arrives here). The `Channel` only carries data after /// the row accepts (the harness hook answers the open itself). #[derive(Debug)] pub enum ForwardedOpen { - /// The `forwarded-tcpip` row — the echo args + originator the door + /// The `forwarded-tcpip` row (the echo args + originator the door /// opened with, verbatim as the wire carried them. Tcpip { connected_address: String, @@ -137,11 +137,11 @@ pub enum ForwardedOpen { }, } -/// The harness client's acceptor — what a vanilla client's matching +/// The harness client's acceptor, what a vanilla client's matching /// `-R` listener stands-in as: when installed, server-initiated /// forwarded opens are accepted and handed to the row through the /// channel the acceptor was built with; **no acceptor installed → the -/// open declines cleanly** (`AdministrativelyProhibited` — the +/// open declines cleanly** (`AdministrativelyProhibited`; the /// family's client-side contract, ADR-003 symmetry: a vanillla stand- /// in with no matching forward never accept-and-drops). pub struct ForwardedAcceptor { @@ -166,7 +166,7 @@ impl ForwardedAcceptor { /// The client-direction data gate (`w4-git-exit-close`'s row /// vehicle): armed on a channel id, the harness client's packet loop /// pends inside its `data` hook for that channel's packets (the hook -/// is awaited inline in russh's client loop) — the server's outbound +/// is awaited inline in russh's client loop); the server's outbound /// writes for the channel back up through the transport's duplex pair /// into the server's message queue until [`DataGate::release`]. The /// held counter (`DataGate::held_packets`) lets the row observe that @@ -179,7 +179,7 @@ pub struct DataGate { } impl DataGate { - /// Builds the inert gate — arm it with [`DataGate::arm`] once the + /// Builds the inert gate; arm it with [`DataGate::arm`] once the /// row has the channel id to gate. pub fn new() -> Self { Self { @@ -199,14 +199,14 @@ impl DataGate { *self.release.lock() = Some(release); } - /// How many data packets have hit the armed gate so far — the + /// How many data packets have hit the armed gate so far, the /// row's freeze signal (count `>= 1` means the client's packet /// loop is pended inside the hook). pub fn held_packets(&self) -> usize { self.held.load(Ordering::Acquire) } - /// Releases the gate — the client's packet loop resumes and the + /// Releases the gate; the client's packet loop resumes and the /// backed-up server queues drain. pub fn release(&self) { *self.target.lock() = None; @@ -227,7 +227,7 @@ impl DataGate { } } -/// The harness's russh client handler — the [`MemHostKeyPolicy`] +/// The harness's russh client handler, the [`MemHostKeyPolicy`] /// decision double bridged into russh's `check_server_key` hook, with /// the decision input exactly as the wave-4 dial wiring will shape it /// ([`PresentedHostKey`] over the crate's fingerprint path), plus the @@ -241,9 +241,9 @@ pub struct HarnessClientHandler { } impl HarnessClientHandler { - /// Builds the handler over a policy double — `with_default(true)` + /// Builds the handler over a policy double: `with_default(true)` /// for the routine permissive posture, `with_default(false)` (or a - /// pinned rule) for the fail-closed rows — with the forwarded + /// pinned rule) for the fail-closed rows; with the forwarded /// acceptor absent (opens decline cleanly; install one with /// [`HarnessClientHandler::with_forwarded_acceptor`]). pub fn new(policy: Arc) -> Self { @@ -279,7 +279,7 @@ impl russh::client::Handler for HarnessClientHandler { /// The data gate's hook: when the gate is armed on this channel id /// and not yet released, the client's packet loop pends inside it - /// (the hook is awaited inline) — the server's outbound writes + /// (the hook is awaited inline), the server's outbound writes /// back up through the transport into its message queue until the /// row releases. Inert otherwise; also the block counter the row /// polls to know the freeze is real. @@ -373,7 +373,7 @@ impl russh::client::Handler for HarnessClientHandler { } } -/// Assembles the server side from the wave-1 doubles — a +/// Assembles the server side from the wave-1 doubles: a /// [`ServeConfig`] over the given identity provider and fixture host /// keys, with the session limits applied. pub fn serve_config( @@ -389,7 +389,7 @@ pub fn serve_config( serve } -/// Constructs the adapter from the doubles — [`serve_config`] with the +/// Constructs the adapter from the doubles ([`serve_config`] with the /// default [`Limits`]; the decrypt-at-construction failure paths are /// the construction tests' business (`w2-server-mount`), so a harness /// row's construction failing is a bug, not an observation. @@ -405,9 +405,9 @@ pub async fn adapter( /// One driven loopback session: the mounted server task plus the /// connected client handle and its policy double. pub struct LoopbackSession { - /// The connected russh client — the helpers' driver. + /// The connected russh client, the helpers' driver. pub client: Handle, - /// The policy double the connection's host-key decision rode — + /// The policy double the connection's host-key decision rode, /// decision-log inspection for the rows. pub host_key_policy: Arc, server_task: tokio::task::JoinHandle>, @@ -416,7 +416,7 @@ pub struct LoopbackSession { impl LoopbackSession { /// Ends one loopback row cleanly: disconnects the client, waits /// for the server task, and requires a clean session end on both - /// sides — the harness's every-row termination posture. + /// sides, the harness's every-row termination posture. pub async fn unmount(self) { self.client .disconnect(Disconnect::ByApplication, "row done", "en") @@ -432,7 +432,7 @@ impl LoopbackSession { /// Drives one loopback session: mounts the adapter over a duplex pair /// (spawned to completion, the assembly's accept-loop shape), connects /// a harness client against it and returns the pair. The adapter is -/// consumed (the spawned task owns it) — build a fresh one per row; +/// consumed (the spawned task owns it), so build a fresh one per row; /// the doubles make that cheap. /// /// Fallible at the connect step on purpose: a fail-closed host-key @@ -446,7 +446,7 @@ pub async fn drive( drive_with_acceptor(adapter, host_key_policy, limits, None).await } -/// [`drive`] with the client-side forwarded acceptor installed — the +/// [`drive`] with the client-side forwarded acceptor installed, the /// `w3-tunnel-listen` rows' vehicle (the harness handler's accept /// hook consumes the installed acceptor; `None` = the clean-decline /// posture [`drive`] carries). @@ -459,7 +459,7 @@ pub async fn drive_with_acceptor( mount_and_connect(adapter, host_key_policy, limits, acceptor, None).await } -/// [`drive`] with the client-direction data gate installed — the +/// [`drive`] with the client-direction data gate installed, the /// `w4-git-exit-close` row's vehicle. pub async fn drive_with_data_gate( adapter: SshAdapter, @@ -498,7 +498,7 @@ async fn mount_and_connect( }) } -/// Authenticates one fixture key — the auth helper: the fixture +/// Authenticates one fixture key, the auth helper: the fixture /// plumbing (`Arc` + `PrivateKeyWithHashAlg`) removed; the /// [`AuthResult`] comes back verbatim for the success / failure-shape /// rows to match on. @@ -515,7 +515,7 @@ pub async fn authenticate_publickey( } /// The failure shape's advertisement half: the remaining-methods set -/// carried by an [`AuthResult::Failure`] — `None` when the result is +/// carried by an [`AuthResult::Failure`]; `None` when the result is /// a success (the rows' success/failure observation shape). pub fn remaining_methods(result: &AuthResult) -> Option { match result { @@ -526,7 +526,7 @@ pub fn remaining_methods(result: &AuthResult) -> Option { } } -/// Opens a session channel — the open helper. Success is a confirmed +/// Opens a session channel, the open helper. Success is a confirmed /// [`Channel`]; the open-failure shape is the `Err` verbatim /// ([`Error::ChannelOpenFailure`] carries the SSH decline reason the /// decline-matrix rows match on). @@ -536,7 +536,7 @@ pub async fn open_session_channel( client.channel_open_session().await } -/// Opens a `direct-tcpip` channel — the tunnel open helper (`ssh -L` +/// Opens a `direct-tcpip` channel, the tunnel open helper (`ssh -L` /// / `ssh -D` traffic). The open-failure shape is the `Err` verbatim, /// the decline-matrix rows' reason surface. pub async fn open_direct_tcpip( @@ -549,7 +549,7 @@ pub async fn open_direct_tcpip( .await } -/// Opens a `direct-streamlocal` channel — the unix-socket forward +/// Opens a `direct-streamlocal` channel, the unix-socket forward /// helper. The open-failure shape is the `Err` verbatim. pub async fn open_direct_streamlocal( client: &Handle, @@ -558,7 +558,7 @@ pub async fn open_direct_streamlocal( client.channel_open_direct_streamlocal(socket_path).await } -/// Opens an x11 channel — the never-feature open helper (ADR-003 §5). +/// Opens an x11 channel, the never-feature open helper (ADR-003 §5). /// The open-failure shape is the `Err` verbatim. pub async fn open_x11_channel( client: &Handle, @@ -570,7 +570,7 @@ pub async fn open_x11_channel( .await } -/// Sends an exec request over a channel (`want_reply` set — the +/// Sends an exec request over a channel (`want_reply` set; the /// success/failure shape rides [`ChannelMsg::Success`]/[`ChannelMsg::Failure`] /// through [`next_message`]). pub async fn request_exec(channel: &Channel, command: &str) -> Result<(), Error> { @@ -587,19 +587,19 @@ pub async fn request_subsystem(channel: &Channel, name: &str) -> Result<(), channel.request_subsystem(true, name).await } -/// Sends a pty request over a channel (`want_reply` set — the pty row +/// Sends a pty request over a channel (`want_reply` set; the pty row /// rides the standard success/failure observation). pub async fn request_pty(channel: &Channel) -> Result<(), Error> { channel.request_pty(true, "xterm", 80, 24, 0, 0, &[]).await } -/// Sends an env request over a channel (`want_reply` set — the OQ-09 +/// Sends an env request over a channel (`want_reply` set; the OQ-09 /// unconditional-decline rows' observation). pub async fn request_env(channel: &Channel, name: &str, value: &str) -> Result<(), Error> { channel.set_env(true, name, value).await } -/// Sends an x11-req request over a channel (`want_reply` set — the +/// Sends an x11-req request over a channel (`want_reply` set; the /// never-feature request rows). pub async fn request_x11(channel: &Channel) -> Result<(), Error> { channel @@ -607,16 +607,16 @@ pub async fn request_x11(channel: &Channel) -> Result<(), Error> { .await } -/// Sends an agent-forwarding request over a channel (`want_reply` set -/// — the never-feature request rows; ADR-003 §5). +/// Sends an agent-forwarding request over a channel (`want_reply` +/// set, the never-feature request rows; ADR-003 §5). pub async fn request_agent_forward(channel: &Channel) -> Result<(), Error> { channel.agent_forward(true).await } -/// Requests a `tcpip-forward` listen (`-R` ingress) — the +/// Requests a `tcpip-forward` listen (`-R` ingress); the /// success/failure shape is the result verbatim /// ([`Error::RequestDenied`] on a declined listen; a `port = 0` -/// request's actually-bound number rides the success value — sshd +/// request's actually-bound number rides the success value, sshd /// parity). pub async fn tcpip_forward( client: &Handle, @@ -651,7 +651,7 @@ pub async fn cancel_streamlocal_forward( client.cancel_streamlocal_forward(socket_path).await } -/// Drains the acceptor's event channel — the row's observation shape +/// Drains the acceptor's event channel, the row's observation shape /// (`None` once the acceptor's sender went, i.e. after the session's /// end). pub async fn next_forwarded_open( @@ -660,13 +660,13 @@ pub async fn next_forwarded_open( receiver.recv().await } -/// Observes the next channel message — `None` after the channel has +/// Observes the next channel message; `None` after the channel has /// closed (russh's EOF-of-conversation shape). pub async fn next_message(channel: &mut Channel) -> Option { channel.wait().await } -/// Awaits the channel's exit status — drains interim messages until +/// Awaits the channel's exit status, draining interim messages until /// [`ChannelMsg::ExitStatus`] (the wave-3 derivation contract's /// observation shape) or the channel's end, which is `None`. pub async fn await_exit_status(channel: &mut Channel) -> Option { @@ -679,7 +679,7 @@ pub async fn await_exit_status(channel: &mut Channel) -> Option { } } -/// Awaits the channel's close — drains interim messages until +/// Awaits the channel's close, draining interim messages until /// [`ChannelMsg::Close`] (observed: `true`) or the channel's end /// (`false`). pub async fn await_close(channel: &mut Channel) -> bool { diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 5623a4a..a8ccaf4 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,4 +1,4 @@ -//! alkssh's wave-1 test doubles — the in-memory seams every later +//! alkssh's wave-1 test doubles, the in-memory seams every later //! wave's contract tests run against (the alkgit `tests/common/` //! convention, adapted): an in-memory `IdentityProvider` //! ([`MemIdentityProvider`]), the in-memory vault seam ([`TestVault`]), @@ -6,8 +6,8 @@ //! ed25519 test-key fixtures ([`FIXTURE_KEYS`]). //! //! **Location decision (recorded, the OQ-03 freeze-inventory -//! discipline):** the doubles live *only* here — a shared module under -//! `tests/` reached with `mod common;` — and never in the public API: +//! discipline):** the doubles live *only* here (a shared module under +//! `tests/` reached with `mod common;`) and never in the public API: //! no re-export from `lib.rs`, no feature gate, nothing doubles-related //! reachable from the crate root. The doubles' shapes are test //! surface, test-versioned freely; the only `src/`-side consumers are @@ -15,7 +15,7 @@ //! `include_str!`, never a public export. //! //! **Vault double decision (recorded, flagged for the wave-1 gate):** -//! alkvault 0.1 ships an in-memory construction — +//! alkvault 0.1 ships an in-memory construction: //! `VaultServiceHandle::new()` is an in-process vault that //! `unlock_new` arms in-memory. The double is therefore a *wrapper* //! ([`TestVault`]) around that construction, not a local re-impl @@ -26,7 +26,7 @@ //! //! **Fixture decision (recorded):** committed static OpenSSH-PEM test //! keys, minted by `ssh-keygen` at vector-generation time (the -//! independent issuer), never generated at test time — determinism and +//! independent issuer), never generated at test time; determinism and //! no tooling dependency. The committed private halves are throwaway //! fixtures, not secrets: minted for this suite only, never registered //! anywhere real, never deployed. Each key's fingerprint is recorded @@ -36,43 +36,43 @@ //! asserts parity against them. //! //! Each test binary's `mod common;` compiles the whole shared module -//! and no single binary exercises every double — dead_code is allowed +//! and no single binary exercises every double, so dead_code is allowed //! module-wide so one binary's suite never fails the next's. //! //! The row/stamp discipline (adapted from the sibling crates): test -//! functions are *rows* — the name states the property, not the -//! caller — and each carries a doc-comment list item beginning +//! functions are *rows* (the name states the property, not the +//! caller), and each carries a doc-comment list item beginning //! **`Contract stamp:`** citing the pinning spec §/ADR § (never a bare //! wave or date). The marker is greppable: //! `grep -rn "Contract stamp:" tests/` is the inventory. #![allow(dead_code)] -/// The loopback harness — *the* contract-test vehicle (its own +/// The loopback harness, *the* contract-test vehicle (its own /// location/transport decisions live in its module docs: /// `tests/common/harness.rs`). pub mod harness; -/// The in-process fake `sshd` (`w4-dial`) — the *client-direction* +/// The in-process fake `sshd` (`w4-dial`), the *client-direction* /// contract vehicle (the dial surface, the wave-4 client chain; its /// own placement/shape decisions live in the module docs: /// `tests/common/sshd_double.rs`). pub mod sshd_double; -/// The git-seam doubles (`w3-git-mapping`, `git`-gated — alkssh's +/// The git-seam doubles (`w3-git-mapping`, `git`-gated: alkssh's /// hand-rolled minimal alkgit quartet per `alkgit/src/backend.rs`'s /// noop shapes; the module's own doc records the decisions: /// `tests/common/git_doubles.rs`). #[cfg(feature = "git")] pub mod git_doubles; -/// The session-seam doubles (`w3-tty-session`, `session`-gated — the +/// The session-seam doubles (`w3-tty-session`, `session`-gated; the /// hand-rolled TtyBackend shim + ownership witness; the module's own /// doc records the decisions: `tests/common/tty_doubles.rs`). #[cfg(feature = "session")] pub mod tty_doubles; -/// The decline-row tracing capture (`w4-channel-not-held-rows`) — the +/// The decline-row tracing capture (`w4-channel-not-held-rows`); the /// mapping binaries' decline-class rows assert the event vocabulary /// through it (the module's own doc records the convention: /// `tests/common/event_capture.rs`). @@ -92,7 +92,8 @@ use alkssh::{HostKeyPolicy, HostKeySource, KeySourceError, PresentedHostKey}; /// (`tests/vectors/.pub`), and the fingerprint recorded /// byte-verbatim from `ssh-keygen -lf` (`tests/vectors/fingerprints.txt`). /// -/// The `pem`/`blob`/`fingerprint` values are committed constants — throwaway +/// The `pem`/`blob`/`fingerprint` values are committed constants, +/// throwaway /// fixture material, never registered or deployed anywhere real. #[derive(Debug)] pub struct FixtureKey { @@ -101,10 +102,10 @@ pub struct FixtureKey { /// The OpenSSH private-key PEM, included verbatim from the /// committed fixture file. pub pem: &'static str, - /// The public key's base64 blob — the OpenSSH one-line encoding, + /// The public key's base64 blob: the OpenSSH one-line encoding, /// `ssh-ed25519 ` stripped of the key-type prefix and comment. pub blob: &'static str, - /// The fingerprint recorded from `ssh-keygen -lf` — the + /// The fingerprint recorded from `ssh-keygen -lf`, the /// independent-issuer value every comparison in the suite asserts /// parity against (ADR-004 decision 1's contract invariant). pub fingerprint: &'static str, @@ -116,7 +117,7 @@ impl FixtureKey { parse_public_key_base64(self.blob).expect("committed fixture blob parses") } - /// The decoded private key — `decode_secret_key(pem, None)`, the + /// The decoded private key, `decode_secret_key(pem, None)`, the /// ADR-005 decision 2 conversion (the fixtures' inner format is /// exactly the at-rest contract: unencrypted OpenSSH PEM). pub fn private_key(&self) -> PrivateKey { @@ -155,7 +156,7 @@ pub const FIXTURE_KEYS: &[FixtureKey] = &[ }, ]; -/// Looks a fixture up by name — `fixture("alpha")` is the canonical +/// Looks a fixture up by name; `fixture("alpha")` is the canonical /// client-dial key. pub fn fixture(name: &str) -> &'static FixtureKey { FIXTURE_KEYS @@ -165,7 +166,7 @@ pub fn fixture(name: &str) -> &'static FixtureKey { } /// Builds an [`Identity`] for registration (`id` + scopes; the -/// `resources` map is empty — the wire layer only needs the resolved +/// `resources` map is empty; the wire layer only needs the resolved /// identity, richer ACL shapes are the assembly's). pub fn identity(id: &str, scopes: &[&str]) -> Identity { Identity { @@ -175,7 +176,7 @@ pub fn identity(id: &str, scopes: &[&str]) -> Identity { } } -/// The in-memory [`IdentityProvider`] — registered fingerprints → +/// The in-memory [`IdentityProvider`]: registered fingerprints → /// [`Identity`] resolutions over alkcall's trait verbatim. /// /// The double the wave-2 auth bridge and dispatch tests resolve @@ -187,7 +188,7 @@ pub struct MemIdentityProvider { } impl MemIdentityProvider { - /// An empty registry — nothing resolves until registered + /// An empty registry; nothing resolves until registered /// (fail-closed: unregistered fingerprints decline). pub fn new() -> Self { Self { @@ -202,12 +203,12 @@ impl MemIdentityProvider { .insert(fingerprint.to_string(), identity); } - /// Removes a registration — the post-resolution-revoke shape. + /// Removes a registration, the post-resolution-revoke shape. pub fn revoke(&self, fingerprint: &str) { self.identities.write().remove(fingerprint); } - /// The registered fingerprints — inspection for test assertions. + /// The registered fingerprints, inspection for test assertions. pub fn registered_fingerprints(&self) -> Vec { let mut keys = self .identities @@ -227,37 +228,37 @@ impl Default for MemIdentityProvider { } impl IdentityProvider for MemIdentityProvider { - /// The fingerprint path — ADR-004 decision 1's single resolution + /// The fingerprint path, ADR-004 decision 1's single resolution /// shape: exact string equality against registered values. fn resolve_from_fingerprint(&self, fingerprint: &str) -> Option { self.identities.read().get(fingerprint).cloned() } - /// The token path resolves nothing in the SSH direction — - /// ADR-004's dispositions are fingerprint-only on this surface + /// The token path resolves nothing in the SSH direction, + /// since ADR-004's dispositions are fingerprint-only on this surface /// (`auth-bridge.md`); the double never invents a token shape. fn resolve_from_token(&self, _: &AuthToken) -> Option { None } } -/// The in-memory vault seam — a wrapper over alkvault 0.1's own +/// The in-memory vault seam, a wrapper over alkvault 0.1's own /// in-memory construction ([`VaultServiceHandle`], unlocked at /// construction via `unlock_new`). /// /// The locked/absent/tampered/mismatch failure postures (POC-2 §3) are /// exercised *through the real production seams* the source traits -/// call, against this handle — the double exists so tests never touch +/// call, against this handle; the double exists so tests never touch /// vault lifecycle decisions themselves: [`TestVault::unlocked`] arms /// it, `lock` closes it, and the sources keep refusing, never -/// retrying (the crate never unlocks — ADR-005's separation). +/// retrying (the crate never unlocks, per ADR-005's separation). #[derive(Clone)] pub struct TestVault { handle: VaultServiceHandle, } impl TestVault { - /// A freshly armed in-memory vault — unlocked, ready to encrypt. + /// A freshly armed in-memory vault, unlocked and ready to encrypt. pub fn unlocked() -> Self { let handle = VaultServiceHandle::new(); handle @@ -266,13 +267,13 @@ impl TestVault { Self { handle } } - /// The vault handle the production sources consume — clones share + /// The vault handle the production sources consume; clones share /// the same vault state (locking through one is visible to all). pub fn handle(&self) -> VaultServiceHandle { self.handle.clone() } - /// Seals one fixture key's PEM into an at-rest record — the + /// Seals one fixture key's PEM into an at-rest record (the /// ADR-005 inner-format contract (unencrypted OpenSSH PEM in an /// `EncryptedData` record). pub fn seal(&self, key: &FixtureKey) -> EncryptedData { @@ -287,7 +288,7 @@ impl TestVault { .expect("in-memory vault encrypts the plaintext") } - /// Locks the vault — the locked-vault posture (POC-2 §3, the + /// Locks the vault, the locked-vault posture (POC-2 §3, the /// `KeySourceError::Locked` refusal class). pub fn lock(&self) { self.handle.lock(); @@ -299,14 +300,14 @@ impl TestVault { } } -/// The in-memory [`HostKeySource`] double — a static decrypted key set +/// The in-memory [`HostKeySource`] double, a static decrypted key set /// (wave-2 addition): the wire-shaped rows construct a real /// `SshAdapter`, whose construction wants a non-empty host-key set, and /// the direct-hook rows want a source that is never loaded (the handler -/// construction loads nothing — host keys are the russh `Config`'s +/// construction loads nothing; host keys are the russh `Config`'s /// business, built in [`alkssh::SshAdapter::new`]). /// -/// `absent()` is the empty-set shape — its load refuses with +/// `absent()` is the empty-set shape; its load refuses with /// [`KeySourceError::Absent`] (the fail-closed contract), so any row /// that accidentally loads an absent double fails loudly. pub struct MemHostKeySource { @@ -319,7 +320,7 @@ impl MemHostKeySource { Self { keys: Vec::new() } } - /// A static decrypted set from the fixture keys — the wire rows' + /// A static decrypted set from the fixture keys, the wire rows' /// host-key set (e.g. `["bravo"]`, the rotation-pair member). pub fn from_fixtures(keys: &[&'static FixtureKey]) -> Self { Self { @@ -339,12 +340,12 @@ impl HostKeySource for MemHostKeySource { } } -/// The in-memory [`HostKeyPolicy`] — a configurable verdict double with +/// The in-memory [`HostKeyPolicy`], a configurable verdict double with /// an inspectable decision log, for the wave-4 dial tests (and the /// case-1/case-2 rows of every host-key contract test). /// -/// Verdicts: a rules list of exact `(host, fingerprint)` matches — -/// last matching rule wins — falling back to a configurable +/// Verdicts: a rules list of exact `(host, fingerprint)` matches; +/// the last matching rule wins, falling back to a configurable /// default verdict for unlisted pairs. The default of the /// **default-constructed double is reject** (the crate's fail-closed /// posture, `OQ-05`); permissive verdicts are the test's explicit @@ -363,7 +364,7 @@ struct Rule { accept: bool, } -/// One recorded host-key decision — the presented key and the verdict +/// One recorded host-key decision: the presented key and the verdict /// the policy returned. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Decision { @@ -380,7 +381,7 @@ impl MemHostKeyPolicy { Self::with_default(false) } - /// A decision double with an explicit default verdict — the + /// A decision double with an explicit default verdict (the /// case-2 permissive posture (`accepting` doubles) is the test's /// explicit choice, never a default. pub fn with_default(default_verdict: bool) -> Self { @@ -401,13 +402,13 @@ impl MemHostKeyPolicy { }); } - /// Pins an accept rule for one `(host, fingerprint)` — the case-1 + /// Pins an accept rule for one `(host, fingerprint)`, the case-1 /// trust-anchor shape (hard accept on exact match). pub fn pin(&self, host: &str, fingerprint: &str) { self.rule(host, fingerprint, true); } - /// The decision log — every [`Decision`] in call order. + /// The decision log, every [`Decision`] in call order. pub fn decisions(&self) -> Vec { self.log.lock().clone() } @@ -440,7 +441,7 @@ impl HostKeyPolicy for MemHostKeyPolicy { /// The leg-2 rows' tracing visibility (`w3-tunnel-listen`): a minimal /// hand-rolled global [`tracing::Subscriber`] printing every event's -/// field pairs to stderr — the same hand-rolled convention the +/// field pairs to stderr, the same hand-rolled convention the /// crate-side vocabulary rows use (no `tracing-subscriber` /// dependency; events fire from spawned tasks on both sides of the /// fabric, so the global subscriber is the only capture shape that diff --git a/tests/common/sshd_double.rs b/tests/common/sshd_double.rs index df8d07b..6dd8b6c 100644 --- a/tests/common/sshd_double.rs +++ b/tests/common/sshd_double.rs @@ -1,9 +1,9 @@ -//! The in-process fake `sshd` (`w4-dial`) — the **client-direction** +//! The in-process fake `sshd` (`w4-dial`), the **client-direction** //! contract-test vehicle: a hand-rolled russh server handler standing //! in for the vanilla `sshd` every wave-4 dial row is pointed at (the //! reverse-runner shape). The alkssh loopback harness //! ([`super::harness`]) drives the *server* direction and is not the -//! vehicle here — the client dials *vanilla* servers, so this double +//! vehicle here (the client dials *vanilla* servers, so this double //! is a plain russh server (no alkssh in its serving path), on a real //! loopback TCP listener: a dial target is an address the dial //! surface resolves and connects to, which a duplex pair has no @@ -11,7 +11,7 @@ //! //! **Shape decisions (recorded, the task's placement item):** //! -//! - **Where**: sibling of the wave-1 doubles under `tests/common/` — +//! - **Where**: sibling of the wave-1 doubles under `tests/common/`; //! the module-placing convention (test surface, test-versioned //! freely, no public API export, no feature gate; the client //! handler skeleton it exercises compiles in every build). @@ -20,45 +20,45 @@ //! completion on its own task, and loops (a row never re-dials the //! same double). //! - **Identity**: the double resolves fingerprints against an -//! injected accept set ([`SshdAccepts`], exact-string equality — +//! injected accept set ([`SshdAccepts`]; exact-string equality, //! the family's only resolution shape, ADR-004 decision 1, the //! vanilla-parity stand-in for a real `sshd`'s //! `authorized_keys`). Every other auth hook is an explicit reject, //! never an inherited default (the ADR-004 decision 3 hygiene). //! - **Host keys**: the fixture host-key pair rides the //! `russh::server::Config`; the presented fingerprint is the -//! crate's single fingerprint path value — the rows' pin rules +//! crate's single fingerprint path value (the rows' pin rules match on //! match on `fixture("bravo")`'s recorded value. //! - **The session handle**: the double's `auth_succeeded` hook hands //! the per-connection [`russh::server::Handle`] to the row through -//! a one-shot carrier ([`SshdDouble::session_handle`]) — the row's +//! a one-shot carrier ([`SshdDouble::session_handle`]), the row's //! initiator for the server-initiated-open decline rows (server → //! client `channel_open_*`; the dialed client's skeleton declines; //! the server's open call observes -//! `Err(ChannelOpenFailure(..))` — the wire rows' observable). +//! `Err(ChannelOpenFailure(..))`, the wire rows' observable). //! - **The session handle**: the double's `auth_succeeded` hook hands //! the per-connection [`russh::server::Handle`] to the row through -//! a one-shot carrier ([`SshdDouble::session_handle`]) — the row's +//! a one-shot carrier ([`SshdDouble::session_handle`]), the row's //! initiator for the server-initiated-open decline rows (server → //! client `channel_open_*`; the dialed client's skeleton declines; //! the server's open call observes -//! `Err(ChannelOpenFailure(..))` — the wire rows' observable). +//! `Err(ChannelOpenFailure(..))`, the wire rows' observable). //! - **The acceptor stub**: rows that need a served session channel //! (the stays-usable-after-declines row here; the op-row vehicles //! later) arm the double to accept client session opens and hand //! the channel out ([`SshdDouble::next_opened_session`]). //! - **The op-row script** (`w4-op-rows`): the double's -//! request/open surfaces grow a small script — the session +//! request/open surfaces grow a small script: the session //! requests' reply (success/failure), the scripted stdout/stderr //! data + exit report a launched program would produce, and the -//! direct opens' echo-or-reject behavior — plus an observation +//! direct opens' echo-or-reject behavior, plus an observation //! surface (the recorded commands/pty params/window //! changes/signals the client rows assert the wire verbatim //! against). The double stays vanilla-parity: a hand-rolled //! responder standing in for `sshd`, nothing alkssh-typed inside. //! //! - **The `-R` server half** (`w4-reverse-listen`): the double grows -//! the reverse-forward surfaces a vanilla `sshd` really serves — the +//! the reverse-forward surfaces a vanilla `sshd` really serves: the //! `tcpip-forward` / `streamlocal-forward` global-request hooks //! (scripted accept/deny; an accept **binds a real socket** in //! sshd's role, so a `port = 0` request's minted bound port is the @@ -68,10 +68,10 @@ //! toward the client echoing the listen's own args + the //! connection's peer as the originator, then the bytes pumped //! bidirectionally; a client-declined open closes the accepted -//! connection — vanilla parity), and the cancel forms removing the +//! connection, vanilla parity), and the cancel forms removing the //! matching entry (tearing the real listener down; an unknown //! listener denies, sshd parity). The bookkeeping is per-connection -//! handler state and bounded by the scripted listens alone — the +//! handler state and bounded by the scripted listens alone (the //! double is a scripted stand-in, not a real server: at most one //! forward per scripted accept is what the rows drive. @@ -85,13 +85,13 @@ use russh::keys::PrivateKey; use russh::server::{Auth, Handle, Msg, PublicKeyOffer, Response, Session, VerifiedPublicKey}; use russh::{Channel, ChannelOpenFailure, MethodKind, MethodSet}; -/// The double's scripted exit report — what a launched program's -/// death would produce (`exit-status` / `exit-signal`). +/// The double's scripted exit report (what a launched program's +/// death would produce: `exit-status` / `exit-signal`). #[derive(Debug, Clone, Copy)] pub enum DblExit { /// `exit-status(N)`. Status(u32), - /// `exit-signal(name)` — the wire's signal-name class. + /// `exit-signal(name)`, the wire's signal-name class. Signal(&'static str), } @@ -99,7 +99,7 @@ pub enum DblExit { /// (`direct-tcpip` / `direct-streamlocal`). #[derive(Debug, Clone, Copy)] pub enum DblDirect { - /// Reject the open — the scripted server-refusal class + /// Reject the open: the scripted server-refusal class /// (`ConnectFailed`, the vanilla sshd's dead-target shape). Reject, /// Accept the open and echo-pump the channel (the pump rows' @@ -108,28 +108,28 @@ pub enum DblDirect { } /// The double's scripted behavior for the client's reverse-forward -/// listen requests (`tcpip-forward` / `streamlocal-forward@…) — the +/// listen requests (`tcpip-forward` / `streamlocal-forward@…`), the /// `-R` rows' scripted class (`w4-reverse-listen`). #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum DblListen { - /// Deny the listen — the vanilla sshd's refusal (the scripted + /// Deny the listen; the vanilla sshd's refusal (the scripted /// server-refusal class; the wire `RequestFailure` the client's /// op row mirrors). The script's default (fail-closed double). #[default] Deny, /// Accept the listen: the double binds a **real socket** in - /// sshd's role (the actually-bound port rides the reply's mint — + /// sshd's role (the actually-bound port rides the reply's mint, /// the port-0 row's real shape), records it for the cancel forms, /// and spawns the accept loop (per accepted connection: a /// server-initiated `forwarded-*` open toward the client echoing /// the listen's own args + the connection's peer, then the bytes /// pumped bidirectionally; a client-declined open closes that - /// accepted connection — vanilla parity). + /// accepted connection, vanilla parity). Accept, } /// The fake `sshd`'s op-row script (the `w4-op-rows` request -/// surfaces) — what the double answers and, on a success, what the +/// surfaces), what the double answers and, on a success, what the /// scripted "program" produces. #[derive(Debug, Clone, Copy)] pub struct SshdScript { @@ -142,7 +142,7 @@ pub struct SshdScript { pub stdout: &'static [u8], /// The channel data written as `extended_data(1)` stderr. pub stderr: &'static [u8], - /// The exit report after the outputs (`None` = none — the + /// The exit report after the outputs (`None` = none, the /// no-report rows). pub exit: Option, /// The `direct-tcpip` opens' behavior. @@ -154,7 +154,7 @@ pub struct SshdScript { /// The `streamlocal-forward` listen form's behavior (the unix /// `-R` rows). pub unix_listen: DblListen, - /// The counted refusal — the double declines the *first N* client + /// The counted refusal; the double declines the *first N* client /// session opens (per connection, armed by /// `accept_session_channels`): the stays-usable-after-a-decline /// rows' scripted shape (one connection, first open refused, the @@ -183,11 +183,11 @@ impl Default for SshdScript { } /// One recorded global-request listen/cancel form: (the request -/// name, the wire endpoint string, the wire port) — the reverse-listen +/// name, the wire endpoint string, the wire port); the reverse-listen /// rows assert the listens the client ops put on the wire. pub type ListenRecord = (&'static str, String, u32); -/// The double's per-connection observations — the wire rows assert +/// The double's per-connection observations; the wire rows assert /// the verbatim translations against these (what the client's op /// rows put on the wire). #[derive(Clone, Debug, Default)] @@ -201,11 +201,11 @@ pub struct SshdObserved { cancels: Arc>>, } -/// One recorded pty request's translated shapes — (term, cols, rows, +/// One recorded pty request's translated shapes: (term, cols, rows, /// pixel_width, pixel_height). pub type PtyRecord = (String, u32, u32, u32, u32); -/// One recorded window change's shapes — (cols, rows, pixel_width, +/// One recorded window change's shapes: (cols, rows, pixel_width, /// pixel_height). pub type WindowRecord = (u32, u32, u32, u32); @@ -234,13 +234,13 @@ impl SshdObserved { self.windows.lock().clone() } - /// The signals seen (russh's `Sig` debug names — "TERM", + /// The signals seen (russh's `Sig` debug names, "TERM", /// `Custom("..")`, …). pub fn signals(&self) -> Vec { self.signals.lock().clone() } - /// The global-request listen forms seen (name, endpoint, port — + /// The global-request listen forms seen (name, endpoint, port; /// the requested port, never the mint). pub fn listens(&self) -> Vec { self.listens.lock().clone() @@ -252,7 +252,7 @@ impl SshdObserved { } } -/// The double's scripted program serve — after a request's success +/// The double's scripted program serve, after a request's success /// reply: stdout, then `extended_data(1)` stderr, then the exit /// report, then the close (the vanilla sshd's exit-then-close /// discipline). @@ -292,7 +292,7 @@ async fn scripted_program(handle: Handle, channel_id: russh::ChannelId, script: let _ = handle.close(channel_id).await; } -/// The direct opens' echo pump — the accepted-typed-open shape's +/// The direct opens' echo pump, the accepted-typed-open shape's /// server half, POC-1 §7's byte round-trip. async fn direct_echo(mut stream: russh::ChannelStream) { use tokio::io::{AsyncReadExt, AsyncWriteExt}; @@ -311,9 +311,9 @@ async fn direct_echo(mut stream: russh::ChannelStream) { /// The `-R` accept loop per bound listener (the double's sshd role): /// per accepted connection a server-initiated `forwarded-*` open -/// toward the client — the connected address echoes the listen +/// toward the client; the connected address echoes the listen /// request's wire string verbatim, the port the actually-bound one, -/// the originator the accepted connection's peer — then the bytes +/// and the originator the accepted connection's peer; then the bytes /// pumped bidirectionally between the SSH channel and the accepted /// socket. A client-declined open closes that accepted connection /// (vanilla parity: the listener stays, the data has nowhere to go). @@ -347,7 +347,7 @@ async fn accept_forward_loop( } /// The accepted forward connection's pump (its SSH channel ↔ its -/// socket) — the data leg's byte plane. +/// socket), the data leg's byte plane. async fn forward_connection(channel: Channel, mut conn: tokio::net::TcpStream) { let mut stream = channel.into_stream(); let _ = tokio::io::copy_bidirectional(&mut stream, &mut conn).await; @@ -384,7 +384,7 @@ async fn unix_forward_connection(channel: Channel, mut conn: tokio::net::Un let _ = tokio::io::copy_bidirectional(&mut stream, &mut conn).await; } -/// The fake `sshd`'s per-connection handler — accept-set identity +/// The fake `sshd`'s per-connection handler: accept-set identity /// resolution, explicit rejects everywhere, the `auth_succeeded` /// handle carrier and the session-open acceptor stub. struct SshdDoubleHandler { @@ -397,7 +397,7 @@ struct SshdDoubleHandler { remaining_declines: std::sync::Arc, /// The `-R` bookkeeping (per-connection, sshd's listener table): /// the key is the cancel-form's match key (the wire endpoint + the - /// bound port — a `port = 0` mint's cancel matches the bound one), + /// bound port (a `port = 0` mint's cancel matches the bound one), /// the value the live accept loop (cancel aborts it, dropping the /// real listener with it). tcp_forwards: std::collections::HashMap<(String, u32), tokio::task::JoinHandle<()>>, @@ -425,7 +425,7 @@ impl russh::server::Handler for SshdDoubleHandler { } /// Explicit accept-and-delegate (the probe hook consumes no auth - /// attempt — POC-1 §4); the real disposition is + /// attempt, POC-1 §4); the real disposition is /// [`Self::auth_publickey`]'s. async fn auth_publickey_offered( &mut self, @@ -513,7 +513,7 @@ impl russh::server::Handler for SshdDoubleHandler { } /// The `direct-tcpip` script: reject (the scripted - /// server-refusal class, `ConnectFailed` — the vanilla sshd's + /// server-refusal class `ConnectFailed`, the vanilla sshd's /// dead-target shape) or accept + echo pump. async fn channel_open_direct_tcpip( &mut self, @@ -633,7 +633,7 @@ impl russh::server::Handler for SshdDoubleHandler { Ok(()) } - /// The `tcpip-forward` listen form: recorded, scripted — an accept + /// The `tcpip-forward` listen form: recorded and scripted; an accept /// binds a real `127.0.0.1` listener in sshd's role (a `port = 0` /// request's mint is the socket's real bound port, the out-param /// parity), keys the listener by (wire address, bound port), and @@ -675,7 +675,7 @@ impl russh::server::Handler for SshdDoubleHandler { /// The `cancel-tcpip-forward` form: matches by the raw wire /// strings (the bound port for a mint); a hit removes the - /// listener (tearing the real socket down — the cancel row's + /// listener (tearing the real socket down, the cancel row's /// observable), an unknown listener denies (sshd parity). async fn cancel_tcpip_forward( &mut self, @@ -700,7 +700,7 @@ impl russh::server::Handler for SshdDoubleHandler { /// scripts, binds the real unix socket (stale file unlinked /// first), and spawns the unix accept loop. Off-Unix the hook is /// not implemented and falls to the trait's deny default (the - /// vanilla Windows sshd parity) — the crate's own runtime-Unix + /// vanilla Windows sshd parity); the crate's own runtime-Unix /// gate mirrors the refusal client-side before the wire. #[cfg(unix)] async fn streamlocal_forward( @@ -729,7 +729,7 @@ impl russh::server::Handler for SshdDoubleHandler { } /// The `cancel-streamlocal-forward` form (matches by the path - /// alone — the unix cancel's sshd parity). + /// alone, the unix cancel's sshd parity). #[cfg(unix)] async fn cancel_streamlocal_forward( &mut self, @@ -753,8 +753,8 @@ impl russh::server::Handler for SshdDoubleHandler { impl SshdDoubleHandler { /// The scripted request reply: success launches the scripted - /// program through the session's handle (spawned — the packet - /// loop returns fast) *when a program is scripted at all* — an + /// program through the session's handle (spawned, so the packet + /// loop returns fast) *when a program is scripted at all*; an /// output-less/no-exit script launches nothing (the interactive /// sessions stay open; close is the client's or the connection's); /// the failure class answers `channel_failure`. @@ -775,7 +775,7 @@ impl SshdDoubleHandler { } } -/// The fake `sshd`'s accepted-identity register — exact-string +/// The fake `sshd`'s accepted-identity register, exact-string /// fingerprints (the row registers the fixture dials with). pub struct SshdAccepts { inner: Arc>>, @@ -789,9 +789,9 @@ impl SshdAccepts { } } -/// One spawned fake `sshd` — the client-direction contract vehicle. +/// One spawned fake `sshd`, the client-direction contract vehicle. pub struct SshdDouble { - /// The dial target, `:` — the row's + /// The dial target, `:`, the row's /// `DialConfig.address` value. pub address: String, session_carrier: Option>, @@ -806,7 +806,7 @@ pub struct SshdDouble { /// `host_keys` rides the `russh::server::Config`; /// `accept_session_channels` arms the session-open acceptor stub. /// Returns the double, its accept-set register (register before -/// dialing — the wire's auth reads it at the dial), and the +/// dialing, since the wire's auth reads it at the dial), and the /// observation surface (see [`SshdObserved`]). pub async fn spawn_scripted( host_keys: Vec, @@ -884,7 +884,7 @@ pub async fn spawn_scripted( } /// Spawns the double on `127.0.0.1:0` with the plain dial rows' -/// default script — the `w4-dial` shape, kept: the double and its +/// default script, the `w4-dial` shape kept: the double and its /// accept-set register. pub async fn spawn( host_keys: Vec, @@ -896,7 +896,7 @@ pub async fn spawn( } impl SshdDouble { - /// The dialed session's server-side handle — the initiator for + /// The dialed session's server-side handle, the initiator for /// the server-initiated-open rows. Awaits the `auth_succeeded` /// carrier; the dial has authenticated by the time a row calls /// this (the carrier's sender only fires inside the double's @@ -912,13 +912,13 @@ impl SshdDouble { } /// The client-initiated session channels the acceptor stub - /// accepted — `None` after the session's end (the observation + /// accepted; `None` after the session's end (the observation /// shape's honest empty). pub async fn next_opened_session(&mut self) -> Option> { self.opened_sessions.recv().await } - /// The next per-connection serving outcome — the clean-close + /// The next per-connection serving outcome, the clean-close /// rows' observable (a clean `Disconnect::ByApplication` is the /// sessions' `Ok`; an abrupt peer close is an `Err` wire class). /// `None` after the double's loop ends. diff --git a/tests/common/tty_doubles.rs b/tests/common/tty_doubles.rs index 8457e1a..25b0e94 100644 --- a/tests/common/tty_doubles.rs +++ b/tests/common/tty_doubles.rs @@ -1,17 +1,17 @@ //! The `session`-seam test doubles (`w3-tty-session`): the alkssh-side -//! **TtyBackend shim double** — alktty's `MockBackend`/`testing.rs` are +//! **TtyBackend shim double**: alktty's `MockBackend`/`testing.rs` are //! `pub(crate)` + `cfg(test)` and never importable, so the suite //! hand-rolls the shim per the `TtyHandle` field shapes: a backend //! that records the `TtyParams` it was allocated, consumes stdin //! (recording bytes, the EOF shutdown and the abort kill), emits //! scripted stdout/stderr chunks and a scripted exit code, and //! surfaces a control handle recording resizes/signals. Plus the -//! ownership witness double — the identity that reaches +//! and the ownership witness double: the identity that reaches //! `drive_session_pre_negotiated`'s ADR-050 ownership check is the //! identity ride's live witness (the task's "identity-landing item"). //! //! Every stream/future here is test-scripted and instantly-completed -//! or never-completing — no real process, no real PTY (the real-tool +//! or never-completing; no real process, no real PTY (the real-tool //! smoke composes alktty's own `local` backend instead, dev-dep only). use std::collections::HashMap; @@ -28,7 +28,7 @@ use bytes::Bytes; use tokio::io::AsyncWrite; use tokio_stream::wrappers::ReceiverStream; -/// The shim's shared observation surface — every row's assertions +/// The shim's shared observation surface; every row's assertions /// come off this (`Record TtyParams`, consume stdin/EOF/resizes/ /// signals, the abort kill witness). #[derive(Debug, Default)] @@ -38,20 +38,20 @@ pub struct TtyShimObservation { /// Bytes written to the shim's stdin, concatenated per allocation. pub stdin: parking_lot::Mutex>, /// Whether a stdin shutdown (the EOF translation's destination) - /// was observed — one flag per shutdown, but one allocation per - /// row in practice. + /// was observed (one flag per shutdown, but one allocation per + /// row in practice). pub stdin_eof: parking_lot::Mutex>, /// Resizes from the control handle (`cols`, `rows`). pub resizes: parking_lot::Mutex>, - /// Signals from the control handle — the name strings, verbatim. + /// Signals from the control handle, the name strings verbatim. pub signals: parking_lot::Mutex>, /// The abort kill witness: pushed once per `exit_code` future - /// dropped *unresolved* — alktty's kill-on-drop contract + /// dropped *unresolved*; alktty's kill-on-drop contract /// (ADR-056) observed through the shim. pub kills: Arc>>, } -/// The shim's scripted per-allocation behavior — what the shim emits +/// The shim's scripted per-allocation behavior: what the shim emits /// and what exit code it resolves with. #[derive(Debug, Clone, Default)] pub struct ShimScript { @@ -66,7 +66,7 @@ pub struct ShimScript { pub exit: Option, } -/// The TtyBackend shim double — a hand-rolled minimal backend per the +/// The TtyBackend shim double, a hand-rolled minimal backend per the /// `TtyHandle` field shapes (see the module doc). Clone-able (the /// observation + script are `Arc`s). #[derive(Clone, Default)] @@ -133,7 +133,7 @@ impl TtyBackend for TtyShim { }) } - /// The ADR-050 check input — every allocation targets this shim + /// The ADR-050 check input (every allocation targets this shim /// resource, so the ownership witness row (the identity surface) /// always evaluates. fn resource_id(&self, _params: &TtyParams) -> Option<(&'static str, String)> { @@ -143,7 +143,7 @@ impl TtyBackend for TtyShim { impl ShimScript { /// Whether the allocation is PTY-mode (the TtyParams's terminal is - /// not the NegotiateRequest.tty this module speaks — the adapter's + /// not the NegotiateRequest.tty this module speaks; the adapter's /// `From` conversion is what the seam consumes; /// the shim sees the converted `TtyParams`). fn terminal_is_pty(&self, params: &TtyParams) -> bool { @@ -151,9 +151,9 @@ impl ShimScript { } } -/// A scripted stream — the chunks in order, then end. Instantly -/// drained (the alktty pumps consume; the exit chunk arrives after — -/// the adapter's exit-chunk-is-last invariant orders everything). +/// A scripted stream: the chunks in order, then end. Instantly +/// drained (the alktty pumps consume; the exit chunk arrives after, +/// since the adapter's exit-chunk-is-last invariant orders everything). fn scripted_stream(chunks: &[Vec]) -> Pin + Send>> { let (tx, rx) = tokio::sync::mpsc::channel(chunks.len().max(1) + 1); for chunk in chunks { @@ -163,7 +163,7 @@ fn scripted_stream(chunks: &[Vec]) -> Pin, } @@ -255,7 +255,7 @@ impl TtyControl for ShimControl { } /// A shim-backed `SessionSeam` in the `session`-seam shape the -/// adapters take — `backends` map holds the shim under `"shim"`, the +/// adapters take: the `backends` map holds the shim under `"shim"`, the /// selector names it, ownership unset (the ADR-050 check skips). pub fn tty_seam(shim: &Arc) -> alkssh::SessionSeam { let mut backends = HashMap::new(); @@ -270,12 +270,12 @@ pub fn tty_seam(shim: &Arc) -> alkssh::SessionSeam { /// The ownership witness double ([`alkcall::core::ownership:: /// OwnershipProvider`]): records every identity evaluation and rules /// by its configured verdict (the deny shape produces the negotiation -/// error frame on the wire — the bridge's `negotiation-failed` +/// error frame on the wire, the bridge's `negotiation-failed` /// decline). #[derive(Debug)] pub struct MemOwnership { pub owns: bool, - /// The identity ids that reached `owns` — the identity ride's + /// The identity ids that reached `owns`, the identity ride's /// live witness. pub ids: parking_lot::Mutex>, } @@ -310,7 +310,7 @@ impl OwnershipProvider for MemOwnership { } } -/// A shim-backed seam with the ownership provider present — the +/// A shim-backed seam with the ownership provider present, the /// witness rows' builder. pub fn tty_seam_with_ownership( shim: &Arc, @@ -325,7 +325,7 @@ pub fn tty_seam_with_ownership( } } -/// A seam whose selector names no backend in its own map — the +/// A seam whose selector names no backend in its own map; it renders the /// `unknown_backend` negotiation error frame, driven from config. pub fn misconfigured_seam() -> alkssh::SessionSeam { alkssh::SessionSeam { diff --git a/tests/dispatch_core.rs b/tests/dispatch_core.rs index 65b1417..ceec076 100644 --- a/tests/dispatch_core.rs +++ b/tests/dispatch_core.rs @@ -1,5 +1,5 @@ //! The wave-2 dispatch/decline-core contract tests -//! (`w2-dispatch-decline-core`) — the skeleton rows of the decline +//! (`w2-dispatch-decline-core`): the skeleton rows of the decline //! matrix (`mapping.md` §Decline matrix), driven per feature build //! through the loopback harness. This task tests the rows it lands; //! the full per-build matrix suite is wave-5's. @@ -32,7 +32,7 @@ use russh::{Channel, ChannelOpenFailure, Error}; use alkssh::Limits; -/// Mounts an authenticated loopback session over the doubles — the +/// Mounts an authenticated loopback session over the doubles, the /// dispatch rows' driver: fixture `alpha` resolves through /// `MemIdentityProvider`, host keys `bravo`, the permissive host-key /// posture (the explicit test choice). @@ -58,7 +58,7 @@ async fn authenticated() -> LoopbackSession { session } -/// Matches an open failure's SSH reason — the wire decline reason the +/// Matches an open failure's SSH reason, the wire decline reason the /// open-gate rows assert. fn open_failure(err: Error, expected: ChannelOpenFailure, context: &str) { assert!( @@ -71,7 +71,7 @@ fn open_failure(err: Error, expected: ChannelOpenFailure, context: &str) { } /// The request-level decline observation: the channel answers Failure. -/// A capability decline's channel stays open afterwards — the POC-1 §5 +/// A capability decline's channel stays open afterwards, the POC-1 §5 /// session-survives-declines posture the channel-alive rows lean on. async fn expect_failure(channel: &mut Channel, context: &str) { match next_message(channel).await { @@ -81,7 +81,7 @@ async fn expect_failure(channel: &mut Channel, context: &str) { } /// The serving-path (family-seam stub) decline observation: Failure -/// then Close — the vanilla-clean shape for a row whose serving path +/// then Close, the vanilla-clean shape for a row whose serving path /// would own the channel. async fn expect_failure_then_close(channel: &mut Channel, context: &str) { expect_failure(channel, context).await; @@ -91,7 +91,7 @@ async fn expect_failure_then_close(channel: &mut Channel, context: &str) { ); } -/// Proves a declined channel is still usable — a follow-up request +/// Proves a declined channel is still usable: a follow-up request /// reaches the dispatch again instead of the channel being dead. async fn expect_channel_alive(channel: &mut Channel) { common::harness::request_subsystem(channel, "sftp") @@ -101,10 +101,10 @@ async fn expect_channel_alive(channel: &mut Channel) { } // --------------------------------------------------------------------------- -// Shared rows — run in every feature build. +// Shared rows; run in every feature build. // --------------------------------------------------------------------------- -/// - *Contract stamp:* ADR-003 §5 (x11 is a never-feature — declined +/// - *Contract stamp:* ADR-003 §5 (x11 is a never-feature, declined /// in every build, never feature-gated). #[tokio::test] async fn x11_channel_opens_decline_in_every_build() { @@ -122,7 +122,7 @@ async fn x11_channel_opens_decline_in_every_build() { /// - *Contract stamp:* mapping.md §Global-request rows (the `-R` /// listen flow is a `tunnel` row declined when the flow cannot -/// serve — this wave: every build). +/// serve; this wave: every build). #[tokio::test] async fn tcpip_forward_listen_requests_decline_in_every_build() { let session = authenticated().await; @@ -139,7 +139,7 @@ async fn tcpip_forward_listen_requests_decline_in_every_build() { /// - *Contract stamp:* mapping.md §Global-request rows (the /// `streamlocal-forward` unix listen form is the `tunnel` row's /// other half: unfeatured builds decline before any fabric call, -/// a `tunnel` build declines on the unset listen seam — the same +/// a `tunnel` build declines on the unset listen seam; the same /// refused-global-request wire shape both ways). #[tokio::test] async fn streamlocal_forward_listen_requests_decline_in_every_build() { @@ -155,10 +155,10 @@ async fn streamlocal_forward_listen_requests_decline_in_every_build() { } /// - *Contract stamp:* mapping.md §Global-request rows (the cancel -/// forms: `false` for an unknown pair — the sshd not-found parity; +/// forms: `false` for an unknown pair (the sshd not-found parity); /// unfeatured builds decline their gate before reaching the -/// listener map, a `tunnel` build's empty map misses the pair — -/// the same refused-cancel wire shape both ways). +/// listener map, a `tunnel` build's empty map misses the pair; the +/// same refused-cancel wire shape both ways). #[tokio::test] async fn global_request_cancels_refuse_unknown_pairs_in_every_build() { let session = authenticated().await; @@ -206,7 +206,7 @@ async fn x11_and_agent_requests_decline_wherever_sessions_open() { // --------------------------------------------------------------------------- // Default build (no features): everything declines (mapping.md -// §Decline matrix — "none (default): declines everything"). +// §Decline matrix, "none (default): declines everything"). // --------------------------------------------------------------------------- #[cfg(not(any(feature = "session", feature = "git", feature = "tunnel")))] @@ -215,8 +215,8 @@ mod default_build { use common::harness::{open_direct_streamlocal, open_direct_tcpip}; /// - *Contract stamp:* mapping.md §Decline matrix (none-build - /// row: every channel type declines at open — session channels - /// as unfeatured, tunnel rows as unfeatured — plus the + /// row: every channel type declines at open (session channels + /// as unfeatured, tunnel rows as unfeatured) plus the /// never-feature x11). #[tokio::test] async fn every_channel_open_declines_in_a_default_build() { @@ -255,9 +255,9 @@ mod default_build { // --------------------------------------------------------------------------- // git-only build: routes git-parseable exec to the git row; declines -// pty/shell, plain exec, all other opens (mapping.md §Decline matrix — +// pty/shell, plain exec, all other opens (mapping.md §Decline matrix, // git row). The harness builds no seam, so the git row's decline is -// the config-driven one (`w3-git-mapping`: seam-unconfigured — the +// the config-driven one (`w3-git-mapping`: seam-unconfigured, the // unset-declines contract, serving-path shape); the serving rows ride // `tests/git_mapping.rs`. // --------------------------------------------------------------------------- @@ -271,7 +271,7 @@ mod git_build { }; /// - *Contract stamp:* the task's channel-open gate (session - /// channels open where a session-serving feature exists — `git` + /// channels open where a session-serving feature exists; `git` /// qualifies, the parse path lives inside session channels). #[tokio::test] async fn session_channels_open_in_a_git_build() { @@ -284,8 +284,8 @@ mod git_build { /// - *Contract stamp:* ADR-006 point 3 (parse-only: a /// git-parseable exec routes to the git row; this build - /// configures no seam, so the row declines at its config gate — - /// the serving-path shape, failure then close). The row's + /// configures no seam, so the row declines at its config gate, + /// the serving-path shape: failure then close). The row's /// serving surface (seam configured, real dispatch) is /// `tests/git_mapping.rs`'s. #[tokio::test] @@ -312,7 +312,7 @@ mod git_build { /// - *Contract stamp:* mapping.md §Decline matrix (git-build row: /// plain exec declines; the parse-then-fail shape of POC-3 - /// stage A — the channel survives the decline). + /// stage A; the channel survives the decline). #[tokio::test] async fn plain_exec_declines_and_keeps_the_channel_in_a_git_build() { let session = authenticated().await; @@ -328,7 +328,7 @@ mod git_build { } /// - *Contract stamp:* POC-3 §2 (unknown git services take the - /// agreed declined surface — `w3-git-mapping`'s decided class, + /// agreed declined surface (`w3-git-mapping`'s decided class, /// off the pipe row: `ExecRoute::Declined`, build-independent; /// the reply vocabulary is shared with parse-then-fail: failure, /// channel alive). @@ -353,7 +353,7 @@ mod git_build { } /// - *Contract stamp:* mapping.md §Decline matrix (git-build row: - /// pty/shell and all session requests decline — the pty row + /// pty/shell and all session requests decline; the pty row /// declines unfeatured (`channel_failure`, the channel alive) /// exactly as the shell row does). #[tokio::test] @@ -383,7 +383,7 @@ mod git_build { /// - *Contract stamp:* mapping.md §Request-level rows (subsystem: /// `sftp` is the OQ-13 placeholder decline; git service names - /// carry no repository id — ADR-006 decision 2). + /// carry no repository id; ADR-006 decision 2). #[tokio::test] async fn subsystems_decline_with_their_named_reasons_in_a_git_build() { let session = authenticated().await; @@ -405,7 +405,7 @@ mod git_build { } /// - *Contract stamp:* OQ-09 (mapping.md §Request-level rows: - /// `env_request` declines unconditionally — no allowlist ships). + /// `env_request` declines unconditionally; no allowlist ships). #[tokio::test] async fn env_requests_decline_in_a_git_build() { let session = authenticated().await; @@ -421,7 +421,7 @@ mod git_build { } /// - *Contract stamp:* mapping.md §Decline matrix (git-build - /// row: all other channel types decline — tunnel unfeatured). + /// row: all other channel types decline, tunnel unfeatured). #[tokio::test] async fn tunnel_opens_decline_unfeatured_in_a_git_build() { let session = authenticated().await; @@ -453,7 +453,7 @@ mod git_build { // its gate); with no seam/config this build's session rows decline at // their config gates (the unset-declines contract, serving-path // shape: `w3-tty-session`); declines tunnel opens (mapping.md -// §Decline matrix — session row). +// §Decline matrix, session row). // --------------------------------------------------------------------------- #[cfg(all(feature = "session", not(feature = "git"), not(feature = "tunnel")))] @@ -476,7 +476,7 @@ mod session_build { } /// - *Contract stamp:* mapping.md §Decline matrix (session row: - /// git-parseable exec declines — the `git` parse is its gate; + /// git-parseable exec declines; the `git` parse is its gate; /// the channel survives the decline, POC-1 §5). #[tokio::test] async fn git_parseable_exec_declines_in_a_session_build() { @@ -498,7 +498,7 @@ mod session_build { /// - *Contract stamp:* OQ-08 + the recorded wire shape /// (`w3-tty-session`: `exec_wrapper_argv` unset → the pipe row - /// declines — the serving-path shape, failure then close, never + /// declines (the serving-path shape, failure then close, never /// a fallback). The row's serving surface (everything /// configured) is `tests/tty_mapping.rs`'s. #[tokio::test] @@ -581,7 +581,7 @@ mod session_build { } /// - *Contract stamp:* mapping.md §Decline matrix (session row: - /// other channel types decline — tunnel unfeatured). + /// other channel types decline, tunnel unfeatured). #[tokio::test] async fn tunnel_opens_decline_unfeatured_in_a_session_build() { let session = authenticated().await; @@ -612,8 +612,8 @@ mod session_build { // tunnel-only build: session channels decline (auto-reject); the // tunnel direct rows decline on the **absent handle** even with the // feature on (the route-1 bridge is `w3-tunnel-direct`: the pre-admit -// unset-handle class — the unset-declines posture; the fabric double's -// serve/cap/fabric-failure rows ride tests/tunnel_mapping.rs) — +// unset-handle class, the unset-declines posture; the fabric double's +// serve/cap/fabric-failure rows ride tests/tunnel_mapping.rs) per // mapping.md §Decline matrix (tunnel row). // --------------------------------------------------------------------------- @@ -624,7 +624,7 @@ mod tunnel_build { /// - *Contract stamp:* ADR-006 point 3 as amended (parse-only /// dispatch: a request-less/deserving-less session channel - /// declines as unfeatured — a tunnel-only build has no + /// declines as unfeatured; a tunnel-only build has no /// session-serving feature, so the open declines). #[tokio::test] async fn session_channels_decline_in_a_tunnel_build() { @@ -641,9 +641,9 @@ mod tunnel_build { } /// - *Contract stamp:* mapping.md §Channel-type rows + the - /// unset-declines posture (`w3-seam-config` — the feature alone + /// unset-declines posture (`w3-seam-config`, the feature alone /// configures nothing): the direct rows decline on the **absent - /// fabric handle** even with `tunnel` on — + /// fabric handle** even with `tunnel` on: /// [`connect failed`], the cannot-bridge class ADR-006 decision /// 1 pins (`w3-tunnel-direct`'s recorded wire classes: policy /// refusals are administratively-prohibited, cannot-bridge is @@ -675,8 +675,8 @@ mod tunnel_build { } // --------------------------------------------------------------------------- -// All features: the routing decisions hold with the full graph on — -// the git row is still its config-driven decline in this binary (the +// All features: the routing decisions hold with the full graph on; the +// git row is still its config-driven decline in this binary (the // serving rows ride tests/git_mapping.rs), and the session rows are // still their config-driven declines (the serving rows ride // tests/tty_mapping.rs). @@ -706,7 +706,7 @@ mod all_features { } /// - *Contract stamp:* OQ-08 + the recorded wire shape (the - /// unset-wrapper pipe row declines — the serving-path shape; + /// unset-wrapper pipe row declines, the serving-path shape; /// `w3-tty-session`). The serving surface rides /// `tests/tty_mapping.rs`. #[tokio::test] @@ -723,7 +723,7 @@ mod all_features { } /// - *Contract stamp:* mapping.md §Channel-type rows + OQ-08 (the - /// unset-seam pty/shell declines with the full graph on — the + /// unset-seam pty/shell declines with the full graph on, since the /// feature alone configures nothing; the serving surface rides /// `tests/tty_mapping.rs`). #[tokio::test] @@ -751,7 +751,7 @@ mod all_features { /// - *Contract stamp:* the unset-declines posture (`w3-seam-config`, /// carried through `w3-tunnel-direct`: the route-1 bridge's - /// pre-admit unset-handle class) — the direct rows decline on + /// pre-admit unset-handle class): the direct rows decline on /// the **absent fabric handle** even with the full feature graph /// on (`ConnectFailed`, the cannot-bridge class); the served /// surface rides tests/tunnel_mapping.rs's fabric double. @@ -781,8 +781,8 @@ mod all_features { } /// - *Contract stamp:* mapping.md §Request-level rows (the - /// capability declines — sftp placeholder, git subsystem - /// names, env — hold with everything on). + /// capability declines (sftp placeholder, git subsystem + /// names, env) hold with everything on). #[tokio::test] async fn capability_declines_hold_with_all_features() { let session = authenticated().await; diff --git a/tests/doubles.rs b/tests/doubles.rs index 2ad989e..1738270 100644 --- a/tests/doubles.rs +++ b/tests/doubles.rs @@ -1,4 +1,4 @@ -//! The wave-1 doubles' end-to-end rows — the seams exercised through +//! The wave-1 doubles' end-to-end rows: the seams exercised through //! the doubles exactly as the later waves' contract tests will run //! against them: fingerprint registration resolution, the vault //! custody round-trip and its failure postures, and the host-key @@ -26,7 +26,7 @@ use common::{FIXTURE_KEYS, MemHostKeyPolicy, MemIdentityProvider, TestVault, fix /// - *Contract stamp:* ADR-004 decision 1 (fingerprint → /// `resolve_from_fingerprint` → `Some` = accept; `None` = reject). /// - *Contract stamp:* ADR-005 context (client fingerprints never -/// involve the vault — the `IdentityProvider` path only). +/// involve the vault (the `IdentityProvider` path only). #[test] fn mem_identity_provider_registered_fingerprint_resolves() { let alpha = fixture("alpha"); @@ -51,7 +51,7 @@ fn mem_identity_provider_registered_fingerprint_resolves() { ); } -/// A revocation makes the fingerprint resolve `None` again — the +/// A revocation makes the fingerprint resolve `None` again; the /// resolution set is inspectable and mutable. /// /// - *Contract stamp:* ADR-004 decision 1 (`None` → reject is the @@ -74,7 +74,7 @@ fn mem_identity_provider_revocation_resolves_none() { assert!(provider.registered_fingerprints().is_empty()); } -/// The token path resolves nothing on the SSH surface — the double +/// The token path resolves nothing on the SSH surface; the double /// never invents a token shape. /// /// - *Contract stamp:* ADR-004 decision 1 (the fingerprint is the @@ -89,8 +89,8 @@ fn mem_identity_provider_token_path_resolves_none() { assert!(provider.resolve_from_token(&token).is_none()); } -/// Every fixture key's fingerprint — whether derived via the private -/// PEM or the committed public blob — equals its `ssh-keygen -lf` +/// Every fixture key's fingerprint, whether derived via the private +/// PEM or the committed public blob, equals its `ssh-keygen -lf` /// recorded value. This row keeps the fixture set honest for every /// consumer; `tests/fingerprint_parity.rs` is the deep parity check. /// @@ -144,7 +144,7 @@ async fn test_vault_seal_then_key_source_decode_round_trips() { /// The POC-2 §3 failure postures ride the real seams: locked vault → /// `Locked`, absent record → `Absent`, tampered ciphertext → -/// `Decryption` — each a distinct variant, each a refusal, no +/// `Decryption`; each a distinct variant, each a refusal, no /// fallback key shape. /// /// - *Contract stamp:* ADR-005 decision 4 (failure modes fail closed @@ -181,7 +181,7 @@ async fn test_vault_postures_refuse_fail_closed_through_the_source() { assert!(matches!(err, KeySourceError::Decryption(_)), "got {err:?}"); } -/// The host-key set loads from the vault seam in registration order — +/// The host-key set loads from the vault seam in registration order: /// one custody model, both directions (the decrypt-at-construction /// load path). /// @@ -215,10 +215,10 @@ async fn host_key_source_set_loads_from_the_vault_seam_in_order() { /// The policy double's verdicts are honored and its decision log is /// the inspectable record: pinned exact `(host, fingerprint)` pairs -/// accept, unmatched pairs fall to the default (reject — fail-closed), +/// accept, unmatched pairs fall to the default (reject, fail-closed), /// and every decision is logged with the full presented context. /// -/// - *Contract stamp:* OQ-05 resolution (`host_key.rs` module docs — +/// - *Contract stamp:* OQ-05 resolution (`host_key.rs` module docs: /// the crate is policy-blind; verdicts are the policy's). /// - *Contract stamp:* ADR-005 decision 6 (the host *pin* is public /// config; exact-string comparison by contract). @@ -263,10 +263,10 @@ async fn mem_host_key_policy_verdicts_are_recorded_and_honored() { } /// A permissive default is the test's explicit choice (never a -/// default), and an explicit rule overrides it — the case-2 +/// default), and an explicit rule overrides it; the case-2 /// ephemeral-fleet shape versus a pin-style correction. /// -/// - *Contract stamp:* OQ-05 resolution (`host_key.rs` — there is no +/// - *Contract stamp:* OQ-05 resolution (`host_key.rs`; there is no /// accept-all built-in crate option; case-2 policies are the /// assembly's to write). /// - *Contract stamp:* ADR-004 decision 6 posture analog diff --git a/tests/e2e_client.rs b/tests/e2e_client.rs index fa17dbc..828231c 100644 --- a/tests/e2e_client.rs +++ b/tests/e2e_client.rs @@ -1,4 +1,4 @@ -//! The client-direction real-tool e2e (`w5-e2e-client`) — the +//! The client-direction real-tool e2e (`w5-e2e-client`): the //! reverse-runner shape re-landed against a **real `sshd`** //! (`docs/plans/implementation.md` §Wave 5, the real-tool e2e bullet's //! client half). The wave-4 client rows ran against the in-process @@ -8,24 +8,24 @@ //! (exit-status parity through a real server's reaping), the //! direct-tcpip dial (`-L`-shaped), the `-R` leg (the port-0 mint //! against a real server's actually-bound reply, the server-initiated -//! `forwarded-tcpip` open served through the acceptor registry — the -//! reverse-runner consumer pattern end to end), the cancel form +//! `forwarded-tcpip` open served through the acceptor registry (the +//! reverse-runner consumer pattern end to end), the cancel form the cancel form //! tearing the real listen down, and the decline rows (the sftp //! client-side placeholder decline, the server-refused direct-tcpip //! open with the connection staying usable, the host-key policy -//! mismatch hard-decline — the case-1 pin posture against a real +//! mismatch hard-decline, the case-1 pin posture against a real //! presented key). //! //! **Placement decision (recorded, the task's acceptance criterion //! 1):** a dedicated `tests/e2e_client.rs` binary reusing -//! `tests/common` — the wave-4 client binaries (`tests/client_dial.rs` +//! `tests/common`, so the wave-4 client binaries (`tests/client_dial.rs` //! / `client_ops.rs` / `client_reverse_listen.rs`) keep their //! single-writer posture for `w5-decline-matrix`; this binary owns //! only its own rows and its in-file `support` fixture module, //! disjoint from `tests/e2e_server.rs` (the matrix task's binaries). //! //! **The sshd fixture shape (decided + recorded):** a **per-row -//! spawned** real `sshd` — each row's config knobs differ +//! spawned** real `sshd`; each row's config knobs differ //! (`AllowTcpForwarding` yes/no) and each row dials its own server, //! so a shared per-binary instance buys nothing: per-row isolation //! (own workdir, own minted ed25519 host key, own probed port) beats @@ -39,7 +39,7 @@ //! dialed port; a server that never comes up (binary absent, //! `ssh-keygen` absent, spawn refused, privilege-separation directory //! missing, config refused) is the row's **reasoned skip** with the -//! server's own `-e` log as the reason — never silently green. The +//! server's own `-e` log as the reason, never silently green. The //! dial rides the decrypt-at-dial path over the in-memory vault //! double (`VaultKeySource` over `TestVault`, fixture `alpha` sealed), //! and the case-1 pin posture (`MemHostKeyPolicy::pin`) accepts only @@ -48,7 +48,7 @@ //! Rows are `#[cfg(unix)]` (the fixture spawns processes) and //! feature-gated per row group under the established check-gated //! **skipped-with-reason** posture. Every real-tool interaction is -//! deadline-bounded — a decline must surface a typed value to the +//! deadline-bounded (a decline must surface a typed value to the //! dialer, never a hang. Rows carry `Contract stamp:` doc markers //! against `client.md` / `reverse-runner.md` (the greppable //! `tests/common` discipline). @@ -69,12 +69,12 @@ mod support { use super::common::{MemHostKeyPolicy, TestVault, fixture}; - /// One shared row deadline — every real-process interaction is + /// One shared row deadline; every real-process interaction is /// bounded (the POC-1 §5 posture: a decline never hangs). pub const ROW_DEADLINE: Duration = Duration::from_secs(30); - /// The sshd candidates probed in order (`sbin` paths first — the - /// server binary rarely sits on the user's `PATH`). + /// The sshd candidates probed in order (`sbin` paths first, since + /// the server binary rarely sits on the user's `PATH`). const SSHD_CANDIDATES: &[&str] = &[ "/usr/sbin/sshd", "/usr/local/sbin/sshd", @@ -84,10 +84,10 @@ mod support { /// Prints the row's reasoned skip (never silently green). pub fn skip(row: &str, reason: &str) { - eprintln!("SKIPPED (with reason): {row} — {reason}"); + eprintln!("SKIPPED (with reason): {row}: {reason}"); } - /// The `sshd` binary's location — probed once, `None` when the + /// The `sshd` binary's location, probed once; `None` when the /// environment carries no server (every row's reasoned skip). pub fn sshd_binary() -> Option { SSHD_CANDIDATES @@ -102,7 +102,7 @@ mod support { Command::new("ssh-keygen").arg("-h").output().is_ok() } - /// The per-row fixture workdir — a throwaway directory under the + /// The per-row fixture workdir, a throwaway directory under the /// temp dir, one per row (the wave-5 e2e-server lesson: no shared /// workdirs, no cross-row races). fn workdir(row: &str) -> PathBuf { @@ -113,7 +113,7 @@ mod support { } /// Mints one ed25519 host key into the workdir (the independent - /// issuer) and returns its recorded fingerprint — byte-verbatim + /// issuer) and returns its recorded fingerprint (byte-verbatim /// from `ssh-keygen -lf`, the same `SHA256:` format the /// fingerprint parity contract pins (the policy's pin comparison /// is exact string equality by contract). @@ -127,7 +127,7 @@ mod support { .expect("ssh-keygen spawns"); assert!( minted.status.success(), - "the host key mints — stderr: {}", + "the host key mints; stderr: {}", String::from_utf8_lossy(&minted.stderr) ); let listed = Command::new("ssh-keygen") @@ -145,7 +145,7 @@ mod support { /// The in-process port allocator for the rows' named binds (the /// e2e-server posture verbatim: a monotonic counter over a window /// below the kernel's ephemeral range, probe-verified per - /// allocation — parallel rows never collide). + /// allocation; parallel rows never collide). pub async fn pick_port() -> u16 { static NEXT: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(2000); loop { @@ -161,7 +161,7 @@ mod support { } } - /// The spawned real `sshd` — the per-row fixture (the shape + /// The spawned real `sshd`, the per-row fixture (the shape /// recorded in the module docs). The dial rides the /// decrypt-at-dial path over the in-memory vault double; the /// case-1 pinned policy accepts exactly the minted host key. @@ -175,7 +175,7 @@ mod support { impl SshdFixture { /// A fixture dialing publickey-only with TCP forwarding - /// enabled (`AllowTcpForwarding yes`) — the op rows' server. + /// enabled (`AllowTcpForwarding yes`), the op rows' server. pub async fn spawn(row: &str) -> Result { Self::spawn_with(row, true).await } @@ -301,7 +301,7 @@ mod support { format!("127.0.0.1:{}", self.port) } - /// The case-1 pinned policy — accepts exactly this fixture's + /// The case-1 pinned policy; it accepts exactly this fixture's /// minted host fingerprint at `127.0.0.1` (the pin posture /// consumed against a real presented key). A `Some` pin /// substitutes another fixture's fingerprint (the mismatch @@ -316,7 +316,7 @@ mod support { } /// The authenticated dial over the fixture under the given - /// policy — the decrypt-at-dial path (fixture `alpha` sealed + /// policy, the decrypt-at-dial path (fixture `alpha` sealed /// into the in-memory vault, decrypted and loaded exactly at /// the dial), deadline-bounded. pub async fn dial_from( @@ -339,7 +339,7 @@ mod support { .expect("the dial completes within the row deadline") } - /// The dial the op rows use — pinned to the fixture's own + /// The dial the op rows use, pinned to the fixture's own /// key, so the authenticated connection is the expected `Ok`. pub async fn dial_default(&self) -> SshConnection { self.dial_from(self.policy(None)) @@ -356,7 +356,7 @@ mod support { } } - /// The server's captured `-e` diagnostics — the skip reason's raw + /// The server's captured `-e` diagnostics, the skip reason's raw /// input, tail-truncated (best effort; a missing log is no text). fn log_tail(log: &Path) -> String { let Ok(mut file) = std::fs::File::open(log) else { @@ -375,7 +375,7 @@ mod support { .join(" | ") } - /// A tiny TCP echo server — the direct-tcpip row's real `-L` + /// A tiny TCP echo server, the direct-tcpip row's real `-L` /// target (the bytes round trip through the server-side bridge /// and this server, exactly the `-L` topology). pub async fn spawn_echo_server() -> u16 { @@ -421,7 +421,7 @@ mod support { } /// The exec row (the `session` build): the family-typed exec through -/// a real server — stdout rides `data`, stderr rides +/// a real server: stdout rides `data`, stderr rides /// `extended_data(1)`, the exit status rides in-band last, and the /// server's reaping reports the program's real exit code (a nonzero /// exit proves the parity is the server's, not a canned 0). @@ -434,7 +434,7 @@ mod exec_row { use super::support; - /// Drains the session's chunk plane until the exit chunk — + /// Drains the session's chunk plane until the exit chunk; /// returns (stdout, stderr, the exit code in-band, if any). The /// deadline bounds a wrong row instead of hanging it. async fn read_to_exit(mut session: alkssh::RemoteSession) -> (Vec, Vec, Option) { @@ -466,12 +466,12 @@ mod exec_row { } /// - *Contract stamp:* `client.md` §op rows (row 1, the exec - /// parity) + §The dial surface — the wave-4 double-driven exec + /// parity) + §The dial surface; the wave-4 double-driven exec /// row re-landed against a real `sshd`: the family-typed op /// (`exec()`, the command verbatim) through the real server's - /// own session reaping — stdout separated from stderr, the + /// own session reaping: stdout separated from stderr, the /// real exit status reported in-band last (`exit-status(3)`, - /// parity — not a canned 0), and the case-1 pinned policy's + /// parity, not a canned 0), and the case-1 pinned policy's /// accept decision on record against the really-presented key. #[tokio::test] async fn real_sshd_exec_pumps_streams_and_reports_the_exit_status() { @@ -503,7 +503,7 @@ mod exec_row { assert_eq!( exit, Some(3), - "the real server's reaping reports the program's exit status — parity, not a canned code" + "the real server's reaping reports the program's exit status (parity, not a canned code)" ); assert!( !connection.is_closed(), @@ -514,7 +514,7 @@ mod exec_row { assert_eq!( decisions.len(), 1, - "the dial called the policy exactly once — the real presented key" + "the dial called the policy exactly once, with the real presented key" ); let decision = &decisions[0]; assert!(decision.accepted, "the pinned accept is the dial's verdict"); @@ -531,14 +531,14 @@ mod exec_row { } /// The direct-tcpip row (the `tunnel` build): the `-L`-shaped dial -/// through a real server's forwarding — a real TCP connection to a +/// through a real server's forwarding: a real TCP connection to a /// live loopback echo server, bytes end to end. #[cfg(all(unix, feature = "tunnel"))] mod direct_tcpip_row { use super::support; /// - *Contract stamp:* `client.md` §op rows (row 2, the - /// direct-tcpip dial) — the wave-4 double-driven `-L` row + /// direct-tcpip dial); the wave-4 double-driven `-L` row /// re-landed against a real server: `tunnel_direct` opens the /// channel on the real wire, the plain byte duplex pumps, and /// a **live** TCP listener on the far side answers @@ -592,7 +592,7 @@ mod reverse_rows { use super::support; - /// The acceptor double — records each open's payload fields and + /// The acceptor double; it records each open's payload fields and /// pumps the duplex as an echo (the assembly's pump shape). #[derive(Clone)] struct AcceptorDouble { @@ -627,7 +627,7 @@ mod reverse_rows { /// - *Contract stamp:* `client.md` §op rows (row 4, the `-R` /// listen + ingest) + `reverse-runner.md` (the consumer - /// pattern) — the wave-4 double-driven row re-landed against a + /// pattern); the wave-4 double-driven row re-landed against a /// real server: the port-0 mint returns the **actually-bound** /// port (a real server's reply, verified by dialing it), the /// server-initiated `forwarded-tcpip` open arrives into the @@ -683,7 +683,7 @@ mod reverse_rows { ) .await .expect("the dialer connects within the row deadline") - .expect("the minted port is actually bound — a real server's reply, dialable locally"); + .expect("the minted port is actually bound (a real server's reply, dialable locally)"); let (connected_address, connected_port, originator_address, originator_port) = tokio::time::timeout(Duration::from_secs(15), opens_rx.recv()) @@ -714,7 +714,7 @@ mod reverse_rows { } /// - *Contract stamp:* `client.md` §Lifecycle primitives (the - /// cancel form) — the wave-4 double-driven cancel row + /// cancel form); the wave-4 double-driven cancel row /// re-landed against a real server: an explicit-port listen is /// actually bound (dialable), the listener handle's `cancel()` /// tears the **real** listen down (a later dial is refused), a @@ -776,7 +776,7 @@ mod reverse_rows { } assert!( torn_down, - "the cancel frees the real bound port — connects are refused afterwards" + "the cancel frees the real bound port; connects are refused afterwards" ); let again = connection @@ -796,7 +796,7 @@ mod reverse_rows { } } -/// The decline rows — the sftp placeholder (every build) and the +/// The decline rows: the sftp placeholder (every build) and the /// host-key policy mismatch (every build): both dial a real server /// and pin typed declines, feature-free. #[cfg(unix)] @@ -808,7 +808,7 @@ mod declines { use super::common::fixture as key_fixture; use super::support; - /// - *Contract stamp:* OQ-13 + `client.md` §op rows (row 5) — + /// - *Contract stamp:* OQ-13 + `client.md` §op rows (row 5): /// the sftp placeholder declines in **every** build against a /// real authenticated connection: typed decline before any /// wire op (the real server observes no subsystem request), @@ -831,19 +831,19 @@ mod declines { assert!(matches!(err, OpError::SftpNotServed), "got {err:?}"); assert!( !connection.is_closed(), - "the pre-wire decline touches no wire state — the connection stays up" + "the pre-wire decline touches no wire state; the connection stays up" ); connection.close().await; fixture.stop().await; } /// - *Contract stamp:* `client.md` §The dial surface (the policy - /// call at `check_server_key`, OQ-05) + Host-key §case 1 — the + /// call at `check_server_key`, OQ-05) + Host-key §case 1: the /// pin posture consumed against a real presented key: a /// mismatch hard-declines the dial (`DialError:: /// HostKeyRejected`, no connection), the policy's decision log /// records the **real** fingerprint as rejected, and a - /// correctly-pinned dial to the same server succeeds — the + /// correctly-pinned dial to the same server succeeds; the /// decline is the policy's decision, not the server's. #[tokio::test] async fn real_presented_key_mismatch_hard_declines_and_the_right_pin_dials() { @@ -869,7 +869,7 @@ mod declines { assert_eq!( decisions.len(), 1, - "the dial called the policy exactly once — the real presented key" + "the dial called the policy exactly once, with the real presented key" ); let decision = &decisions[0]; assert!( @@ -894,7 +894,7 @@ mod declines { } /// The server-refused direct-tcpip row (the `tunnel` **and** -/// `session` builds — the all-features posture): a real server with +/// `session` builds, the all-features posture): a real server with /// `AllowTcpForwarding no` refuses the typed open, and the /// connection stays usable (a following exec is served). The session /// gate is the stays-usable proof's vehicle (recorded: under @@ -910,11 +910,11 @@ mod unfeatured_direct_decline { /// - *Contract stamp:* `client.md` §op rows (row 2's declined /// mirror) + §Correctness facts (a decline is channel-scoped, - /// auth intact, connection usable) — the wave-4 typed-open + /// auth intact, connection usable); the wave-4 typed-open /// decline row re-landed against a real server's own refusal: /// `tunnel_direct` against `AllowTcpForwarding no` → /// `OpenDeclined(Prohibited)` (the `administratively - /// prohibited` class), and a following exec is served — the + /// prohibited` class), and a following exec is served; the /// connection outlives the decline end to end. #[tokio::test] async fn real_server_refused_direct_tcpip_declines_and_the_connection_stays_usable() { @@ -944,14 +944,14 @@ mod unfeatured_direct_decline { ); assert!( !connection.is_closed(), - "the decline is channel-scoped — the connection survives it" + "the decline is channel-scoped; the connection survives it" ); let mut session = tokio::time::timeout(support::ROW_DEADLINE, connection.exec("echo still-usable")) .await .expect("the exec opens within the row deadline") - .expect("the post-decline exec is served — the connection stays usable"); + .expect("the post-decline exec is served; the connection stays usable"); let mut stdout = Vec::new(); let mut reader = alktty::wire::ChunkReader::new(&mut session.output); @@ -969,7 +969,7 @@ mod unfeatured_direct_decline { } assert_eq!( stdout, b"still-usable\n", - "the exec after the decline answers — auth intact, connection usable" + "the exec after the decline answers; auth intact, connection usable" ); connection.close().await; diff --git a/tests/e2e_server.rs b/tests/e2e_server.rs index 39b6545..31bd6c5 100644 --- a/tests/e2e_server.rs +++ b/tests/e2e_server.rs @@ -1,4 +1,4 @@ -//! The server-direction real-tool e2e (`w5-e2e-server`) — the POC-3 +//! The server-direction real-tool e2e (`w5-e2e-server`): the POC-3 //! gates re-landed against the shipped crate: real vanilla processes //! (`ssh` / `git` / `curl` / `sftp`) against the adapter mounted on a //! real TCP listener over the established in-memory doubles (the @@ -11,13 +11,13 @@ //! //! **Placement decision (recorded, the task's acceptance criterion //! 1):** a dedicated `tests/e2e_server.rs` binary reusing -//! `tests/common` — the wave-3/4 mapping binaries keep their +//! `tests/common`, so the wave-3/4 mapping binaries keep their //! single-writer posture for `w5-decline-matrix`; this binary owns //! only its own rows and its in-file fixture helpers (the trimmed //! leg-1/leg-2 fabric double for the tunnel rows, the support //! helpers). Rows arrive under the established check-gated -//! **skipped-with-reason** posture (tool absent / version short — -//! never silently green) and under a wall-clock deadline — a decline +//! **skipped-with-reason** posture (tool absent / version short, +//! never silently green) and under a wall-clock deadline (a decline //! must surface a clean diagnostic to the real client, never a hang //! (POC-1 §5 posture). Rows carry `Contract stamp:` doc markers //! against `mapping.md` / the POC-3 findings (the greppable @@ -40,12 +40,12 @@ mod support { use super::common::{MemIdentityProvider, fixture, identity}; - /// One shared row deadline — every real-process interaction is + /// One shared row deadline; every real-process interaction is /// bounded (POC-1 §5: a decline never hangs). pub const ROW_DEADLINE: std::time::Duration = std::time::Duration::from_secs(30); /// True when spawning the probe succeeds at all (exit codes are - /// the probe's own business — `ssh -V` writes to stderr, `sftp -h` + /// the probe's own business (`ssh -V` writes to stderr, `sftp -h` /// exits 1 with usage). pub fn tool_present(binary: &str, probe: &[&str]) -> bool { Command::new(binary).args(probe).output().is_ok() @@ -53,11 +53,11 @@ mod support { /// Prints the row's reasoned skip (never silently green). pub fn skip(row: &str, reason: &str) { - eprintln!("SKIPPED (with reason): {row} — {reason}"); + eprintln!("SKIPPED (with reason): {row}: {reason}"); } /// The per-row throwaway workdir + the fixture key written into - /// it (0600 — the real client's required file mode). + /// it, 0600, the real client's required file mode). pub fn write_key(row: &str) -> PathBuf { let work = std::env::temp_dir().join(format!("alkssh-e2e-server-{row}-{}", std::process::id())); @@ -77,7 +77,7 @@ mod support { } /// The decline-event observation for the e2e rows: poll the - /// capture until a matching event is on record — the row deadline + /// capture until a matching event is on record; the row deadline /// bounds the wait (not the capture's fixed window), so a slow CI /// host never turns an honest decline into a flake. pub async fn decline_event(want: &[(&str, &str)]) -> super::common::event_capture::Captured { @@ -160,7 +160,7 @@ mod support { /// (`-L`/`-D` client-side listeners, the `-R` fabric's establisher /// bind): a monotonic counter over a window **below** the kernel's /// ephemeral port range, so parallel rows can never collect the - /// same port and bind(0) allocations can never steal one — the + /// same port and bind(0) allocations can never steal one; the /// probe-bind re-verifies availability (a previous run's TIME_WAIT /// tuples) and skips taken ports. pub async fn pick_local_port() -> u16 { @@ -208,7 +208,7 @@ mod support { } } -/// The git rows — `git` build: clone (the wave-3 smoke re-landed) and +/// The git rows (`git` build): clone (the wave-3 smoke re-landed) and /// push (the POC-3 stage-B receive-pack gate), through the git /// mapping over the hand-rolled recording quartet. #[cfg(unix)] @@ -268,7 +268,7 @@ mod git_rows { } /// - *Contract stamp:* mapping.md §Channel-type rows (the git exec - /// row — `git clone ssh://…`; POC-3 §A.1 re-landed against the + /// row: `git clone ssh://…`; POC-3 §A.1 re-landed against the /// shipped crate). #[tokio::test] async fn real_git_clones_the_empty_repo_through_the_door() { @@ -309,7 +309,7 @@ mod git_rows { let stderr = String::from_utf8_lossy(&outcome.stderr).to_string(); assert!( outcome.status.success(), - "vanilla git clone (2.43+) through the door succeeds — stderr: {stderr}" + "vanilla git clone (2.43+) through the door succeeds; stderr: {stderr}" ); assert!( target.join(".git").is_dir(), @@ -317,7 +317,7 @@ mod git_rows { ); assert!( stderr.contains("empty repository"), - "the unborn-HEAD advertisement is what the clone consumed — stderr: {stderr}" + "the unborn-HEAD advertisement is what the clone consumed; stderr: {stderr}" ); assert!( doubles.resolved_ids().iter().any(|id| id == "owner/demo"), @@ -327,7 +327,7 @@ mod git_rows { } /// - *Contract stamp:* mapping.md §Channel-type rows (the git exec - /// row — `git push ssh://…` = receive-pack through the real + /// row: `git push ssh://…` = receive-pack through the real /// client; POC-3 §A stage-B gate re-landed, the wave-3 smoke's /// clone-only coverage completed). #[tokio::test] @@ -362,7 +362,7 @@ mod git_rows { .await; assert!( init.status.success(), - "the local repo initializes — stderr: {}", + "the local repo initializes; stderr: {}", String::from_utf8_lossy(&init.stderr) ); std::fs::write(repo.join("hello.txt"), "alkssh e2e push\n") @@ -383,7 +383,7 @@ mod git_rows { .await; assert!( commit.status.success(), - "the commit lands — stderr: {}", + "the commit lands; stderr: {}", String::from_utf8_lossy(&commit.stderr) ); let head = run_git(&["-C", repo.to_str().expect("path"), "rev-parse", "HEAD"]).await; @@ -415,7 +415,7 @@ mod git_rows { let stderr = String::from_utf8_lossy(&outcome.stderr).to_string(); assert!( outcome.status.success(), - "vanilla git push (receive-pack) through the door succeeds — stderr: {stderr}" + "vanilla git push (receive-pack) through the door succeeds; stderr: {stderr}" ); let prepared = doubles.prepared(); @@ -440,7 +440,7 @@ mod git_rows { } } -/// The session rows — `session` build: the interactive pty/shell +/// The session rows (`session` build): the interactive pty/shell /// session (the wave-3 smoke re-landed, extended to the echo marker) /// and the plain pipe-exec row with its separate stderr. #[cfg(unix)] @@ -457,7 +457,7 @@ mod session_rows { use super::common::harness::serve_config as harness_serve_config; use super::support; - /// The `local` composition for the session rows — alktty's own + /// The `local` composition for the session rows: alktty's own /// backend in the seam map (dev-dep unification: the `local` /// feature rides the test graph only). fn local_seam() -> SessionSeam { @@ -536,17 +536,17 @@ mod session_rows { assert!( output.status.success(), "vanilla OpenSSH's pty+shell session through the door exits 0 \ - (the exit chunk derived exit-status(0) before close) — stdout: {stdout:?}" + (the exit chunk derived exit-status(0) before close); stdout: {stdout:?}" ); assert!( stdout.contains("alkssh-e2e-pty"), - "the keystrokes and the shell's echo rode the real PTY round trip — stdout: {stdout:?}" + "the keystrokes and the shell's echo rode the real PTY round trip; stdout: {stdout:?}" ); support::cleanup(&work); } /// - *Contract stamp:* mapping.md §Request-level rows (the - /// `exec_request` pipe row — `wrapper ++ [cmd]`, stderr rides + /// `exec_request` pipe row (`wrapper ++ [cmd]`, stderr rides /// `extended_data(1)`; POC-3 §D.1's pipe split, end to end). #[tokio::test] async fn real_openssh_pipe_exec_separates_stdout_and_stderr_through_the_door() { @@ -600,23 +600,23 @@ mod session_rows { let stderr = String::from_utf8_lossy(&output.stderr).to_string(); assert!( output.status.success(), - "vanilla `ssh host \"cmd\"` through the exec wrapper exits 0 — stdout: {stdout:?} stderr: {stderr:?}" + "vanilla `ssh host \"cmd\"` through the exec wrapper exits 0; stdout: {stdout:?} stderr: {stderr:?}" ); assert!( stdout.contains("alkssh-e2e-stdout"), - "the pipe row's stdout rides SSH data — stdout: {stdout:?}" + "the pipe row's stdout rides SSH data; stdout: {stdout:?}" ); assert!( stderr.contains("alkssh-e2e-stderr"), - "the pipe row's stderr rides extended_data(1) separately — stderr: {stderr:?}" + "the pipe row's stderr rides extended_data(1) separately; stderr: {stderr:?}" ); support::cleanup(&work); } } -/// The tunnel rows — `tunnel` build: `-L` (the route-1 bridge), `-R` +/// The tunnel rows (`tunnel` build): `-L` (the route-1 bridge), `-R` /// (listen + arrival + data leg through the leg-2 fabric), and `-D` -/// (curl's SOCKS traffic takes the `direct-tcpip` leg — POC-3 +/// (curl's SOCKS traffic takes the `direct-tcpip` leg, POC-3 /// correction 2's posture). #[cfg(unix)] #[cfg(feature = "tunnel")] @@ -630,7 +630,7 @@ mod tunnel_rows { use super::common::{fixture, identity}; use super::support; - /// The in-file fabric fixtures — the trimmed leg-1/leg-2 fabric + /// The in-file fabric fixtures (the trimmed leg-1/leg-2 fabric /// double (the wave-3 smoke's recorded composition, POC-3 §C.4 /// recipe), TCP-only and happy-path only: the decline/collision /// machinery stays the mapping binaries'. @@ -775,7 +775,7 @@ mod tunnel_rows { } /// The e2e fabric double for the `-R` row: the leg-1 shape - /// extended with the **bind-first listen half** — the + /// extended with the **bind-first listen half**: the /// establisher binds the wire-named endpoint for real (the /// dynamic-address producer), mints the correlation token per /// the ADR-008 discipline, and the accept handler dials the @@ -996,7 +996,7 @@ mod tunnel_rows { } } - /// A tiny HTTP/1.1 endpoint (the POC's shape) — the substrate the + /// A tiny HTTP/1.1 endpoint (the POC's shape), the substrate the /// forwarded traffic dials through the fabric. async fn spawn_http_endpoint() -> (std::net::SocketAddr, String) { let listener = tokio::net::TcpListener::bind("127.0.0.1:0") @@ -1088,7 +1088,7 @@ mod tunnel_rows { } /// - *Contract stamp:* mapping.md §Channel-type rows (the - /// `direct-tcpip` row — `ssh -L` through the route-1 bridge; + /// `direct-tcpip` row: `ssh -L` through the route-1 bridge; /// POC-3 §C.1 re-landed with the shipped crate). #[tokio::test] async fn real_ssh_local_forward_serves_the_direct_tcpip_leg() { @@ -1147,13 +1147,13 @@ mod tunnel_rows { let stdout = String::from_utf8_lossy(&out.stdout).to_string(); assert!( stdout.trim_end() == body.trim_end(), - "vanilla ssh -L + curl through the door → fabric → endpoint returns the body — got {stdout:?}" + "vanilla ssh -L + curl through the door → fabric → endpoint returns the body; got {stdout:?}" ); support::cleanup(&work); } /// - *Contract stamp:* mapping.md §Global-request rows (the `-R` - /// listen flow — `ssh -R`'s listen, the fabric-bound port, the + /// listen flow: `ssh -R`'s listen, the fabric-bound port, the /// server-initiated `forwarded-tcpip` arrival, the client-dialed /// data leg; the `w3-tunnel-listen` flow re-landed against a /// real OpenSSH client). @@ -1224,13 +1224,13 @@ mod tunnel_rows { assert!( stdout.trim_end() == body.trim_end(), "vanilla ssh -R + curl: fabric arrival → forwarded-tcpip → client-dialed endpoint returns \ - the body — got {stdout:?}" + the body; got {stdout:?}" ); support::cleanup(&work); } /// - *Contract stamp:* mapping.md §Channel-type rows (`direct-tcpip` - /// serves **all** `ssh -D` traffic per POC-3 correction 2 — the + /// serves **all** `ssh -D` traffic per POC-3 correction 2; the /// SOCKS handshake happens client-side in OpenSSH; POC-3 §B.2's /// corrected posture re-landed with real curl). #[tokio::test] @@ -1291,7 +1291,7 @@ mod tunnel_rows { let stdout = String::from_utf8_lossy(&out.stdout).to_string(); assert!( stdout.trim_end() == body.trim_end(), - "curl --socks5-hostname through vanilla ssh -D rides the door's direct-tcpip leg — \ + "curl --socks5-hostname through vanilla ssh -D rides the door's direct-tcpip leg; \ got {stdout:?}" ); } @@ -1299,7 +1299,7 @@ mod tunnel_rows { } } -/// The decline-observability row where the `session` feature is off — +/// The decline-observability row where the `session` feature is off: /// a real `ssh` pty attempt meets a clean, channel-scoped decline /// (auth intact, no hang), with the door's decline event on record. #[cfg(unix)] @@ -1363,11 +1363,11 @@ mod unfeatured_session_decline { let stderr = String::from_utf8_lossy(&output.stderr).to_string(); assert!( !output.status.success(), - "the unfeatured pty attempt surfaces a failure to the real client — stderr: {stderr:?}" + "the unfeatured pty attempt surfaces a failure to the real client; stderr: {stderr:?}" ); assert!( !stderr.trim().is_empty(), - "the decline surfaces a clean diagnostic — stderr: {stderr:?}" + "the decline surfaces a clean diagnostic; stderr: {stderr:?}" ); if cfg!(feature = "git") { let event = support::decline_event(&[ @@ -1392,7 +1392,7 @@ mod unfeatured_session_decline { } } -/// The decline-observability rows where the `tunnel` feature is off — +/// The decline-observability rows where the `tunnel` feature is off: /// a real `ssh -R` dies at the listen gate with a clean diagnostic; /// a real `ssh -L`'s curls fail per connection without hanging the /// client; the door's decline events hold for both. @@ -1435,7 +1435,7 @@ mod unfeatured_tunnel_declines { } /// - *Contract stamp:* mapping.md §Global-request rows (the gate: - /// unfeatured `tcpip_forward` declines — POC-3 §C.2's refusal + /// unfeatured `tcpip_forward` declines; POC-3 §C.2's refusal /// shape re-landed with a real OpenSSH client and /// `ExitOnForwardFailure`). The -R row is gated here /// (check-gated, skipped-with-reason, not silently green). @@ -1480,11 +1480,11 @@ mod unfeatured_tunnel_declines { let stderr = String::from_utf8_lossy(&output.stderr).to_string(); assert!( !output.status.success(), - "the declined listen surfaces a failure to the real client — stderr: {stderr:?}" + "the declined listen surfaces a failure to the real client; stderr: {stderr:?}" ); assert!( stderr.contains("forwarding failed"), - "OpenSSH's remote-forward-failed diagnostic is on record — stderr: {stderr:?}" + "OpenSSH's remote-forward-failed diagnostic is on record; stderr: {stderr:?}" ); support::decline_event(&[ ("row", "tcpip_forward"), @@ -1496,7 +1496,7 @@ mod unfeatured_tunnel_declines { } /// - *Contract stamp:* mapping.md §Channel-type rows (the - /// `direct-tcpip` open gate — unfeatured declines; POC-1 §5: + /// `direct-tcpip` open gate (unfeatured declines; POC-1 §5): /// the real client observes a clean per-connection failure, /// no hang). #[tokio::test] @@ -1572,12 +1572,12 @@ mod unfeatured_tunnel_declines { } /// The decline-observability row for the sftp subsystem decline -/// (OQ-13) — a real `sftp` client's subsystem request meets the +/// (OQ-13): a real `sftp` client's subsystem request meets the /// named, channel-scoped decline with a clean diagnostic and no hang. /// /// Row placement note: the sftp slot gates nothing, and the row can /// only be exercised where session channels open (git / session -/// builds — in the none/tunnel builds the session-open decline is the +/// builds; in the none/tunnel builds the session-open decline is the /// observable, already pinned above and by the matrix suite). #[cfg(unix)] #[cfg(any(feature = "session", feature = "git"))] @@ -1647,11 +1647,11 @@ mod subsystem_decline { let stderr = String::from_utf8_lossy(&output.stderr).to_string(); assert!( !output.status.success(), - "the sftp decline surfaces a failure to the real client — stderr: {stderr:?}" + "the sftp decline surfaces a failure to the real client; stderr: {stderr:?}" ); assert!( !stderr.trim().is_empty(), - "the decline surfaces a clean diagnostic — stderr: {stderr:?}" + "the decline surfaces a clean diagnostic; stderr: {stderr:?}" ); let event = support::decline_event(&[ ("row", "subsystem_request"), @@ -1665,7 +1665,7 @@ mod subsystem_decline { } /// The decline-observability row for the unknown-repo collapsed -/// generic denial — a real `git clone` of a nonexistent repo dies +/// generic denial: a real `git clone` of a nonexistent repo dies /// with the collapsed `access denied` band before any protocol byte /// (no existence oracle) and exit 128. #[cfg(unix)] @@ -1735,16 +1735,16 @@ mod unknown_repo_decline { assert_eq!( outcome.status.code(), Some(128), - "the collapsed denial is git's fatal-remote-error exit — stderr: {stderr:?}" + "the collapsed denial is git's fatal-remote-error exit; stderr: {stderr:?}" ); assert!( stderr.contains("access denied") && stderr.contains("owner/absent"), "the denial names the collapsed `access denied` band with the normalized id, no existence \ - oracle — stderr: {stderr:?}" + oracle; stderr: {stderr:?}" ); assert!( !stderr.contains("not found"), - "no repository-existence oracle leaks — stderr: {stderr:?}" + "no repository-existence oracle leaks; stderr: {stderr:?}" ); support::cleanup(&work); } diff --git a/tests/fingerprint_parity.rs b/tests/fingerprint_parity.rs index fb80f11..b26389b 100644 --- a/tests/fingerprint_parity.rs +++ b/tests/fingerprint_parity.rs @@ -1,4 +1,4 @@ -//! Fingerprint-format parity — ADR-004 decision 1's contract +//! Fingerprint-format parity: ADR-004 decision 1's contract //! invariant proven against independent-issuer vectors (POC-1 §1). //! //! The vectors are the wave-1 test-key fixture set @@ -7,8 +7,8 @@ //! byte-verbatim from `ssh-keygen -lf` (OpenSSH 9.6p1, at //! vector-generation time; see `tests/vectors/fingerprints.txt`). The //! crate's single fingerprint path must reproduce those strings -//! exactly from every issuer shape — the committed public blob, the -//! private key's derived public half, and the committed `.pub` file — +//! exactly from every issuer shape (the committed public blob, the +//! private key's derived public half, and the committed `.pub` file) //! so registration values from any standard issuer compare equal, //! without cross-issuer drift. @@ -21,7 +21,7 @@ use common::FIXTURE_KEYS; const VECTOR_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/vectors"); /// The crate's single fingerprint path reproduces the recorded value -/// from the committed public blob alone — the public-key-only issuer +/// from the committed public blob alone, the public-key-only issuer /// shape (a registry that only ever sees public material). /// /// - *Contract stamp:* ADR-004 decision 1 (fingerprint parity with @@ -40,8 +40,8 @@ fn computed_fingerprints_match_recorded_values_for_public_blobs() { } } -/// The private-key path — the shape every auth/mapping test uses -/// (`decode_secret_key` → sign/serve) — yields a public half whose +/// The private-key path, the shape every auth/mapping test uses +/// (`decode_secret_key` → sign/serve), yields a public half whose /// fingerprint is the same recorded value. /// /// - *Contract stamp:* ADR-004 decision 1 (the fingerprint string @@ -66,7 +66,7 @@ fn private_derived_fingerprints_match_recorded_values() { /// value. /// /// - *Contract stamp:* ADR-004 decision 1 (independent-issuer vectors -/// are the parity proof — the commitment must be the recorded key). +/// are the parity proof; the commitment must be the recorded key). /// - *Contract stamp:* ADR-005 decision 1 (the fixtures' inner format /// is exactly the at-rest contract: unencrypted OpenSSH PEM). #[test] @@ -106,7 +106,7 @@ fn committed_fixture_files_match_the_recorded_keys() { } /// The recorded manifest (`tests/vectors/fingerprints.txt`) records -/// every fixture — no fixture ships without its independent issuer's +/// every fixture; no fixture ships without its independent issuer's /// fingerprint. /// /// - *Contract stamp:* wave-1 test-double convention (recorded @@ -130,7 +130,7 @@ fn recorded_manifest_covers_every_fixture() { /// url-safe-alphabet drift (`+`/`/`, no `=`). /// /// - *Contract stamp:* ADR-004 decision 1 (`SHA256:` + unpadded -/// base64, standard alphabet — byte-identical comparison by +/// base64, standard alphabet; byte-identical comparison by /// contract). #[test] fn registered_string_compare_is_byte_identical() { diff --git a/tests/git_mapping.rs b/tests/git_mapping.rs index 76f9837..22f0ee5 100644 --- a/tests/git_mapping.rs +++ b/tests/git_mapping.rs @@ -1,4 +1,4 @@ -//! The `w3-git-mapping` contract rows — the git branch of the spine +//! The `w3-git-mapping` contract rows: the git branch of the spine //! served for real: the exec grammar routes to the published alkgit //! seam over the russh channel duplex (ADR-006 decision 2), the //! process-mode dialect, the denial byte-order, the exit-status @@ -6,7 +6,7 @@ //! harness against the hand-rolled in-memory alkgit doubles //! (`tests/common/git_doubles.rs`). The decline-matrix rows *per //! feature build* stay in `tests/dispatch_core.rs`; this binary adds -//! the git row's serving and grammar-decline surface (feature-gated — +//! the git row's serving and grammar-decline surface (feature-gated; //! in a non-git build the binary compiles empty, per the crates' //! compile-time feature isolation). @@ -63,8 +63,8 @@ mod serving { session } - /// Opens a session channel and routes one git exec — the rows' - /// serving driver. Asserts the routed exec's Success reply (the + /// Opens a session channel and routes one git exec (the rows' + /// serving driver). Asserts the routed exec's Success reply (the /// routing decision, on the wire). pub(super) async fn route_git(session: &LoopbackSession, command: &str) -> Channel { let mut channel = open_session_channel(&session.client) @@ -83,7 +83,7 @@ mod serving { channel } - /// Proves the channel survived a decline — a follow-up request + /// Proves the channel survived a decline: a follow-up request /// dispatches again (the POC-1 §5 session-survives-declines /// posture; replicated from `dispatch_core.rs`). pub(super) async fn still_alive(channel: &mut Channel, context: &str) { @@ -247,7 +247,7 @@ mod serving { std::str::from_utf8(&first_line).unwrap(), "version 2\n", "the advertisement speaks first (alkgit speaks first) and carries \ - no '# service=' smart prefix — process mode, byte-level" + no '# service=' smart prefix; process mode, byte-level" ); let mut caps: Vec = Vec::new(); @@ -269,7 +269,8 @@ mod serving { /// `serve_duplex_resolved`) + the exit_status row (clean serve /// end → exit-status(0) **before** close, from the spawned task) /// + POC-3 §A.5 (vanilla git exits 0 on success). The registry - /// resolves the handed-through id (`owner/demo`) — dispatch + /// resolves the handed-through id (`owner/demo`), which is the + /// dispatch /// fidelity through the doubles. #[tokio::test] async fn ls_refs_round_trips_and_clean_serve_ends_exit_status_zero_before_close() { @@ -351,9 +352,9 @@ mod serving { } /// - *Contract stamp:* POC-3 §A.5 / alkgit ADR-008 N-2 (the - /// collapsed generic denial before any protocol byte — unknown ≡ + /// collapsed generic denial before any protocol byte (unknown ≡ /// unauthorized, no existence oracle): an unknown repo is *not* - /// an alkssh decline — the seam's denial band is the first byte + /// an alkssh decline): the seam's denial band is the first byte /// on the channel, then exit-status(1) per the POC's wire /// evidence, then close (status before close, spawned task). #[tokio::test] @@ -366,7 +367,7 @@ mod serving { let band = match next_packet(&mut channel, &mut framer, "the denial band").await { Packet::Payload(payload) => payload, other => panic!( - "the collapsed denial is the first byte — no pack/ref byte precedes it, got {other:?}" + "the collapsed denial is the first byte; no pack/ref byte precedes it, got {other:?}" ), }; assert_eq!( @@ -388,10 +389,10 @@ mod serving { /// convention 7) + the identity-ride decision (`w2-auth-bridge`'s /// parked item, discharged `w3-git-mapping`): the resolved /// identity is the *live* difference between two - /// otherwise-identical rows — a private repo granted to the + /// otherwise-identical rows: a private repo granted to the /// riding identity serves, the same repo without the grant /// denies (alkgit's `authorize` evaluation witnesses the ride - /// through the seam — the authorize-path witness row). + /// through the seam, the authorize-path witness row). #[tokio::test] async fn identity_ride_witnessed_by_the_authorize_gate() { let granted = Arc::new(gd::MemGit::new()); @@ -428,9 +429,9 @@ mod serving { /// - *Contract stamp:* mapping.md §the seams (the git row: /// `serve_duplex_resolved(repo_id, identity, service = push, …)` - /// — the receive-pack direction) + alkgit ADR-020 §1 (the + /// for the receive-pack direction) + alkgit ADR-020 §1 (the /// packless CAS path: commands + flush, no pack) + ADR-013 §6–7 - /// (`GitRefs::apply_updates` is the single CAS home — the wire + /// (`GitRefs::apply_updates` is the single CAS home; the wire /// layer applies, the double records). #[tokio::test] async fn packless_receive_pack_applies_the_cas_and_reports() { @@ -508,7 +509,7 @@ mod serving { } /// - *Contract stamp:* POC-3 §2 (unknown services declined - /// honestly — the decided decline-with-reason surface; the + /// honestly (the decided decline-with-reason surface; the /// record): request-level failure, alive channel, nothing /// reaches the seam. #[tokio::test] @@ -546,7 +547,7 @@ mod serving { session.unmount().await; } - /// - *Contract stamp:* POC-3 §A (SSH exec must carry the repo) — + /// - *Contract stamp:* POC-3 §A (SSH exec must carry the repo): /// service-only declines request-level, alive channel. #[tokio::test] async fn service_only_declines_request_level_with_alive_channel() { @@ -575,7 +576,7 @@ mod serving { /// the shape gate (the parse hands the id through; invalid ids /// decline at the git row, never resolve): charset, segments, /// and the empty id all decline request-level with an alive - /// channel — the `invalid-repo-id` class. + /// channel, the `invalid-repo-id` class. #[tokio::test] async fn invalid_repo_ids_decline_before_the_seam() { let doubles = Arc::new(gd::MemGit::new()); @@ -626,7 +627,7 @@ mod serving { /// - *Contract stamp:* mapping.md §Data-plane/limits + /// `Limits::max_exec_command_len` (the per-length cap enforced /// **before** any parse or allocation; decline-first, - /// alloc-never — the wave-2 carried-not-enforced reservation + /// alloc-never; the wave-2 carried-not-enforced reservation /// consumed `w3-git-mapping`): an over-length command answers /// failure, alive channel, nothing parsed. #[tokio::test] @@ -688,18 +689,18 @@ mod serving { } /// - *Contract stamp:* the status-before-close hardening - /// (`w4-git-exit-close` — the wave-3 gate's booked finding 1, + /// (`w4-git-exit-close`, the wave-3 gate's booked finding 1, /// the saturated-`Sender` tail made real on the wire): the /// serve's *answer volume* exceeds the whole outbound pipeline /// (the harness client's packet loop is frozen on the armed /// data gate → the transport duplex `DUPLEX_CAPACITY` fills → - /// the server's flush pends → russh's bounded message queue — - /// `event_buffer_size`, default 10, pinned below — fills → the + /// the server's flush pends → russh's bounded message queue + /// (`event_buffer_size`, default 10, pinned below) fills → the /// serve's remaining answer writes pend). The gate's release /// then drives the serve tail through the just-unwinding /// contention: the backlogged answer data drains **through the /// same queue the report sends ride**, and the exit-status - /// still lands **before** the close — the split-halves + /// still lands **before** the close, the split-halves /// construction's property (the report is the only /// close-contracting sender; sequential awaited sends on the /// one handle), pinning every wire row of this class against @@ -710,7 +711,7 @@ mod serving { russh::server::Config::default().event_buffer_size, 10, "the row's construction pins russh's default message-queue capacity \ - (the saturated-tail scenario's depth) — a russh default change here \ + (the saturated-tail scenario's depth); a russh default change here \ re-reads this row's freeze-settle yields, not its assertions" ); @@ -823,13 +824,13 @@ mod serving { // ------------------------------------------------------------------ // The store-and-take handoff, observed: two sequential services on - // two channels of one session — the store is the session task's, + // two channels of one session; the store is the session task's, // never poisoned by the taken one. // ------------------------------------------------------------------ /// - *Contract stamp:* POC-3 §A.4 (the accepted-but-held Channel → /// `channels.remove(&id)` → `into_stream()` in the spawned task; - /// the session task reuses the store) — the second serve on a + /// the session task reuses the store); the second serve on a /// fresh channel of the same session rides the same handoff. #[tokio::test] async fn store_is_reused_across_sequential_serves() { @@ -868,20 +869,20 @@ mod serving { // ------------------------------------------------------------------ // The channel-not-held guard (`w4-channel-not-held-rows`): a second - // exec on an already-served channel declines request-level — the + // exec on an already-served channel declines request-level; the // store-and-take handoff holds a channel exactly once, the wave-3 // gate's booked finding 2. // ------------------------------------------------------------------ /// - *Contract stamp:* mapping.md §Request-level rows (the git - /// row's store-and-take handoff: the `channel-not-held` class — + /// row's store-and-take handoff, the `channel-not-held` class: /// a second exec on an already-served channel answers - /// `channel_failure`, inline, the first serve rides on — no + /// `channel_failure`, inline, the first serve rides on; no /// second serving path ever spawns) + the event vocabulary /// (`src/observe.rs`: class `request`, reason /// `channel-not-held`, route `git`; the advertisement drains /// first and the serve parks at the gated `list_refs` behind it, - /// so the wire is quiescent for the decline — race-free by + /// so the wire is quiescent for the decline (race-free by /// construction). #[tokio::test] async fn second_exec_on_a_served_git_channel_declines_channel_not_held() { @@ -913,7 +914,7 @@ mod serving { doubles.resolved_ids(), vec!["owner/demo".to_owned()], "the first serve resolved and parks at the gated list_refs behind \ - its advertisement — the stored channel is taken, the wire quiescent" + its advertisement; the stored channel is taken, the wire quiescent" ); request_exec(&channel, "git-upload-pack '/owner/demo'") @@ -957,7 +958,7 @@ mod serving { #[cfg(feature = "git")] mod real_tool { //! The real-tool smoke (`w3-git-mapping`): one `git clone` (2.43+) - //! through a TCP-mounted adapter against the hand-rolled doubles — + //! through a TCP-mounted adapter against the hand-rolled doubles, //! the POC-3 stage-A gate re-landed cheaply. Tooling posture //! (recorded): the smoke requires `git` ≥ 2.43 and `ssh` in the //! environment; when absent it is **skipped with a printed reason** @@ -977,11 +978,11 @@ mod real_tool { async fn real_git_clone_smoke() { let (git_ok, git_reason) = git_available(); if !git_ok { - eprintln!("SKIPPED (with reason): real-tool clone smoke — {git_reason}"); + eprintln!("SKIPPED (with reason): real-tool clone smoke: {git_reason}"); return; } if Command::new("ssh").arg("-V").output().is_err() { - eprintln!("SKIPPED (with reason): real-tool clone smoke — ssh is unavailable"); + eprintln!("SKIPPED (with reason): real-tool clone smoke, ssh is unavailable"); return; } @@ -1053,7 +1054,7 @@ mod real_tool { let stderr = String::from_utf8_lossy(&outcome.stderr).to_string(); assert!( outcome.status.success(), - "vanilla git clone (2.43) through the door succeeds — stderr: {stderr}" + "vanilla git clone (2.43) through the door succeeds; stderr: {stderr}" ); assert!( target.join(".git").is_dir(), @@ -1061,7 +1062,7 @@ mod real_tool { ); assert!( stderr.contains("empty repository"), - "the unborn-HEAD advertisement is what the clone consumed — stderr: {stderr}" + "the unborn-HEAD advertisement is what the clone consumed; stderr: {stderr}" ); assert!( doubles.resolved_ids().iter().any(|id| id == "owner/demo"), diff --git a/tests/loopback_harness.rs b/tests/loopback_harness.rs index 186bea2..84d39f0 100644 --- a/tests/loopback_harness.rs +++ b/tests/loopback_harness.rs @@ -1,4 +1,4 @@ -//! The `w2-loopback-harness` acceptance rows — the harness proved +//! The `w2-loopback-harness` acceptance rows: the harness proved //! live: a full in-process connect → authenticate (fixture key through //! `MemIdentityProvider`) → authenticated-session observation through //! the wave-2 stack, plus the observation shapes (auth failure, @@ -6,7 +6,7 @@ //! tests speak through the same helpers. //! //! Every row drives the crate through the harness (`common::harness`) -//! — the recorded transport (tokio duplex pair, no TCP port) and the +//! through it, the recorded transport (tokio duplex pair, no TCP port) and the //! recorded client posture (fixture keys, `MemHostKeyPolicy`, the //! `Limits` keepalive/wall-clock posture) are the harness's own //! decisions, exercised here. @@ -46,7 +46,7 @@ fn permissive_policy() -> Arc { /// in-process transport) + ADR-004 decision 1 (the fixture key's /// fingerprint accepts through `MemIdentityProvider`) + ADR-005 /// decision 6 (the host key set loads decrypt-at-construction from -/// `MemHostKeySource` — the wave-1 doubles live through the wave-2 +/// `MemHostKeySource`; the wave-1 doubles live through the wave-2 /// stack). #[tokio::test] async fn in_process_pair_connects_and_authenticates_end_to_end() { @@ -91,7 +91,7 @@ async fn in_process_pair_connects_and_authenticates_end_to_end() { /// - *Contract stamp:* ADR-001 (the authenticated session is live and /// serving over the mount) + `mapping.md` §Decline matrix (the /// fail-closed decline is observable through the harness as a -/// ChannelOpenFailure reason — the *specific* reason is +/// ChannelOpenFailure reason; the *specific* reason is /// `w2-dispatch-decline-core`'s row, which landed it; in builds with /// a session-serving feature this row never sees a decline, so it /// is pinned to the featureless builds it speaks about). @@ -124,7 +124,7 @@ async fn authenticated_session_serves_and_declines_with_an_observed_reason() { session.unmount().await; } -/// - *Contract stamp:* ADR-004 decision 1 (`None` → reject — the +/// - *Contract stamp:* ADR-004 decision 1 (`None` → reject; the /// failure shape rides the harness with the advertisement intact) /// + ADR-004 decision 4 (the remaining-methods set is exactly /// `{publickey}`). @@ -184,7 +184,7 @@ async fn fail_closed_host_key_policy_verdict_disconnects_the_dial() { /// - *Contract stamp:* `auth.md` §Host-key policy case 1 (the /// trust-anchor shape: an exact `(host, fingerprint)` pin accepts -/// with a fail-closed default for everything else) — the policy +/// with a fail-closed default for everything else); the policy /// double's rule vocabulary driven over the wire. #[tokio::test] async fn pinned_policy_rule_serves_the_trust_anchor_case() { diff --git a/tests/observe.rs b/tests/observe.rs index bd7241c..ece6b28 100644 --- a/tests/observe.rs +++ b/tests/observe.rs @@ -1,4 +1,4 @@ -//! The `w3-decline-tracing` wire rows — the event presence pin: every +//! The `w3-decline-tracing` wire rows, the event presence pin: every //! decline class in `src/` (the open-level declines, the request-level //! capability declines, the seam-stub serving declines with their //! spawned-path lifecycle, and the auth dispositions) emits its @@ -7,17 +7,17 @@ //! //! **Test convention (recorded):** the family's only tracing-test //! precedent is alktunnels' fmt-subscriber dev-dep, used for debug -//! *output* — there is no event-capture convention to adopt, so these +//! *output*, and there is no event-capture convention to adopt, so these //! rows pin the convention: a hand-rolled minimal //! [`tracing::Subscriber`] capturing events into a shared buffer, //! installed once as the global default (the server side runs on -//! spawned tasks — a thread-local default cannot see them; a global -//! capture needs no extra dependency). The install is up front — the +//! spawned tasks, which a thread-local default cannot see; a global +//! capture needs no extra dependency). The install is up front; the //! mount helpers call [`capture`] before any wire exchange, so no //! event is emitted below the not-yet-installed global. Rows assert //! presence by field-matching (`row` + `decline_class` + `reason` + //! build), and the vocabulary assertion checks each captured decline's exact -//! field set — the shape the three wave-3 mapping branches inherit. +//! field set, the shape the three wave-3 mapping branches inherit. //! The helper-level shapes (field order, the `warn` level of the //! failure arm) are pinned in `src/observe.rs`'s own unit rows. //! @@ -44,7 +44,7 @@ use russh::{Channel, ChannelMsg}; use alkssh::Limits; // --------------------------------------------------------------------------- -// The capture subscriber — the recorded test convention (see module docs). +// The capture subscriber, the recorded test convention (see module docs). // --------------------------------------------------------------------------- #[derive(Debug, Clone)] @@ -122,7 +122,7 @@ fn capture() -> &'static Arc { }) } -/// The shared capture snapshot — every test reads the whole buffer and +/// The shared capture snapshot: every test reads the whole buffer and /// matches fields, so parallel rows never order against each other. fn captured() -> Vec { capture().0.lock().unwrap().clone() @@ -144,7 +144,7 @@ async fn await_event(want: &[(&str, &str)]) -> Captured { } } -/// The expected `feature_build` value, derived from `cfg!` — the +/// The expected `feature_build` value, derived from `cfg!`; the /// vocabulary assertion checks every captured decline against it (the /// same convention as `src/observe.rs`'s cfg-derived unit row). fn expected_build() -> &'static str { @@ -173,7 +173,7 @@ fn expected_build() -> &'static str { } } -/// The global-request rows — the no-channel surfaces (the event +/// The global-request rows, the no-channel surfaces (the event /// vocabulary assertion needs to know the field set these carry). fn is_global_row(row: Option<&str>) -> bool { row.is_some_and(|row| { @@ -188,7 +188,7 @@ fn is_global_row(row: Option<&str>) -> bool { } /// The vocabulary assertion: a captured decline carries the exact -/// field set (nothing more — the safety posture rides on this: no +/// field set (nothing more; the safety posture rides on this: no /// dynamic extra fields exist), with the build/class/reason/row the /// caller matched on. fn assert_decline(event: &Captured, want: &[(&str, &str)]) { @@ -239,10 +239,10 @@ fn assert_decline(event: &Captured, want: &[(&str, &str)]) { } // --------------------------------------------------------------------------- -// Shared rows — run in every feature build. +// Shared rows; run in every feature build. // --------------------------------------------------------------------------- -/// - *Contract stamp:* ADR-003 §5 (x11 is a never-feature — the open +/// - *Contract stamp:* ADR-003 §5 (x11 is a never-feature; the open /// declines in every build; the event pins the deciding context). #[tokio::test] async fn x11_open_decline_emits_the_never_feature_event() { @@ -261,12 +261,12 @@ async fn x11_open_decline_emits_the_never_feature_event() { } /// - *Contract stamp:* mapping.md §Global-request rows (the `-R` -/// listen form declines this build's flow — the event carries no +/// listen form declines this build's flow (the event carries no /// channel id: global requests have none). The reason is the /// build's gate: `unfeatured` where the feature is off, /// `seam-unconfigured` where the tunnel feature is on but no /// fabric leg/listen seam is configured (the unset-declines -/// posture — a bare `authenticated()` session configures neither). +/// posture; a bare `authenticated()` session configures neither). #[cfg(not(feature = "tunnel"))] #[tokio::test] async fn tcpip_forward_decline_emits_the_global_request_event() { @@ -289,7 +289,7 @@ async fn tcpip_forward_decline_emits_the_global_request_event() { /// - *Contract stamp:* mapping.md §Global-request rows + the /// decline-matrix's config-driven notes (the `w3-tunnel-listen` /// migrated stub row): a featured build whose fabric leg/listen -/// seam is unconfigured declines `seam-unconfigured` — the feature +/// seam is unconfigured declines `seam-unconfigured`; the feature /// alone configures nothing. #[cfg(feature = "tunnel")] #[tokio::test] @@ -310,7 +310,7 @@ async fn tcpip_forward_decline_emits_the_seam_unconfigured_event() { session.unmount().await; } -/// - *Contract stamp:* ADR-004 (the bridge rejects fail-closed — +/// - *Contract stamp:* ADR-004 (the bridge rejects fail-closed: /// `None` resolution → reject disposition; the event pins the /// decline without exposing who). #[tokio::test] @@ -363,7 +363,7 @@ async fn auth_none_decline_emits_the_auth_event() { } /// - *Contract stamp:* auth.md §Dispositions (log exposure is -/// deployment policy — the crate's events are safe-by-default: no +/// deployment policy; the crate's events are safe-by-default: no /// username, secret, or fingerprint ever enters an event field or /// message; `w3-decline-tracing`'s safety posture, pinned by /// scanning every captured event across the whole binary's rows). @@ -426,7 +426,7 @@ mod default_build { use common::harness::open_session_channel; /// - *Contract stamp:* mapping.md §Decline matrix (the none-build - /// row: everything declines — the event answers the booked + /// row: everything declines; the event answers the booked /// finding: the decline's deciding context is observable). #[tokio::test] async fn unfeatured_session_open_emits_the_open_event() { @@ -453,11 +453,11 @@ mod git_build { request_subsystem, request_x11, }; - /// - *Contract stamp:* ADR-006 decision 4 (spawn-and-return — the + /// - *Contract stamp:* ADR-006 decision 4 (spawn-and-return; the /// serving path is spawned; the lifecycle events started / /// decline / ended ride the spawned task, in wiring order). The /// git row's decline in a seam-less build is config-driven - /// (`w3-git-mapping`: the unset-declines contract — the reason + /// (`w3-git-mapping`: the unset-declines contract, the reason /// names the seam, not the stub). #[tokio::test] async fn git_seam_stub_declines_with_the_full_serving_lifecycle() { @@ -623,7 +623,7 @@ mod session_build { /// - *Contract stamp:* ADR-006 decision 4 (the pty serving decline /// is spawned; the lifecycle rides the task) + OQ-08 (the - /// unset-seam decline: feature on, seam unset — the config- + /// unset-seam decline (feature on, seam unset), the config- /// driven class the real paths inherit, /// `w3-tty-session`). #[tokio::test] @@ -669,7 +669,7 @@ mod session_build { } /// - *Contract stamp:* OQ-08 + the event vocabulary (`w3-tty- - /// session`: the unset-field pipe decline — + /// session`: the unset-field pipe decline, /// `wrapper-unconfigured`, the serving-path class from a /// spawned task). #[tokio::test] @@ -703,7 +703,7 @@ mod tunnel_build { /// - *Contract stamp:* the unset-declines posture (`w3-seam-config`, /// carried through `w3-tunnel-direct`: the route-1 bridge's - /// pre-admit classes) — the direct row's absent-handle decline + /// pre-admit classes): the direct row's absent-handle decline /// emits the `seam-unconfigured` open-class event (the fabric /// double's real decline events ride tests/tunnel_mapping.rs). #[tokio::test] @@ -766,12 +766,13 @@ async fn authenticated(username: &str) -> common::harness::LoopbackSession { session } -/// A mounted (kex-complete, **unauthenticated**) loopback session — +/// A mounted (kex-complete, **unauthenticated**) loopback session, /// the auth-decline rows' driver: an auth disposition is observed /// before any acceptance exists, so these rows must not pre-derive /// themselves through [`authenticated`] (a second auth exchange on an -/// authenticated session is not a supported russh surface — mounted -/// fresh is the honest shape, matching `auth_bridge.rs`'s rows). +/// authenticated session is not a supported russh surface, so it is +/// mounted fresh; that is the honest shape, matching +/// `auth_bridge.rs`'s rows). async fn mounted() -> common::harness::LoopbackSession { capture(); let provider = Arc::new(MemIdentityProvider::new()); @@ -799,7 +800,7 @@ async fn expect_failure_then_close(channel: &mut Channel) { "the seam stub closes the channel" ); // Yield so the spawned task's post-close events (ended) are likely - // to have landed before the unmount — await_event's polling covers + // to have landed before the unmount; await_event's polling covers // the rest. tokio::time::sleep(Duration::from_millis(50)).await; } diff --git a/tests/spawn_return.rs b/tests/spawn_return.rs index 16a114e..a8e9e68 100644 --- a/tests/spawn_return.rs +++ b/tests/spawn_return.rs @@ -1,4 +1,4 @@ -//! The spawn-and-return mechanics proof (`w2-spawn-return`) — the +//! The spawn-and-return mechanics proof (`w2-spawn-return`), the //! structural constraint (ADR-006 decision 4) pinned as tests, over //! the real wire. //! @@ -7,7 +7,7 @@ //! peer's follow-up bytes (POC-3 proved by construction with //! receive-pack). The crate's plumbing //! ([`alkssh::spawn_serving_path`], -//! [`alkssh::report_exit_status_then_close`] — the `#[doc(hidden)]` +//! [`alkssh::report_exit_status_then_close`], the `#[doc(hidden)]` //! contract-test re-exports from `src/serve.rs`) makes the escape //! mechanical: the handler hook clones `session.handle()`, spawns the //! serving future, and returns. @@ -16,10 +16,10 @@ //! proof handler stands in for the crate's own auth/dispatch hooks //! (their correctness is `w2-auth-bridge`/`w2-dispatch-decline-core` //! contract territory; the `dispatch` seam stubs now spawn through the -//! same plumbing, so the crate's own rows exercise the spawn too — +//! same plumbing, so the crate's own rows exercise the spawn too; //! `tests/dispatch_core.rs`). What is under test here is the //! *mechanics*: the spawn-then-return, the cloned-handle reporting, -//! and the wire ordering — `exit-status` before close, arriving after +//! and the wire ordering (`exit-status` before close, arriving after //! the handler already returned, while the session's packet loop keeps //! routing the connection's follow-up traffic. @@ -41,14 +41,14 @@ use russh::{Channel, ChannelId, ChannelMsg, Disconnect, Error, MethodKind, Metho use alkssh::Limits; -/// The exit status the proof stub reports — an arbitrary distinct +/// The exit status the proof stub reports, an arbitrary distinct /// value the rows assert verbatim (`exit-status(7)`). const PROOF_EXIT: u32 = 7; -/// The command the rows exec — anything; the proof handler ignores it. +/// The command the rows exec (anything; the proof handler ignores it). const PROOF_COMMAND: &str = "mechanics-proof-serving-path"; -/// The async completion gate the spawned serving paths hold on — +/// The async completion gate the spawned serving paths hold on, /// released only after the rows have proven the handler returned. /// `watch`-based (no lost-wakeup race: a late subscriber still sees /// the release). @@ -56,7 +56,7 @@ fn serving_gate() -> tokio::sync::watch::Sender { tokio::sync::watch::channel(false).0 } -/// The spawned task's wait: blocks until (or returns if) released — +/// The spawned task's wait: blocks until (or returns if) released; /// `borrow_and_update` marks the release seen so the wakeup is never /// lost or replayed. async fn gate_wait(rx: &mut tokio::sync::watch::Receiver) { @@ -65,7 +65,7 @@ async fn gate_wait(rx: &mut tokio::sync::watch::Receiver) { } } -/// What the proof handler records — the timestamps the rows compare. +/// What the proof handler records: the timestamps the rows compare. #[derive(Default)] struct ProofRecord { handler_returned_at: Option, @@ -74,7 +74,7 @@ struct ProofRecord { type Shared = Arc>; -/// The proof handler (server side): mechanics-only — it authenticates +/// The proof handler (server side): mechanics-only. It authenticates /// the fixture alpha by the crate's one fingerprint path, accepts /// session channels, and serves every exec by *the crate's own /// spawn-and-return plumbing*: a serving path gated on the row's @@ -96,7 +96,7 @@ impl russh::server::Handler for ProofServer { Ok(Auth::Accept) } - /// The mechanics rows' own fixture check — fingerprint equality + /// The mechanics rows' own fixture check: fingerprint equality /// against fixture alpha through the crate's fingerprint path /// (not the bridge contract; that is `w2-auth-bridge`'s suite). async fn auth_publickey( @@ -124,7 +124,7 @@ impl russh::server::Handler for ProofServer { } /// The hook under proof: clone the handle, spawn the serving path - /// (gated — it stays pending past this method's return), record + /// (gated, it stays pending past this method's return), record /// the handler's return instant, and go. async fn exec_request( &mut self, @@ -151,7 +151,7 @@ impl russh::server::Handler for ProofServer { /// server task (russh's own stack over the proof handler), and the /// connected client. Transport and posture mirror the loopback /// harness (its recorded decisions); the handler is intentionally not -/// the crate's `SessionHandler` — the crate stack under a custom +/// the crate's `SessionHandler`; the crate stack under a custom /// serving hook is the proof's subject. struct ProofSession { client: russh::client::Handle, @@ -210,7 +210,7 @@ async fn mount() -> ProofSession { } impl ProofSession { - /// Releases the gate — the spawned serving paths complete + /// Releases the gate; the spawned serving paths complete /// asynchronously from here on. fn release_gate(&self) { let _ = self.gate.send(true); @@ -228,7 +228,7 @@ impl ProofSession { } /// Waits (bounded) until the exec hook has provably run and - /// returned — the client's `exec` returns when the request is on + /// returned; the client's `exec` returns when the request is on /// the wire; the loop's processing of it is observed here. async fn exec_hook_has_returned(&self) { tokio::time::timeout(std::time::Duration::from_secs(5), async { @@ -241,7 +241,7 @@ impl ProofSession { } /// The handler provably returned while the spawned serving path - /// was still pending — the handler-returns-fast assertion. + /// was still pending, the handler-returns-fast assertion. fn assert_handler_returned_spawn_still_pending(&self, context: &str) { let record = self.record.lock(); assert!( @@ -250,7 +250,7 @@ impl ProofSession { ); assert!( record.exit_reported_at.is_none(), - "{context}: the spawned serving path is still gated — nothing reported yet" + "{context}: the spawned serving path is still gated; nothing reported yet" ); } } @@ -260,7 +260,7 @@ impl ProofSession { // --------------------------------------------------------------------------- /// - *Contract stamp:* ADR-006 decision 4 (the structural constraint: -/// every serving path is spawned — the handler completes while the +/// every serving path is spawned (the handler completes while the /// spawned task is still running) + mapping.md §The structural /// constraint: spawn-and-return (the follow-up-bytes deadlock /// inverted: the connection's loop keeps routing while a serving @@ -279,7 +279,7 @@ async fn handler_returns_fast_while_the_spawned_serving_path_is_pending() { session.exec_hook_has_returned().await; session.assert_handler_returned_spawn_still_pending("after the exec"); - // The follow-up-bytes inversion — POC-3's deadlock shape: the peer + // The follow-up-bytes inversion, POC-3's deadlock shape: the peer // sends immediate follow-up traffic and the loop routes it while // the first serving path is still pending. let follow_up = open_session_channel(&session.client) @@ -335,7 +335,7 @@ async fn spawned_stub_reports_exit_status_before_close_after_the_handler_returne }; // Strict wire order, message by message: exit-status first, close - // after — the ordering contract verbatim. + // after, the ordering contract verbatim. let first = next_message(&mut channel) .await .expect("the released serving path reports"); diff --git a/tests/tty_mapping.rs b/tests/tty_mapping.rs index dea01cc..8a13c8e 100644 --- a/tests/tty_mapping.rs +++ b/tests/tty_mapping.rs @@ -1,15 +1,15 @@ -//! The `w3-tty-session` contract rows — the session branch of the +//! The `w3-tty-session` contract rows: the session branch of the //! spine served for real: pty/shell/pipe-exec through the published //! alktty seam (`drive_session_pre_negotiated`) over the translation //! bridge, the locally-built negotiation, the control rows, the exit //! derivation contract (mapping.md rules 1–6), and the -//! negotiation-error decline class — all observed through the +//! and the negotiation-error decline class; all observed through the //! loopback harness against the hand-rolled TtyBackend shim //! (`tests/common/tty_doubles.rs`). The decline-matrix rows *per //! feature build* stay in `tests/dispatch_core.rs`; this binary adds //! the session rows' serving surface, the unset-field declines (which //! need a configured seam to isolate), and the real-tool pty smoke -//! (feature-gated — in a `session`-less build the binary compiles +//! (feature-gated: in a `session`-less build the binary compiles //! empty, per the crates' compile-time feature isolation). #![allow(dead_code)] @@ -37,7 +37,7 @@ mod serving { use super::common::{MemHostKeyPolicy, MemIdentityProvider, fixture, identity}; use alkssh::{Limits, ServeConfig, SshAdapter}; - /// The observation surface on the wire — the terminal-observation + /// The observation surface on the wire, the terminal-observation /// enum these rows drive (russh-verbatim shapes, drained in order /// until the deadline). #[derive(Debug)] @@ -50,7 +50,7 @@ mod serving { Failure, } - /// The next observation with a deadline — None past 10 s (nothing + /// The next observation with a deadline; None past 10 s (nothing /// else can arrive; a row hanging past the deadline is its bug). pub(super) async fn next_observation(channel: &mut Channel) -> Option { tokio::time::timeout(std::time::Duration::from_secs(10), async { @@ -86,7 +86,7 @@ mod serving { } /// Drains observations until the terminal outcome (status or - /// signal) — collecting the data rides for the ride rows, and + /// signal), collecting the data rides for the ride rows, and /// asserting the close follows after (the status-before-close /// order). pub(super) async fn collect_terminal( @@ -127,7 +127,7 @@ mod serving { } } - /// Waits for one Success reply (want-reply requests) — with a + /// Waits for one Success reply (want-reply requests), with a /// deadline; a Failure or a silent close is the panic, the rows /// drive Success paths. pub(super) async fn expect_success(channel: &mut Channel, context: &str) { @@ -182,7 +182,7 @@ mod serving { panic!("no signal reached the shim's control"); } - /// Builds the session rows' serve-config — everything set (the + /// Builds the session rows' serve-config, everything set (the /// shim seam, the shell argv, the exec wrapper, session cwd/env), /// overridable per row through the mutator. The identity resolves /// from the `alpha` fixture into `ssh-rider` (the witness id). @@ -203,12 +203,12 @@ mod serving { } /// Mounts an authenticated loopback session over the given config - /// — the rows' driver (fixture `alpha` → `ssh-rider`). + /// (the rows' driver; fixture `alpha` → `ssh-rider`). pub(super) async fn session_with(mutate: impl FnOnce(&mut ServeConfig)) -> LoopbackSession { session_with_limits(mutate, Limits::default()).await } - /// [`session_with`] over non-default [`Limits`] — the rows that + /// [`session_with`] over non-default [`Limits`], for the rows that /// tune a budget (the channel-cap release row's ceiling of 1). pub(super) async fn session_with_limits( mutate: impl FnOnce(&mut ServeConfig), @@ -235,13 +235,13 @@ mod serving { session } - /// A shim-backed seam — the rows' default (no ownership provider). + /// A shim-backed seam, the rows' default (no ownership provider). pub(super) fn shim_seam(shim: &Arc) -> impl FnOnce(&mut ServeConfig) { let seam = td::tty_seam(shim); move |serve: &mut ServeConfig| serve.session_seam = Some(seam) } - /// Opens a session channel and sends the pty+shell request pair — + /// Opens a session channel and sends the pty+shell request pair; /// replaced per-row below (the rows drive their own sequences). #[tokio::test] @@ -338,7 +338,7 @@ mod serving { assert_eq!( params.cmd, vec!["/bin/wrap".to_owned(), "-x".to_owned(), "uptime".to_owned()], - "the wire command appended to the wrapper argv — never naively split" + "the wire command appended to the wrapper argv, never naively split" ); assert!( params.terminal.is_none(), @@ -421,13 +421,13 @@ mod serving { // ------------------------------------------------------------------ // The channel-not-held guard (`w4-channel-not-held-rows`): a second - // request on an already-served channel declines request-level — the + // request on an already-served channel declines request-level; the // store-and-take handoff holds a channel exactly once, the wave-3 // gate's booked finding 2. // ------------------------------------------------------------------ /// - *Contract stamp:* mapping.md §Request-level rows (the exec - /// row's store-and-take handoff: the `channel-not-held` class — + /// row's store-and-take handoff, the `channel-not-held` class: /// a second exec on an already-served pipe channel answers /// `channel_failure`, inline, the first serve rides on) + the /// event vocabulary (`src/observe.rs`: class `request`, reason @@ -485,12 +485,12 @@ mod serving { /// - *Contract stamp:* mapping.md §Request-level rows (the /// `shell_request` row's store-and-take handoff: the - /// `channel-not-held` class — a second shell request on an + /// `channel-not-held` class: a second shell request on an /// already-served shell channel answers `channel_failure`, /// inline, the first serve rides on) + the event vocabulary /// (`src/observe.rs`: class `request`, reason /// `channel-not-held`; the lifecycle row carries no - /// `exec_route` — absent-field shape pinned on the wire). + /// `exec_route`; absent-field shape pinned on the wire). #[tokio::test] async fn second_shell_request_on_a_served_shell_channel_declines_channel_not_held() { ec::install(); @@ -543,7 +543,7 @@ mod serving { // ------------------------------------------------------------------ // The channel_close-fired per-channel cancel path on the wire // (`w4-tty-coverage`, wave-3 gate booked item 3): the cap release + - // the per-channel state teardown, wire-witnessed — the disjoint + // the per-channel state teardown, wire-witnessed; the disjoint // release sites the gate verified per row (the wire rows here // witness the established-channel-close site, `channel_cap.rs` // release site 1). @@ -553,9 +553,9 @@ mod serving { /// `channel_cap.rs` release site 1 + `handler.rs` /// §the control rows' per-channel surface (a client close on a /// served row fires the `channel_close` hook: the bridge surface - /// fires the per-channel cancel — the serving task aborts the + /// fires the per-channel cancel; the serving task aborts the /// alktty session, alktty's kill-on-drop contract fires, nothing - /// fabricated on the wire — and the cap releases, disjoint from + /// fabricated on the wire, and the cap releases, disjoint from /// the bridge-failure and arrival sites). #[tokio::test] async fn a_client_close_on_a_served_row_fires_the_per_channel_cancel_and_releases_the_cap() { @@ -605,7 +605,7 @@ mod serving { } assert!( !shim.observation().kills.lock().is_empty(), - "the close-fired per-channel cancel aborted the alktty session — \ + "the close-fired per-channel cancel aborted the alktty session; \ alktty's kill-on-drop contract fired (witnessed before unmount, \ so this is the channel_close path, not the teardown)" ); @@ -622,7 +622,7 @@ mod serving { let mut recovered = open_session_channel(&session.client) .await - .expect("the cap recovered after the close — the channel_close hook released"); + .expect("the cap recovered after the close, since the channel_close hook released"); request_exec(&recovered, "uptime") .await .expect("the recovered channel routes"); @@ -634,19 +634,19 @@ mod serving { // ------------------------------------------------------------------ // The Closed/Break no-exit-chunk close shape on the wire // (`w4-tty-coverage`): a bridge read that ends without an exit - // chunk reports nothing — the derivation contract's absent-report + // chunk reports nothing; the derivation contract's absent-report // posture pinned, not just the happy paths. (The frame-level // Closed/Break classification rows live in `src/tty_map.rs`'s test // mod; the Break classification is unreachable through alktty's - // own validated `ChunkWriter` — a defensive arm.) + // own validated `ChunkWriter`, a defensive arm.) // ------------------------------------------------------------------ /// - *Contract stamp:* mapping.md §Exit chunk (the contract's /// close-shape class: the bridge read ends **without** an exit - /// chunk → no report, plain close, the lifecycle's ended event — + /// chunk → no report, plain close, the lifecycle's ended event: /// its absence is neither 0 nor 255). The shape is constructed /// through the real path: the shim's stdout carries a payload - /// beyond alktty's own `MAX_CHUNK_LEN` wire bound — alktty's + /// beyond alktty's own `MAX_CHUNK_LEN` wire bound; alktty's /// `ChunkWriter` rejects it locally, its drainer shuts the write /// half down, and the bridge's next read is EOF (`Closed`) with /// the scripted exit never forwarded. Nothing fabricated. @@ -754,13 +754,13 @@ mod serving { } assert!( !shim.observation().stdin_eof.lock().is_empty(), - "the SSH EOF translated to the zero-length stdin-chunk sentinel — \ + "the SSH EOF translated to the zero-length stdin-chunk sentinel: \ the backend's stdin shutdown was observed" ); // The session never resolves its exit (script exit = None); // the disconnect is the connection-level cancel: the serving - // task aborts the alktty session — the kill-on-drop witness + // task aborts the alktty session (the kill-on-drop witness // recorded, nothing fabricated on the wire. session.unmount().await; for _ in 0..100 { @@ -771,7 +771,7 @@ mod serving { } assert!( !shim.observation().kills.lock().is_empty(), - "the cancellation aborted the never-resolving session — \ + "the cancellation aborted the never-resolving session; \ alktty's kill-on-drop contract fired" ); } @@ -787,7 +787,7 @@ mod serving { let session = session_with(shim_seam(&shim)).await; // Pre-serve resize: after the pty is stored, before the shell - // request — the stored params resize (the final size wins). + // request; the stored params resize (the final size wins). let channel = open_session_channel(&session.client) .await .expect("the session channel opens"); @@ -840,7 +840,7 @@ mod serving { .await .expect("the signal rides (fire-and-forget)"); let name = await_signal(&shim).await; - assert_eq!(name, "TERM", "accepted verbatim — no alkssh-side filter"); + assert_eq!(name, "TERM", "accepted verbatim, no alkssh-side filter"); session.unmount().await; } @@ -853,7 +853,7 @@ mod serving { /// ≥ 0 → `exit-status(N)`; negative `−N`, N ≥ 2 → /// `exit-signal(name)` via the table; POC-3 §D.2's `−15` → /// `TERM` live evidence) + rules 3 (the `−1` sentinel → 255, - /// never a signal claim) — each rule's wire row. `core_dumped` + /// never a signal claim); each rule's wire row follows. `core_dumped` /// is never asserted (the bool stays false). #[tokio::test] async fn exit_chunks_derive_by_the_contract_rules() { @@ -883,7 +883,7 @@ mod serving { assert!(matches!(signal_name, Sig::TERM), "rule 2: −15 → TERM"); assert!( !core_dumped, - "core_dumped is never asserted — the bool stays false" + "core_dumped is never asserted; the bool stays false" ); } ( @@ -913,7 +913,7 @@ mod serving { /// - *Contract stamp:* mapping.md §the seams + the task's /// negotiate-then-serve decision (the alktty error frame → - /// `negotiation-failed`, `exit-status(255)`, close — the one + /// `negotiation-failed`, `exit-status(255)`, close: the one /// could-not-start claim this door makes: nothing ran). #[tokio::test] async fn unknown_backend_answers_255_then_close() { @@ -958,7 +958,7 @@ mod serving { assert_eq!( ids, vec!["ssh-rider".to_owned()], - "the resolved identity rode to drive_session_pre_negotiated — \ + "the resolved identity rode to drive_session_pre_negotiated; \ the parked wave-2 identity-landing item asserted live" ); session.unmount().await; @@ -1009,7 +1009,7 @@ mod unset_declines { use russh::client::Msg; use russh::{Channel, ChannelMsg}; - /// An authenticated loopback over a mutated config — the + /// An authenticated loopback over a mutated config, the /// unset-field rows' driver. async fn session_with(mutate: impl FnOnce(&mut ServeConfig)) -> LoopbackSession { let provider = Arc::new(MemIdentityProvider::new()); @@ -1049,7 +1049,7 @@ mod unset_declines { } /// - *Contract stamp:* OQ-08 (`shell_argv` unset → `shell_request` - /// declines — never a fallback) + the recorded wire shape (the + /// declines, never a fallback) + the recorded wire shape (the /// serving-path decline: failure then close, from a spawned /// task). #[tokio::test] @@ -1129,7 +1129,7 @@ mod unset_declines { mod real_tool { //! The real-tool smoke (`w3-tty-session`): one OpenSSH pty //! session (`ssh -tt`, a real PTY via a dev-dep alktty `local` - //! composition — the posture decided: the session rows' smoke + //! composition, the posture decided: the session rows' smoke //! composes the REAL backend, not the shim, because a plain shim //! row cannot observe what vanilla OpenSSH actually sends; POC-3 //! stage D proved the same composition) through a TCP-mounted @@ -1152,7 +1152,7 @@ mod real_tool { use super::common::harness::serve_config as harness_serve_config; use super::common::{MemIdentityProvider, fixture, identity}; - /// The `local` composition for the smoke — alktty's own backend in + /// The `local` composition for the smoke: alktty's own backend in /// the seam map (dev-dep unification: the `local` feature rides the /// test graph only). fn local_seam() -> SessionSeam { @@ -1171,11 +1171,11 @@ mod real_tool { #[tokio::test] async fn real_openssh_pty_session_smoke() { if Command::new("ssh").arg("-V").output().is_err() { - eprintln!("SKIPPED (with reason): real-tool pty smoke — ssh is unavailable"); + eprintln!("SKIPPED (with reason): real-tool pty smoke, ssh is unavailable"); return; } if Command::new("sh").arg("-c").arg("exit 0").output().is_err() { - eprintln!("SKIPPED (with reason): real-tool pty smoke — sh is unavailable"); + eprintln!("SKIPPED (with reason): real-tool pty smoke, sh is unavailable"); return; } @@ -1265,7 +1265,7 @@ mod real_tool { assert!( success, "vanilla OpenSSH's pty+shell session through the door exits 0 \ - (the exit chunk derived exit-status(0) before close) — stdout: {stdout:?}" + (the exit chunk derived exit-status(0) before close); stdout: {stdout:?}" ); } } diff --git a/tests/tunnel_mapping.rs b/tests/tunnel_mapping.rs index 53c59ef..85dd47c 100644 --- a/tests/tunnel_mapping.rs +++ b/tests/tunnel_mapping.rs @@ -1,13 +1,13 @@ -//! The `w3-tunnel-direct` contract rows — the tunnel branch served for +//! The `w3-tunnel-direct` contract rows: the tunnel branch served for //! real: the route-1 bridge (ADR-006 decision 1) lands //! `direct-tcpip`/`direct-streamlocal` through the published alktunnels //! 0.5.0 seam (alkssh 0.2.0's W2 adoption: `TunnelSession::open_direct` //! → accept only after the fabric open succeeds → `take_halves()` //! pumped against the taken channel; the forwarded serving surface on -//! the establisher shape — the `ForwardedGate` correlation gate), +//! the establisher shape, the `ForwardedGate` correlation gate), //! observed through the loopback harness against the **fabric //! double** (`w3-tunnel-direct`'s recorded test composition: the -//! POC-3 §C.4 in-process recipe — `ChannelsAdapter` + +//! POC-3 §C.4 in-process recipe (`ChannelsAdapter` + //! `InstallChannelZero` + the alktunnels openables + a hand-rolled //! dial/dial-fail seam, hand-rolled here, never a sibling-checkout //! path). @@ -21,19 +21,19 @@ //! the release mechanism: an admitted-but-rejected bridge releases its //! count, a closed serving channel recovers), the composed identity //! gate (the fabric's `AccessControl::check` refusing an unscoped -//! channels identity — the visible-surface invariant's alkcall half, +//! channels identity, the visible-surface invariant's alkcall half, //! with the establisher never reached), the establisher's identity //! witness (the POC-3 §C.3 shape), the OQ-11 off-Unix gate, and the //! real-tool `ssh -L` smoke. //! //! The fabric double's dial seam is in-process by design: the dial //! target is matched against a map of pre-created duplex halves keyed -//! by the rendered target string (`host:port` / socket path — exactly +//! by the rendered target string (`host:port` / socket path, exactly //! the shape the establisher hands the `DialFn`), so the serve rows //! are fully deterministic (no sockets on the target substrate), while //! the real-tool smoke hand-rolls a real-TCP dial closure against a //! real loopback endpoint (the smoke exercises the substrate for real; -//! tooling posture recorded like the git task — skipped-with-reason +//! tooling posture recorded like the git task, skipped-with-reason //! when `ssh`/`curl` is unavailable, never silently green). #![allow(dead_code)] @@ -85,7 +85,7 @@ mod serving { /// tunnel-featured serve-config holds. The accept side's channel-0 /// identity (`caller`) is what the fabric's /// `AccessControl::check(peer_identity)` gates the mapped opens - /// against — the assembly-composed identity of the real deployment; + /// against, the assembly-composed identity of the real deployment; /// `witness` records what the establisher's per-call auth (alkcall /// CF-006) saw. pub(super) async fn wire_fabric( @@ -109,7 +109,7 @@ mod serving { return; }; let (writer, reader) = split_single_stream(channel0_bidi); - // The serving-side identity set once at install — the + // The serving-side identity set once at install, the // hub_leg.rs one-time-set precedent the door's // `set_identity` mechanics decision reads (the identity // the serving dispatch resolves for the mapped opens' @@ -159,7 +159,7 @@ mod serving { /// The leg-2 fabric double (`w3-tunnel-listen`'s recorded /// composition): the leg-1 wire fabric extended with the - /// **bind-first listen half** — the assembly-composed shape the + /// **bind-first listen half**, the assembly-composed shape the /// vanilla `-R` listen flow rides, built exactly on the published /// alktunnels pieces: a `bindfirst_establisher`-shaped /// establisher, `make_bindfirst_accept_handler`, and the @@ -175,7 +175,7 @@ mod serving { /// wire-mapped resource string as the bind endpoint directly /// (`resource = "127.0.0.1:9200"` binds `127.0.0.1:9200`) and mints /// the correlation token per the ADR-008 discipline. Who may bind - /// what is the fabric's policy — the double binds what the room + /// what is the fabric's policy: the double binds what the room /// asks; a real fabric's ACL is the same seam. `localhost` /// renders to `127.0.0.1` so the real-tool smoke's curl is /// deterministic about the family. @@ -184,7 +184,7 @@ mod serving { pub(super) registry: Arc, opener: Arc>, /// The establisher's mint stream (the rows' real-token vehicle - /// — the ACL row needs the genuinely minted token its listen's + /// which the ACL row needs; the genuinely minted token its listen's /// fabric established; the SSH layer never carries the token). minted: tokio::sync::Mutex>, } @@ -192,7 +192,7 @@ mod serving { impl FabricDouble { /// The fabric's `ForwardedOpener` (the call plane), exported /// for the rows' direct drives (an arrival the fabric would - /// make, dialed by the row itself — the unknown-token and + /// make, dialed by the row itself (the unknown-token and /// composed-gate rows' vehicle). pub(super) async fn forwarded_opener(&self) -> ForwardedOpener { for _ in 0..600 { @@ -206,13 +206,13 @@ mod serving { /// Drives the fabric's forwarded-open closure directly: /// `Ok` carries the adopted fabric-side halves (the door - /// allocated the channel — the gate-pass/residual-race + /// allocated the channel, so the gate-pass/residual-race /// teardown-at-birth is then observable as an EOF on the /// `recv` half), `Err` is the door-side refusal (the /// unknown-token gate miss / the composed-gate row's ACL - /// answer — the arrival never became anything). + /// answer; the arrival never became anything). /// The next minted correlation token (one per accepted listen, - /// in mint order — the rows' real-token vehicle). + /// in mint order (the rows' real-token vehicle). pub(super) async fn minted_token(&self) -> u32 { self.minted .lock() @@ -240,7 +240,7 @@ mod serving { /// The double's establisher mint discipline: `Counter` is the /// ADR-008 shape the real fabric carries (a non-zero-seeded /// counter, never 0, never re-minted); `WithCollisions` is the - /// row-pinned collision construct — the first `collisions` mints + /// row-pinned collision construct; the first `collisions` mints /// return a fixed `token` (the test forces what the fabric's /// discipline prevents), then the counter continues from where it /// left. @@ -306,7 +306,7 @@ mod serving { /// The double's real-socket bind seam: real TCP/unix binds of the /// wire-named endpoint (the platform boundary the - /// `tunnels/local` feature serves in a real deployment — + /// `tunnels/local` feature serves in a real deployment, /// hand-rolled here, never a sibling-checkout path). Unix binds /// unlink a stale socket file first (`bind_unix`'s caller /// posture). @@ -357,7 +357,7 @@ mod serving { /// invocation (the dispatcher's per-accept contract), downcasting /// the plan's opaque listener to the bind seam's own wrappers. The /// unix leg's `peer` is fabricated (an unnamed peer cannot ride - /// the forwarded op's required `peer` param — the shipped + /// the forwarded op's required `peer` param (the shipped /// accept-pair posture). fn real_accept_loop() -> BindFirstAcceptLoop { Arc::new(move |listener: Arc| { @@ -412,7 +412,7 @@ mod serving { .await } - /// Wires the leg-2 fabric double (leg 1 unchanged underneath — the + /// Wires the leg-2 fabric double (leg 1 unchanged underneath, the /// dial seam + direct openable stay exactly `wire_fabric`'s /// composition, against a leg-1 fail dial the -R rows never /// exercise). `door_scoped_caller` composes the fabric-side @@ -420,7 +420,7 @@ mod serving { /// `arrival_scoped` composes the door-side `ServingConfig.identity` /// with or without the `tunnel:forwarded` scope (the composed-gate /// row's negative leg). `mint` is the establisher's mint - /// discipline ([`MintStrategy`]) — the collision rows' vehicle. + /// discipline ([`MintStrategy`]), the collision rows' vehicle. pub(super) async fn wire_fabric_with_listen_mint( door_scoped_caller: bool, arrival_scoped: bool, @@ -428,9 +428,9 @@ mod serving { ) -> FabricDouble { // The two sides' registries are independent (the fabric's own // dispatch registry; and the DOOR-side shared one the row - // hands alkssh's seam — the registration into the fabric's + // hands alkssh's seam; the registration into the fabric's // registry would be the silent-fork shape). The earlier draft - // wired one Arc to both — pinned wrong here for exactly one + // wired one Arc to both, pinned wrong here for exactly one // reason: the door's `tunnel/forwarded` openable must live in // the DOOR's dispatch surface alone. let door_registry = Arc::new(OperationRegistry::new()); @@ -499,7 +499,7 @@ mod serving { .await; // The real opener maps the wire refusal's // reason through the `From for EstablishmentError` table — the + // Error> for EstablishmentError` table; the // typed `unknown_resource` (the gate's miss // class) must survive the client side here, // so the double maps the details.reason back @@ -622,7 +622,7 @@ mod serving { } } - /// A pre-created duplex target — the "in-process dial" half: the + /// A pre-created duplex target, the "in-process dial" half: the /// test holds the returned side, the map hands the dial seam the /// other half when the establisher renders a matching target. fn inproc_target(targets: &TargetMap, key: &str, capacity: usize) -> tokio::io::DuplexStream { @@ -637,7 +637,7 @@ mod serving { /// The hand-rolled dial seam (the assembly's injected `DialFn`, /// doubled): an exact `host:port` / socket-path key pops the /// pre-created half; an absent key is the dial-fail seam - /// (`TunnelEstablishError::DialFailed`) — both the fabric-failure + /// (`TunnelEstablishError::DialFailed`); both the fabric-failure /// rows' shape and the release rows' failure leg. The call counter /// witnesses the "no fabric call" assertions. fn inproc_dial(targets: TargetMap, calls: Arc) -> DialFn { @@ -665,7 +665,7 @@ mod serving { }) } - /// The fabric caller identity with the direct op's scope — the + /// The fabric caller identity with the direct op's scope, the /// composed-gate identity the serving side resolves, so the ACL /// admits the mapped opens. fn scoped_caller() -> Identity { @@ -707,7 +707,7 @@ mod serving { /// (kept near the top of the module for the rows' readability). use super::common::harness::authenticate_publickey; - /// Matches an open failure's SSH reason — the wire decline reason + /// Matches an open failure's SSH reason, the wire decline reason /// the rows assert. fn open_failure(err: Error, expected: ChannelOpenFailure, context: &str) { assert!( @@ -717,7 +717,7 @@ mod serving { } /// The serve row's data leg: the SSH channel against the in-process - /// target — one request down `direct-tcpip`, one reply back (the + /// target: one request down `direct-tcpip`, one reply back (the /// bidirectional pump of the route-1 bridge, the POC-3 §C.1 shape: /// zero framing, both directions live). async fn round_trip( @@ -773,7 +773,7 @@ mod serving { /// - *Contract stamp:* ADR-006 decision 1 (the route-1 bridge: the /// `direct-tcpip` open → `TunnelSession::open_direct` over a held /// `ChannelClient` → accept only after the fabric open succeeds → - /// `take_halves()` pumped bidirectionally — the POC-3 §C.1 shape, + /// `take_halves()` pumped bidirectionally (the POC-3 §C.1 shape, /// zero framing both directions; the open hook returns fast). #[tokio::test] async fn direct_tcpip_serves_through_the_route_1_bridge() { @@ -850,7 +850,7 @@ mod serving { } /// - *Contract stamp:* ADR-006 decision 1 (fabric-open failure → - /// the explicit `ConnectFailed` reject — accept only after the + /// the explicit `ConnectFailed` reject (accept only after the /// fabric open succeeds; the wave-2 stub's reason surviving as /// the real decline; POC-3 §C.2's failure shape). #[tokio::test] @@ -876,7 +876,7 @@ mod serving { assert_eq!( calls.load(Ordering::SeqCst), 1, - "the bridge dialed the fabric exactly once — the SSH open carried the fabric's answer" + "the bridge dialed the fabric exactly once; the SSH open carried the fabric's answer" ); session.unmount().await; @@ -885,10 +885,10 @@ mod serving { /// - *Contract stamp:* `w3-tunnel-direct`'s recorded cap release /// mechanism (the admission is taken at the hook and held across /// the fabric open; a fabric failure releases the count **inside - /// the spawned task** — the `channel_close` release point only + /// the spawned task**; the `channel_close` release point only /// fires for established channels, so without this release a /// failed bridge would leak budget): a failed bridge under a - /// full cap does not strand the budget — the next open of the + /// full cap does not strand the budget; the next open of the /// same session is admitted (it would answer /// `AdministrativelyProhibited` if the count had leaked). #[tokio::test] @@ -922,7 +922,7 @@ mod serving { // of this same session observes the released count. let mut channel = open_direct_tcpip(&session.client, "127.0.0.1", 36002) .await - .expect("the next open is admitted — the failed bridge released its count"); + .expect("the next open is admitted; the failed bridge released its count"); round_trip( &mut channel, target_side, @@ -938,7 +938,7 @@ mod serving { /// - *Contract stamp:* AGENTS.md convention 9 / `overview.md` /// §Bounded-resources policy + `ChannelCap`'s recorded /// disjoint-release shape: a *closed serving* channel releases - /// through the `channel_close` hook — a full cap refuses with the + /// through the `channel_close` hook; a full cap refuses with the /// cap reason, and a recovered cap admits again. #[tokio::test] async fn the_cap_refuses_beyond_the_ceiling_and_recovers_on_close() { @@ -984,7 +984,7 @@ mod serving { // recovery is observable because the dial target is consumed // once: the moment the cap admits again, the open proceeds // onto the bridge (and fails at the fabric dial with the - // connect-failed class) — an `AdministrativelyProhibited` + // connect-failed class); an `AdministrativelyProhibited` // answer here would mean a leaked count. tokio::time::timeout(std::time::Duration::from_secs(10), async { let mut attempts = 0u32; @@ -1003,11 +1003,11 @@ mod serving { Err(Error::ChannelOpenFailure( ChannelOpenFailure::AdministrativelyProhibited, )) => { - panic!("the cap never recovered after the close — the count leaked") + panic!("the cap never recovered after the close; the count leaked") } Err(Error::ChannelOpenFailure(_)) => { // The open went past the cap answer and onto the - // bridge (the fabric dial's connect-failed) — the + // bridge (the fabric dial's connect-failed); the // released count is what this row observes. return; } @@ -1023,13 +1023,13 @@ mod serving { /// - *Contract stamp:* AGENTS.md convention 7 (the visible-surface /// invariant's alkcall half): the fabric's - /// `AccessControl::check(peer_identity)` gates the mapped open — + /// `AccessControl::check(peer_identity)` gates the mapped open: /// a channels connection whose identity lacks the direct op's /// scope is refused by the fabric's dispatch (`FORBIDDEN`), the /// establisher never runs, and the door answers the SSH open /// with the explicit `ConnectFailed`. The auth bridge's /// SSH-resolved identity and the fabric leg's dial identity - /// compose at the assembly (the deployment policy) — this row is + /// compose at the assembly (the deployment policy); this row is /// the composed-gate witness through the double. #[tokio::test] async fn the_fabric_acl_refuses_an_unscoped_channels_identity() { @@ -1056,7 +1056,7 @@ mod serving { assert_eq!( calls.load(Ordering::SeqCst), 0, - "the ACL check precedes the establisher — a refused open never dialed" + "the ACL check precedes the establisher; a refused open never dialed" ); session.unmount().await; @@ -1064,7 +1064,7 @@ mod serving { /// - *Contract stamp:* mapping.md §Channel-type rows (`direct-tcpip`'s /// target is the SSH open arguments verbatim; an impossible wire - /// target — a port outside the u16 space — is a declined + /// target, a port outside the u16 space, is a declined /// pre-admission, `invalid-target`, connect-failed on the wire). #[tokio::test] async fn an_out_of_range_wire_port_declines_pre_admission() { @@ -1097,7 +1097,7 @@ mod serving { /// - *Contract stamp:* OQ-11 (the runtime-Unix gate: universal /// compile, clean open-decline off-Unix **before any fabric - /// call** — never a partial bridge): this row compiles in this + /// call**, never a partial bridge): this row compiles in this /// binary only off-Unix and pins the gate with its dial-call /// witness at zero. On-Unix builds ride the serve row above. #[cfg(not(unix))] @@ -1125,7 +1125,7 @@ mod serving { assert_eq!( calls.load(Ordering::SeqCst), 0, - "the runtime gate precedes any fabric call — no partial bridge" + "the runtime gate precedes any fabric call; no partial bridge" ); session.unmount().await; @@ -1188,7 +1188,7 @@ mod serving { /// The arrival row's pump legs: the arrival's request reaches the /// forwarded SSH channel, the channel's reply reaches the arrival - /// socket — the fabric `BiStream` ↔ SSH channel duplex, zero + /// socket: the fabric `BiStream` ↔ SSH channel duplex, zero /// framing both directions (the route-1 bridge's primitive, /// reversed). async fn arrival_pump( @@ -1231,8 +1231,8 @@ mod serving { /// (`tcpip_forward` → the family-ward listen dial) + §Channel-type /// rows, the `forwarded-tcpip` row (the data leg: per fabric /// arrival the door opens a `forwarded-tcpip` channel **toward - /// the vanilla client**, echoing the listen request's own args — - /// the OpenSSH matcher parity — and pumping the fabric + /// the vanilla client**, echoing the listen request's own args + /// (the OpenSSH matcher parity) and pumping the fabric /// `BiStream` ↔ the SSH channel). Observed end to end through the /// harness's accept hook. #[tokio::test] @@ -1302,10 +1302,10 @@ mod serving { /// - *Contract stamp:* `client.md` §Lifecycle primitives (the /// bound-port spec: `port = 0` → the server picks and the - /// actually-bound number returns) — the out-param carries the + /// actually-bound number returns); the out-param carries the /// fabric's `bound` reply field's port, and the arrival's echo /// port is that same allocated number (sshd's `get_local_port` - /// parity — a forwarded open for a `0`-minted listener never + /// parity: a forwarded open for a `0`-minted listener never /// claims port 0). #[tokio::test] async fn port_zero_mint_is_resolved_into_the_bound_port_out_param() { @@ -1356,11 +1356,11 @@ mod serving { } /// - *Contract stamp:* the cancel forms (`cancel_tcpip_forward`): - /// 1:1 into the family listener's teardown — the matching listen + /// 1:1 into the family listener's teardown; the matching listen /// cancels `Ok`, the fabric's bound listener goes away (a /// re-connect is refused), and a second cancel of the same /// (address, port) pair answers the not-found denial - /// (`RequestDenied` — the sshd cancel-of-unknown parity). + /// (`RequestDenied`, the sshd cancel-of-unknown parity). #[tokio::test] async fn cancel_tcpip_forward_tears_the_fabric_listener_down() { let double = wire_fabric_with_listen(true, true).await; @@ -1385,7 +1385,7 @@ mod serving { // The fabric listener is gone (the teardown cascaded: the // door's listener session dropped, the far accept loop's EOF - // sentinel fired, the plan's listener dropped — the bind + // sentinel fired, the plan's listener dropped, the bind // releases). Bounded retry: the connect is refused. tokio::time::timeout(Duration::from_secs(10), async { loop { @@ -1415,10 +1415,10 @@ mod serving { /// upstream guarantee the door defends in depth against: the /// test forces what the discipline prevents (the double /// re-mints a live token), and the second listen **refuses - /// fail-closed** — `RequestDenied`, its minted fabric listener + /// fail-closed** (`RequestDenied`), its minted fabric listener /// torn down immediately (the refused registration never left a /// half state), the listener cap released (the next mint is - /// admitted against the same 1-count ceiling) — and the **first + /// admitted against the same 1-count ceiling), and the **first /// route still serves**: the collided mint can never steal a /// live adapter's arrival routes. #[tokio::test] @@ -1434,7 +1434,7 @@ mod serving { .await; // The ceiling of 2 both admits the collided mint past the // listener cap (so the refusal is the route register, not the - // cap — the cap row's shape) and makes the refusal's cap + // cap, the cap row's shape) and makes the refusal's cap // release observable: without the release, the third mint // would be cap-exceeded. let limits = Limits { @@ -1475,16 +1475,16 @@ mod serving { .expect("the refused listen's fabric listener was torn down"); // The listener count was released at the refusal: against the - // same 2-count ceiling, the next mint (a fresh token — the + // same 2-count ceiling, the next mint (a fresh token, since // collision was two mints on one listen, not a broken fabric) // is admitted and registers normally (a `0` mint's success - // reply carries the actually-bound number — the sshd parity). + // reply carries the actually-bound number, the sshd parity). let third = tcpip_forward(&session.client, "127.0.0.1", 0) .await .expect("the collision released the listener count"); assert_ne!(third, 0); - // The first route still serves — the steal is impossible: an + // The first route still serves; the steal is impossible: an // arrival onto the live route's endpoint opens the // forwarded-tcpip channel and the bytes ride the pump. let mut arrival = tokio::net::TcpStream::connect(("127.0.0.1", port_a)) @@ -1518,7 +1518,7 @@ mod serving { // Nothing rode the acceptor beyond the live route's served // arrival (the refused mint's listener was torn down at birth - // — its arrivals could not exist). + // so its arrivals could not exist). tokio::time::timeout(Duration::from_millis(500), opens.recv()) .await .expect_err("no arrival may follow the refused mint"); @@ -1532,8 +1532,8 @@ mod serving { /// whose `listen` token has no route (nothing was ever minted for /// this door) fails the open at the call plane as a typed /// `channel:open_failed` (`TunnelEstablishError::UnknownResource` - /// — the wire's `unknown_resource` reason) **before any channel - /// is born** — the phantom-channel shape (call-plane success, + /// the wire's `unknown_resource` reason) **before any channel + /// is born**; the phantom-channel shape (call-plane success, /// then handler-side decline) is closed at the open: no channel /// allocation, no adopted halves, no acceptor row. #[tokio::test] @@ -1552,7 +1552,7 @@ mod serving { let outcome = double.open_forwarded_directly(params).await; let err = match outcome { Ok(_) => { - panic!("the gate miss fails the open typed — no phantom channel exists to adopt") + panic!("the gate miss fails the open typed; no phantom channel exists to adopt") } Err(error) => error, }; @@ -1561,7 +1561,7 @@ mod serving { "expected UnknownResource at the call plane, got {err:?}" ); - // No arrival rode the acceptor — the open died at the call + // No arrival rode the acceptor (the open died at the call // plane; the handler never ran. tokio::time::timeout(Duration::from_millis(500), opens.recv()) .await @@ -1573,7 +1573,7 @@ mod serving { /// - *Contract stamp:* the forwarded gate's pass posture (alktunnels /// 0.5.0, review 003 W2 adoption): an arrival whose token is - /// genuinely routed behaves exactly as the base shape did — the + /// genuinely routed behaves exactly as the base shape did; the /// open succeeds at the call plane, the door allocates the SSH /// channel at the acceptor, and the fabric-side halves are the /// arrival's data plane (the gate adds an establishment phase; @@ -1643,13 +1643,13 @@ mod serving { /// - *Contract stamp:* AGENTS.md convention 7 (the visible-surface /// invariant's alkcall half on the `-R` leg): the door-side /// registry's `AccessControl::check` gates arrivals by the fabric - /// caller's identity — an identity lacking the + /// caller's identity (an identity lacking the /// `tunnel:forwarded` scope is refused by alkcall's dispatch (the /// openable's own spec) and no SSH channel opens, even for a /// genuinely minted token. The genuinely-minted-token shape /// double-pins the gate ordering now (the establisher variant's /// pinned order, alktunnels 0.5.0 / ADR-008 Amendment 2): the ACL - /// refuses before the establisher's gate ever looks up the token — + /// refuses before the establisher's gate ever looks up the token; /// an unscoped arrival could not leak a gate pass. #[tokio::test] async fn the_door_side_acl_refuses_an_unscoped_arrival() { @@ -1664,7 +1664,7 @@ mod serving { ); // A real token (minted for this listener), unscoped arrival - // identity: the door-side ACL refuses the open op — the fabric + // identity: the door-side ACL refuses the open op, and the fabric // side sees the refusal, never a channel allocation. let token = double.minted_token().await; let params = alktunnels::params::TunnelForwardedParams { @@ -1693,7 +1693,7 @@ mod serving { /// - *Contract stamp:* AGENTS.md convention 9 (the listener count /// is a bounded resource): the per-session listener map is /// bounded through its dedicated counter against the same - /// `max_concurrent_channels` ceiling — the listen beyond the + /// `max_concurrent_channels` ceiling; the listen beyond the /// count answers the vanilla `RequestDenied` while channels stay /// free, and the cancel releases the count again. #[tokio::test] @@ -1739,10 +1739,10 @@ mod serving { /// - *Contract stamp:* AGENTS.md convention 9 / the acceptor /// vocabulary's cap rows (the wave-2 gate's booked shape): the /// per-arrival admission is the owning session's in-crate - /// channel cap — an arrival onto an exhausted count is refused + /// channel cap: an arrival onto an exhausted count is refused /// at the accept surface (no SSH channel opens; the fabric half /// drops, teardown-at-birth), and an established channel's close - /// recovers the count (the next arrival is admitted — the + /// recovers the count (the next arrival is admitted, the /// release proof). #[tokio::test] async fn the_arrival_admission_is_cap_gated_at_the_accept_surface() { @@ -1791,12 +1791,12 @@ mod serving { .expect_err("the refused arrival's socket EOFs"); let _ = eof; - // The release proof: the first arrival's socket goes — the + // The release proof: the first arrival's socket goes; the // pump's fabric→SSH direction EOFs (the pump's - // shutdown-on-completion half-closes the SSH channel — the + // shutdown-on-completion half-closes the SSH channel; the // OpenSSH client, whose target socket died with the arrival, // closes its half; the harness's stand-in does exactly that). - // That close — not the pump — is what fires the packet loop's + // That close (not the pump) is what fires the packet loop's // established-channel release. drop(first_arrival); let _ = first_channel.close().await; @@ -1807,7 +1807,7 @@ mod serving { third_arrival.write_all(b"again").await.expect("rides"); let third_open = tokio::time::timeout(Duration::from_secs(15), opens.recv()) .await - .expect("the next arrival's open arrives — the released count recovered") + .expect("the next arrival's open arrives; the released count recovered") .expect("observed"); let ForwardedOpen::Tcpip { channel: mut third_channel, @@ -1836,7 +1836,7 @@ mod serving { /// - *Contract stamp:* OQ-11 on the listen flow (the runtime-Unix /// gate riding the `streamlocal_forward` serving flow) + the unix /// row of the `-R` leg: the unix listen serves through the fabric - /// (the path echoes verbatim — no port semantics, no port + /// (the path echoes verbatim; no port semantics, no port /// out-param), the arrival opens /// `forwarded-streamlocal@openssh.com` toward the client, and the /// cancel form tears it down 1:1 (path-matched). @@ -1908,7 +1908,7 @@ mod serving { } /// - *Contract stamp:* the unset-declines contract on the listen - /// seam (`w3-tunnel-listen`'s whole-`Option` shape — an + /// seam (`w3-tunnel-listen`'s whole-`Option` shape; an /// egress-only door is legitimate config): a `tunnel` build with /// a fabric leg but no `tunnel_listen_seam` declines every listen /// form with the vanilla `RequestDenied`, while the leg-1 rows @@ -1952,7 +1952,7 @@ mod serving { assert!(matches!(err, Error::RequestDenied), "got {err:?}"); // The egress door still routes: the direct row reaches the - // fabric (the fail-dial class — `ConnectFailed`, not + // fabric (the fail-dial class `ConnectFailed`, not // `AdministrativelyProhibited`). let err = open_direct_tcpip(&session.client, "127.0.0.1", 36005) .await @@ -1970,7 +1970,7 @@ mod serving { /// one-per-op-per-registry (mapping.md §Global-request rows / the /// `install_forwarded_surface` claim): alkcall's `register` /// silently replaces an existing op entry, so the door - /// pre-checks — a second `SshAdapter` composed over the same + /// pre-checks; a second `SshAdapter` composed over the same /// shared seam registry is a **failed construction** /// (`AdapterError::ListenRegistration`), never a silent steal of /// the first adapter's arrival routes. @@ -2011,7 +2011,7 @@ mod serving { mod client_smoke { //! The full-circle smoke (`w4-reverse-listen`'s recorded posture): //! the **alkssh client's** `-R` rows against the **alkssh server - //! direction's** `-R` rows — both directions of the crate in one + //! direction's** `-R` rows, both directions of the crate in one //! live wire, the route-1 bridge's two legs meeting through the //! alkcall fabric double (the composition the alkforge assembly //! makes). A connection to the minted bound port round-trips @@ -2174,7 +2174,7 @@ mod client_smoke { #[cfg(all(feature = "tunnel", unix))] mod real_tool { //! The real-tool smoke (`w3-tunnel-direct`): one `ssh -L` (+ curl) - //! through a TCP-mounted adapter against the fabric double — the + //! through a TCP-mounted adapter against the fabric double, the //! POC-3 §C.1 gate re-landed. Tooling posture (recorded, like the //! git task's): the smoke requires `ssh`/`curl` in the environment; //! when absent it is **skipped with a printed reason** @@ -2191,7 +2191,7 @@ mod real_tool { use super::serving::{wire_fabric, wire_fabric_with_listen}; use alkssh::TunnelListenSeam; - /// The smoke's dial seam: a real-TCP dial closure (hand-rolled — + /// The smoke's dial seam: a real-TCP dial closure (hand-rolled; /// the assembly's `DialFn` injected over the substrate for real; /// alktunnels' `local` feature stays off). fn tcp_dial() -> DialFn { @@ -2210,7 +2210,7 @@ mod real_tool { }) } - /// A tiny HTTP/1.1 endpoint (the POC's shape) — the substrate the + /// A tiny HTTP/1.1 endpoint (the POC's shape), the substrate the /// forwarded traffic dials through the fabric. async fn spawn_http_endpoint() -> (std::net::SocketAddr, String) { let listener = tokio::net::TcpListener::bind("127.0.0.1:0") @@ -2248,7 +2248,7 @@ mod real_tool { .output() .is_err() { - eprintln!("SKIPPED (with reason): real-tool tunnel smoke — ssh is unavailable"); + eprintln!("SKIPPED (with reason): real-tool tunnel smoke, ssh is unavailable"); return; } if std::process::Command::new("curl") @@ -2256,7 +2256,7 @@ mod real_tool { .output() .is_err() { - eprintln!("SKIPPED (with reason): real-tool tunnel smoke — curl is unavailable"); + eprintln!("SKIPPED (with reason): real-tool tunnel smoke, curl is unavailable"); return; } @@ -2371,7 +2371,7 @@ mod real_tool { let stdout = String::from_utf8_lossy(&through.stdout).to_string(); assert!( through.status.success() && stdout.trim_end() == body.trim_end(), - "vanilla ssh -L + curl through the door → fabric → endpoint returns the body — got {stdout:?}" + "vanilla ssh -L + curl through the door → fabric → endpoint returns the body; got {stdout:?}" ); let _ = std::fs::remove_dir_all(&work); @@ -2409,7 +2409,7 @@ mod real_tool { .output() .is_err() { - eprintln!("SKIPPED (with reason): real-tool -R smoke — ssh is unavailable"); + eprintln!("SKIPPED (with reason): real-tool -R smoke, ssh is unavailable"); return; } if std::process::Command::new("curl") @@ -2417,7 +2417,7 @@ mod real_tool { .output() .is_err() { - eprintln!("SKIPPED (with reason): real-tool -R smoke — curl is unavailable"); + eprintln!("SKIPPED (with reason): real-tool -R smoke, curl is unavailable"); return; } @@ -2524,7 +2524,7 @@ mod real_tool { let stdout = String::from_utf8_lossy(&through.stdout).to_string(); assert!( through.status.success() && stdout.trim_end() == body.trim_end(), - "vanilla ssh -R + curl through the fabric → arrival → forwarded-tcpip → client-dialed endpoint returns the body — got {stdout:?}" + "vanilla ssh -R + curl through the fabric → arrival → forwarded-tcpip → client-dialed endpoint returns the body; got {stdout:?}" ); } diff --git a/tests/vectors/fingerprints.txt b/tests/vectors/fingerprints.txt index 9d532c9..674df45 100644 --- a/tests/vectors/fingerprints.txt +++ b/tests/vectors/fingerprints.txt @@ -1,12 +1,12 @@ # Independent-issuer fingerprint vectors: the alkssh wave-1 test-key # fixture set. Each entry pairs a committed OpenSSH ed25519 keypair (the # .key/.pub files in this directory) with its fingerprint byte-verbatim -# from `ssh-keygen -lf` — recorded from OpenSSH_9.6p1 +# from `ssh-keygen -lf`, recorded from OpenSSH_9.6p1 # (Ubuntu-3ubuntu13.20) at vector-generation time. # # The keys are throwaway test fixtures minted for the test suite only; # their private halves are committed on purpose (committed keys are -# throwaway fixtures, not secrets — they are never registered anywhere +# throwaway fixtures, not secrets; they are never registered anywhere # real and never deployed). # # @@ -16,7 +16,7 @@ charlie.pub SHA256:b5jdwosbZUx5nsY5zfr/ZCt+4sJYehVBq7Xl/wstJ9U delta.pub SHA256:4MiQ0KGoTEaklHBTlxPDuQkeu0FTyqEbne10K6Z8CKs ca.pub SHA256:mPAq1aRKBuyH3gZs9IcLWtc1X3AhYi50P80mpo7XPSw # alpha-cert.pub: the alpha user certificate (serial 1, key id -# `alkssh-fixture-alpha`, principal `git`, validity 2026–2036) — the +# `alkssh-fixture-alpha`, principal `git`, validity 2026–2036): the # ssh-keygen output above the fingerprint line is its OpenSSH text; the # certificate's embedded public half is alpha.pub (the same fingerprint # as alpha.pub; `ssh-keygen -lf alpha-cert.pub` reports it with the