docs(comments): sweep em dashes from source comments, test prose, and manifest

Same treatment for the prose the compiler carries: doc and line comments
across src/ and tests/, test assertion and error-message strings (prose
surfaces: the tunnel-map registration/establish errors, the key-source
decode payload, assertion messages), scripts/matrix.sh comment lines,
the fuzz sidecar's comments and README (corpus seeds untouched), and the
Cargo.toml comment headers plus the crates.io description. The AGENTS.md
no-em-dash rule (convention 14) now holds for the whole tracked tree.

Verification: repo-wide git grep is clean (single exempt hit: the
verification command's own search pattern), cargo test (18 suites, zero
failures, default and per-feature builds via scripts/matrix.sh), clippy
--all-targets -D warnings and clippy all-features, fmt --check, doc
--no-deps, and the fuzz corpus gate (fuzz/shared, 11 tests) all green.
This commit is contained in:
glm-5.3-flash committed 2026-11-04 20:28:05 +00:00
1 parent f4b5f896b4
commit 1e583ab55b
55 files changed
+1756 -1751

No files matched your search

+23 -23
View File
@@ -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<MemIdentityProvider>,
limits: Limits,
@@ -109,7 +109,7 @@ fn registered_provider(fingerprints: &[&str]) -> Arc<MemIdentityProvider> {
}
/// - *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<MemIdentityProvider>) -> 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]
+16 -16
View File
@@ -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<MemIdentityProvider> {
}
/// 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<russh::MethodSet> {
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
+18 -18
View File
@@ -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<dyn KeySource> {
@@ -91,10 +91,10 @@ fn postured_key_source(posture: &'static str) -> (Arc<dyn KeySource>, 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.
///
+33 -33
View File
@@ -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<dyn alkssh::KeySource> {
let vault = TestVault::unlocked();
@@ -45,7 +45,7 @@ fn alpha_key_source() -> Arc<dyn alkssh::KeySource> {
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<u8> {
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<u8> {
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<u8>, Vec<u8>, Option<i32>) {
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() {
+41 -41
View File
@@ -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<dyn alkssh::KeySource> {
let vault = TestVault::unlocked();
@@ -50,7 +50,7 @@ fn alpha_key_source() -> Arc<dyn alkssh::KeySource> {
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<String>,
@@ -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<OpenRecord>,
@@ -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<_>>(),
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;
+11 -11
View File
@@ -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<GlobalCapture> {
static CAPTURE: OnceLock<Arc<GlobalCapture>> = 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<Captured> {
}
/// 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"),
+11 -11
View File
@@ -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<RepoRecord, RegistryError> {
match repos.get(id) {
@@ -325,7 +325,7 @@ impl GitPackIngest for MemGit {
}
/// Assembles the recording quartet into a
/// [`GitSeam`](alkssh::GitSeam) — one shared `Arc<MemGit>`, the
/// [`GitSeam`](alkssh::GitSeam) taking one shared `Arc<MemGit>`, the
/// default alkgit budget, the push-options gate off (the v1 default).
pub fn git_seam(mem: &Arc<MemGit>) -> alkssh::GitSeam {
alkssh::GitSeam {
+50 -50
View File
@@ -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<russh::client::Config> {
}
/// 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<MemHostKeyPolicy>) -> 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<HarnessClientHandler>,
/// 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<MemHostKeyPolicy>,
server_task: tokio::task::JoinHandle<Result<(), AdapterError>>,
@@ -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<MethodSet> {
match result {
@@ -526,7 +526,7 @@ pub fn remaining_methods(result: &AuthResult) -> Option<MethodSet> {
}
}
/// 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<HarnessClientHandler>,
@@ -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<HarnessClientHandler>,
@@ -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<Msg>, command: &str) -> Result<(), Error> {
@@ -587,19 +587,19 @@ pub async fn request_subsystem(channel: &Channel<Msg>, 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<Msg>) -> 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<Msg>, 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<Msg>) -> Result<(), Error> {
channel
@@ -607,16 +607,16 @@ pub async fn request_x11(channel: &Channel<Msg>) -> 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<Msg>) -> 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<HarnessClientHandler>,
@@ -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<Msg>) -> Option<ChannelMsg> {
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<Msg>) -> Option<u32> {
@@ -679,7 +679,7 @@ pub async fn await_exit_status(channel: &mut Channel<Msg>) -> Option<u32> {
}
}
/// 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<Msg>) -> bool {
+46 -45
View File
@@ -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/<name>.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 <blob>` 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<String> {
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<Identity> {
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<Identity> {
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<Decision> {
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
+54 -54
View File
@@ -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<DblExit>,
/// 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<Mutex<Vec<ListenRecord>>>,
}
/// 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<String> {
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<ListenRecord> {
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<Msg>) {
use tokio::io::{AsyncReadExt, AsyncWriteExt};
@@ -311,9 +311,9 @@ async fn direct_echo(mut stream: russh::ChannelStream<Msg>) {
/// 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<Msg>, 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<Msg>, 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<std::sync::atomic::AtomicUsize>,
/// 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<parking_lot::RwLock<Vec<String>>>,
@@ -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, `<ip>:<port>` — the row's
/// The dial target, `<ip>:<port>`, the row's
/// `DialConfig.address` value.
pub address: String,
session_carrier: Option<tokio::sync::oneshot::Receiver<Handle>>,
@@ -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<PrivateKey>,
@@ -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<PrivateKey>,
@@ -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<Channel<Msg>> {
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.
+22 -22
View File
@@ -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<Vec<u8>>,
/// 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<Vec<bool>>,
/// Resizes from the control handle (`cols`, `rows`).
pub resizes: parking_lot::Mutex<Vec<(u16, u16)>>,
/// Signals from the control handle — the name strings, verbatim.
/// Signals from the control handle, the name strings verbatim.
pub signals: parking_lot::Mutex<Vec<String>>,
/// 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<parking_lot::Mutex<Vec<bool>>>,
}
/// 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<i32>,
}
/// 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<NegotiateRequest>` 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<u8>]) -> Pin<Box<dyn tokio_stream::Stream<Item = Bytes> + 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<u8>]) -> Pin<Box<dyn tokio_stream::Stream<Item
Box::pin(ReceiverStream::new(rx))
}
/// The shim's stdin — an `AsyncWrite` recording bytes and the EOF
/// The shim's stdin, an `AsyncWrite` recording bytes and the EOF
/// shutdown (`poll_shutdown` = the zero-length sentinel's effect at
/// the backend).
struct ShimStdin {
@@ -239,7 +239,7 @@ impl Drop for GuardedExit {
}
}
/// The shim's control surface — records resizes and signals verbatim.
/// The shim's control surface; it records resizes and signals verbatim.
struct ShimControl {
observation: Arc<TtyShimObservation>,
}
@@ -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<TtyShim>) -> alkssh::SessionSeam {
let mut backends = HashMap::new();
@@ -270,12 +270,12 @@ pub fn tty_seam(shim: &Arc<TtyShim>) -> 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<Vec<String>>,
}
@@ -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<TtyShim>,
@@ -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 {
+43 -43
View File
@@ -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<Msg>, context: &str) {
match next_message(channel).await {
@@ -81,7 +81,7 @@ async fn expect_failure(channel: &mut Channel<Msg>, 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<Msg>, context: &str) {
expect_failure(channel, context).await;
@@ -91,7 +91,7 @@ async fn expect_failure_then_close(channel: &mut Channel<Msg>, 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<Msg>) {
common::harness::request_subsystem(channel, "sftp")
@@ -101,10 +101,10 @@ async fn expect_channel_alive(channel: &mut Channel<Msg>) {
}
// ---------------------------------------------------------------------------
// 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;
+12 -12
View File
@@ -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
+50 -50
View File
@@ -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<PathBuf> {
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, String> {
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<u8>, Vec<u8>, Option<i32>) {
@@ -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;
+53 -53
View File
@@ -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);
}
+9 -9
View File
@@ -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() {
+36 -35
View File
@@ -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<Msg> {
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<Msg>, 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<String> = 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<Msg>` 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"),
+6 -6
View File
@@ -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<MemHostKeyPolicy> {
/// 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() {
+28 -27
View File
@@ -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<GlobalCapture> {
})
}
/// 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<Captured> {
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<Msg>) {
"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;
}
+20 -20
View File
@@ -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<bool> {
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<bool>) {
@@ -65,7 +65,7 @@ async fn gate_wait(rx: &mut tokio::sync::watch::Receiver<bool>) {
}
}
/// 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<Instant>,
@@ -74,7 +74,7 @@ struct ProofRecord {
type Shared = Arc<Mutex<ProofRecord>>;
/// 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<HarnessClientHandler>,
@@ -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");
+42 -42
View File
@@ -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<Msg>) -> Option<Observed> {
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<Msg>, 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<td::TtyShim>) -> 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:?}"
);
}
}
+88 -88
View File
@@ -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<OperationRegistry>,
opener: Arc<tokio::sync::OnceCell<ForwardedOpener>>,
/// 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<mpsc::UnboundedReceiver<u32>>,
}
@@ -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<dyn std::any::Any + Send + Sync>| {
@@ -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<TunnelEstablish
// Error> 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<AtomicUsize>) -> 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:?}"
);
}
+3 -3
View File
@@ -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).
#
# <fixture> <expected fingerprint>
@@ -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