Commit Graph
14 Commits
Author SHA1 Message Date
glm-5.3-flash 196289f5ad feat(handler): enforce the in-crate concurrent-channel cap at the open surface (w2-bounded-resources)
- new private channel_cap module: per-session active-channel count;
  admit (check+increment at accept sites) / has_room / saturating
  release, single-writer (inline packet-loop hooks), unit-tested
- handler wires the cap at every channel_open_* hook: the session
  accept path admits-and-counts at the accept point; the tunnel rows
  cap-gate before the seam stub (a counted-but-unopened stub would
  leak the cap); x11 never consumes a count; the count releases
  through the new channel_close hook
- dispatch::cap_exceeded_open_decline -> AdministrativelyProhibited
  (the assembly's policy ceiling; OpenSSH MaxSessions parity)
- bounded-resources contract rows: cap reached -> clean decline,
  close -> recovery open succeeds (wire-order deterministic),
  zero cap refuses without poisoning, exhausted cap answers the
  tunnel row with the cap reason; max_auth_attempts verified
  behaviorally (within-ceiling failures keep the advertisement, the
  past-ceiling attempt is the NoMoreAuthMethodsAvailable teardown);
  window/packet/buffer/inactivity knobs recorded as covered by the
  config-mapping tests
- max_exec_command_len stays carried, not enforced (wave-3 grammar)

Verification: cargo test (default), --features session / git /
tunnel / --all-features, clippy --all-targets (-D warnings, also
--all-features), fmt --check, cargo doc --no-deps - all green
2026-10-28 11:40:29 +00:00
glm-5.3-flash 2e5a7c9cee feat(serve): land the spawn-and-return plumbing + exit/status mechanics (w2-spawn-return)
- src/serve.rs (new): the ADR-006 decision-4 mechanics in code —
  spawn_serving_path (the one choke point; nothing awaited inline)
  and report_exit_status_then_close (exit-status before close via
  the cloned Session::handle()), #[doc(hidden)] contract-test
  re-exports; a unit row pins spawn-returns-while-pending.
- src/handler.rs: the four session-row seam stubs became spawned
  serving paths (failure-then-close unchanged; stubs are plain fns —
  an async stub holding &Session across the spawn is non-Send); open-
  level declines and the tunnel seam stub stay inline by class, per
  the new module-doc section.
- tests/spawn_return.rs (new): two end-to-end wire rows — the client
  observes exit-status(7) strictly before close and after the handler
  returned; the handler-returns-fast row routes follow-up traffic
  while the serving path is still gated (POC-3 deadlock inversion).
- tasks/implementation/w2-spawn-return.md — completed with notes.

Verification (all green): cargo test; per-feature dispatch matrices
(--features git/session/tunnel/sftp, --all-features); cargo clippy
--all-targets/-all-features with -D warnings; cargo fmt --check;
cargo doc --no-deps (no warnings); taskgraph validate.
2026-10-28 11:04:17 +00:00
glm-5.3-flash 68d3723f6a feat(dispatch): land the parse-only dispatch + the fail-closed decline core (w2-dispatch-decline-core)
- src/dispatch.rs: the ExecRoute decision, the skeleton exec-parse
  probe (service prefix + path shape; wave 3 replaces with the full
  grammar), the wire-reason shapers (AdministrativelyProhibited for
  unfeatured/never-feature opens, ConnectFailed for the tunnel seam
  stub), 7 probe unit rows
- src/handler.rs: channel_open_* gates per the feature graph (session
  ∨ git; tunnel; x11/auth-agent never), parse-only exec_request
  dispatch before any allocation, session-row routes, request-level
  declines (subsystem all-names with the sftp OQ-13 and git named
  classes, env per OQ-09, x11/agent, the four listen requests), the
  named wave-3 seam stubs; decline-first-alloc-never structural;
  module docs carry the decline-core contract incl. the inherited
  auth-agent-open upstream note
- tests/dispatch_core.rs: 26 Contract-stamped decline-matrix rows per
  feature build driven through the loopback harness (none / git-only /
  session-only / tunnel-only / all-features + shared never-feature
  rows)
- tests/common/harness.rs: extended helper vocabulary (tunnel/x11
  opens, pty/env/x11/agent requests, listen requests) — discharges
  the w2-loopback-harness live-rows note
- tests/loopback_harness.rs: the skeleton decline-only session-open
  row cfg-pinned to the featureless builds it describes

Verification: cargo test (91 rows, default build); per-feature
dispatch_core rows (git 11 / session 10 / tunnel 4 / all 8 / sftp 3);
cargo test --all-features; cargo clippy --all-targets -- -D warnings
(and --all-features); cargo fmt --check; cargo doc --no-deps
2026-10-28 09:04:42 +00:00
glm-5.3-flash 2202149fc0 feat(auth): land the ADR-004 dispositional auth bridge (w2-auth-bridge)
- auth_publickey: ed25519-only gate → single fingerprint path →
  resolve_from_fingerprint → accept-with-identity (stored per-
  connection, read by wave 3) / reject fail-closed; the gate is
  explicit-over-inherited (ADR-002 decision 4) and precedes resolution
- auth_publickey_offered: explicit accept-and-delegate (counting
  stays honest, POC-1)
- auth_none / auth_password / auth_keyboard_interactive /
  auth_openssh_certificate: four explicit family-contract declines
- username carried by no hook — resolution is fingerprint-only (OQ-03)
- SessionHandler constructible via #[doc(hidden)] re-export (the
  w2-server-mount note's widening); resolve_bridge structured out of
  the #[non_exhaustive]-arg hooks so contract tests drive the bridge
  core directly
- tests/auth_bridge.rs: 21 rows — wire rows over the real adapter
  mount (accept, fail-closed reject, username independence, revoke
  between attempts, none/password/certificate declines) + direct
  rows over the wave-1 doubles
- cert fixture (throwaway ca + alpha-cert.pub) recorded in
  fingerprints.txt; MemHostKeySource double in tests/common

Verification: cargo test (76 across the suite), --all-features,
clippy --all-targets (both feature sets, -D warnings), fmt --check,
doc --no-deps, taskgraph validate — all green
2026-10-28 08:33:57 +00:00
glm-5.3-flash b90e89b600 feat(server): land the SshAdapter mount + russh Config construction (w2-server-mount)
- SshAdapter:🆕 decrypt-at-construction host-key load (ADR-005
  decision 6) — locked / absent / decryption / unknown-version /
  decode all refuse with AdapterError::Construction(KeySourceError
  preserved), no adapter; an empty key set refuses as Absent even
  from a custom source.
- russh 0.65 server Config built from ServeConfig: methods exactly
  {publickey} (MethodSet from [MethodKind::PublicKey] — honest
  advertisement, ADR-004 decision 4); host keys ride Config::keys;
  Limits knobs (window_size, maximum_packet_size,
  channel_buffer_size, max_auth_attempts) one-for-one;
  inactivity_timeout always Some (bounded-resources posture). All
  other knobs stay russh's default posture: rekey Limits (RFC-4253
  defaults, russh-enforced), auth_rejection_time, server_id
  (russh default — recorded), server keepalive (client-direction
  posture only).
- SshAdapter::handle: ADR-001 mount — generic duplex stream in,
  run_stream per stream, run to completion (Result<(), AdapterError>;
  no ALPN/relay code; the serving loop is spawned inside russh, so
  ADR-006's spawn-and-return holds without double-spawning).
- SessionHandler skeleton (pub(crate)): per-connection
  russh::server::Handler with type Error = AdapterError; every hook
  at the inherited fail-closed default; carries Arc<ServeConfig> for
  w2-auth-bridge / w2-dispatch-decline-core.
- AdapterError (error.rs): Construction + Wire (From<russh::Error>)
  — the wave-1 error-model's reserved wave-2 shape.
- Tests: advertisement-exactly-publickey; knob mapping (tuned +
  default postures); key-set parity; construction failure matrix;
  EOF-on-mount; wire smoke (russh client over duplex: full KEX,
  fail-closed auth decline, exactly the {publickey} method list on
  the wire).

Verified: cargo test (61 across suites), cargo test --all-features,
clippy --all-targets -- -D warnings (default + all-features),
fmt --check, cargo doc --no-deps, taskgraph validate.
2026-10-28 07:51:50 +00:00
glm-5.3-flash 1bd2588788 docs(src): wave-1 gate polish — rustdoc links, doc typos, redundant test lines
- resolve 2 rustdoc broken-intra-doc-link warnings (ambiguous
  'async_trait' crate/attribute-macro name) in key_source.rs and
  host_key.rs
- fix stray ')' typo in the HostKeySource docs
- rewrite the stale lib.rs architecture line (dependency surface and
  feature graph are landed, not 'landing with implementation start')
- drop a discarded try_sign probe and a redundant None re-assignment
  in tests

Verification: cargo test 47/47 (default + --all-features), clippy
-D warnings (both feature configs, all targets), fmt --check,
cargo doc --no-deps 0 warnings
2026-10-28 07:22:24 +00:00
glm-5.3-flash 214690b9c2 test(doubles): land the wave-1 in-memory seams + unified ed25519 fixtures
The `w1-test-doubles` task: the in-memory seams every later wave's
contract tests run against, behind their production seams.

- tests/common/mod.rs — the doubles, test-only (nothing reachable from
  lib.rs, no feature): MemIdentityProvider (registered fingerprints ->
  alkcall Identity resolutions over the IdentityProvider trait; token
  path resolves none per ADR-004), TestVault (a wrapper over alkvault
  0.1's shipped in-memory construction — resolving the flagged
  vault-double question: wrap, not re-impl), MemHostKeyPolicy
  (exact (host, fingerprint) rules + explicit default verdict,
  fail-closed by default, inspectable decision log), and the fixture
  table. Module docs record the location/vault/fixture decisions and
  the row/stamp discipline (greppable Contract stamps).
- tests/vectors/ — one unified fixture set: four ssh-keygen-minted
  ed25519 keypairs (committed .key + .pub + fingerprints.txt recorded
  from ssh-keygen -lf, OpenSSH_9.6p1). The previous inline PEM
  constants in src/key_source.rs were rejected by OpenSSH itself
  (russh-only decodable); all keys were re-minted and the overlapping
  vector set retired — one fixture set now serves the parity tests,
  the custody round-trip, and every later auth/mapping test
  (src-unit tests share it via include_str!).
- tests/doubles.rs — the end-to-end rows: register -> resolve,
  seal -> source -> decode (+ locked/absent/tampered postures),
  host-key set in order, policy verdicts honored-and-logged.
- tests/fingerprint_parity.rs and src/key_source.rs tests moved onto
  the shared fixture files; src changes are #cfg(test) only.

Verification: cargo test (33 + 9 + 5 green; --all-features also green),
cargo clippy --all-targets -- -D warnings clean, cargo fmt --check
clean, taskgraph validate ok (12 tasks).
2026-10-28 07:09:17 +00:00
glm-5.3-flash 949d0bbbe4 feat(config): land the configuration surface (serve-config, dial-config, Limits)
- ServeConfig: OQ-08 shell_argv / exec_wrapper_argv as
  Option<Vec<String>> with unset-declines doc contracts (no crate
  default shell/wrapper); OQ-09 session_cwd/session_env
  (assembly-supplied, never wire-derived); injected
  Arc<dyn IdentityProvider> + Arc<dyn HostKeySource> handles;
  optional Arc<ChannelClient> route-1 handle (absent -> tunnel rows
  decline even under the tunnel feature); Limits.
- DialConfig: address + injected Arc<dyn KeySource> and
  Arc<dyn HostKeyPolicy> handles + Limits.
- Limits: the bounded-resources budget model both directions carry —
  in-crate caps (max_concurrent_channels 64, max_exec_command_len
  8192) and the russh-knob mapping with documented postures
  (max_auth_attempts 10 per ADR-004 decision 6; window 2 MiB /
  packet 32 KiB / buffer 100; inactivity 600 s always-set shape;
  keepalive Some(15 s)/3 client posture).
- Types only: no russh Config construction (wave 2), no dialing
  (wave 4); no construction-time validation — unset-declines lives
  in the type shape (error.rs no-config-error contract).

Verified: cargo test (36), cargo test --all-features, clippy
(all-targets, -D warnings, default + all-features), fmt --check.
2026-10-28 06:57:52 +00:00
glm-5.3-flash 4d529dbacf feat(key-source): land the vault-backed key sources (ADR-005 custody in code)
- Two injected-handle seams: KeySource (dial-config, decrypt-at-use ->
  one PrivateKey) and HostKeySource (serve-config, decrypt-at-construction
  -> the Config::keys set); async_trait object-safe, the HostKeyPolicy
  handle shape
- Crate-provided ADR-005 implementations: VaultKeySource (injected
  vault handle + Option<EncryptedData>, None -> Absent) and
  VaultHostKeySource (record set, empty -> Absent) over the shared
  decrypt_and_decode chain: vault.decrypt -> Zeroizing<String> seam
  wrap -> one-time decode_secret_key(plain, None)
- EncryptedData opaque in src/ (no key_version interpretation); vault
  error taxonomy reshaped into the five-variant KeySourceError matrix,
  never collapsed; plaintext never persists
- 12 in-module tests on the real in-memory alkvault handle: round-trip
  (fingerprint-identical ed25519 key that signs), full failure matrix,
  locked host-bootstrap refusal, lock-mid-session lifecycle,
  v2->v3 rotation identity; three committed throwaway PEM fixtures

Verified: cargo test (23 + 4 parity), cargo test --all-features,
clippy -D warnings (default + all-features), fmt --check, taskgraph
validate
2026-10-28 06:45:56 +00:00
glm-5.3-flash 149f11d4b2 feat(host-key): land the HostKeyPolicy seam (OQ-05, policy-blind)
- HostKeyPolicy trait: async, dyn-compatible (Arc<dyn> handle, the
  alkcall injected-handle pattern) — decide(&self, &PresentedHostKey)
  -> bool with host/port/fingerprint as the decision input
- Verdict type pinned to the russh 0.65 check_server_key shape:
  bool is the trust decision; decline reasons stay with the policy
  (declines are dispositions, not errors). Flagged for the wave-1 gate
- Built-in default RejectAll: fail-closed reject-all (russh's default,
  kept); no accept-all option exists in the crate
- async-trait 0.1 added for the dyn-compatible async handle
  (alkcall-precedented; tree-deduped). Flagged for the wave-1 gate
- Tests: default rejects; custom verdict honored; both through the dyn
  handle; the whole presented context reaches the policy

Verified: cargo test (14), cargo test --all-features, cargo clippy
--all-targets -- -D warnings, cargo fmt --check, taskgraph validate
2026-10-28 06:40:40 +00:00
glm-5.3-flash 635e82b54b feat(fingerprint): land the single fingerprint path + ssh-keygen parity vectors
- src/fingerprint.rs: alkssh::fingerprint wraps the ssh-key re-export
  (HashAlg::Sha256) — the crate's only fingerprint computation and
  formatting site (ADR-004 decision 1's contract invariant)
- tests/fingerprint_parity.rs: 4 committed ed25519 fixtures with
  ssh-keygen -lf-recorded fingerprints (OpenSSH 9.6p1, independent
  issuer); blobs cross-checked against the vectors manifest
- verified: cargo test, clippy (default + all-features, -D warnings),
  fmt; taskgraph validate clean
2026-10-28 06:27:49 +00:00
glm-5.3-flash d85299df38 feat(error): land the fail-closed key-source error taxonomy
- KeySourceError with exactly five variants (Locked, Absent,
  Decryption, UnknownKeyVersion, Decode) — ADR-005 decision 4's
  failure matrix as distinct shapes, the vault taxonomy reshaped
  never collapsed; no catch-all, no Other/Unknown
- payload shapes pinned: Locked/Absent payload-free;
  Decryption/UnknownKeyVersion carry the vault's opaque messages;
  Decode carries a message so the RC-pinned ssh-key error type
  never enters the public API (flagged for the wave-1 gate)
- each variant doc-commented with ADR-005 semantics + fail-closed
  consequence; module stays engine-blind (no vault/russh types)
- no From<VaultServiceError>: non-mappable vault variants would
  force a collapse; w1-key-sources maps explicitly at its seam
- exhaustive-match + Display/Debug/Clone unit tests

Verified: cargo test (default + all-features), cargo clippy
--all-targets --all-features -- -D warnings, cargo fmt --check,
cargo doc --no-deps, taskgraph validate
2026-10-28 06:22:52 +00:00
glm-5.3-flash 263f91fdb7 docs(architecture): review-pass cleanup — inconsistencies, stale refs, scaffolding refresh
- OQ-02: rewritten as a clean resolved statement; contradictory
  deferred-table row removed
- OQ-05: 'old-code anti-pattern' framing corrected — ephemeral-fleet
  accept-and-continue is a legitimate case-2 HostKeyPolicy; the crate
  rule is 'no hard-coded trust model', not 'accept-all forbidden';
  dangling 'expected ADR-007' pointer replaced with the real contract
  locations (auth.md, client.md)
- README: OQ counts corrected (6 resolved / 3 open / 4 deferred);
  sibling references normalized to real ADR IDs (alkcall 010 is alkhttp
  014's analog; 'ADR-016-analog' was a wrong number)
- client/auth: OQ-07 status corrected to resolved-at-adapter-level;
  TOFO typo; TOFU framing
- ADR-004: dangling 'ADR-008' -> serve-config defaults
- ADR-006: SOCKS5 typo
- mapping: alktty typo; '(OQ-… note below)' placeholder -> the real
  POC-3 note reference
- research: cross-repo numbers qualified (alktty OQ-44, alkvault
  ADR-021); reverse-runner lesson 5 reframed per correction
- scaffolding: Cargo.toml description/comments and src/lib.rs doc
  comment updated against ADR-002/003/006 (dynamic-forward retired,
  git exec-only, russh pin decided); CHANGELOG logs POC completion and
  ADRs 001-006

Verification: cargo test, cargo clippy --all-targets -- -D warnings,
cargo fmt --check, cargo check — all pass
2026-10-27 10:00:11 +00:00
glm-5.3-flash e0805cd438 chore: initialize crate base (manifest, lib stub, licensing, agents)
Phase 0 base for the russh-wrapped SSH adapter (family ADR-003):

- Cargo.toml: single-crate alkssh 0.1.0, MIT OR Apache-2.0, lib only,
  publish exclude list matching the sibling-crate policy; deliberately
  empty [dependencies] — the russh pin is phase 0 research output
  (alknet main's 0.49 is a data point, not the decision). [features]
  carries the fail-closed posture as a comment until the capability
  feature graph lands with the committed architecture
- src/lib.rs: crate-root doc describing the adapter shape and the
  fail-closed feature contract
- LICENSE-MIT / LICENSE-APACHE (alktty's standard texts)
- .gitignore (target/, node_modules/, .worktrees/)
- CHANGELOG.md: Keep a Changelog stub, [Unreleased] initialization
- AGENTS.md: full agent operating instructions — git workflow
  (conventional commits, commit-and-push), 13 project conventions
  (russh owns the wire, fail-closed capability features, key reuse via
  alkvault-backed sources, visible-surface=authorized-surface,
   ALPN as one-way door), verification commands, taskgraph
  task rules, SDD phase 0 lifecycle status, architecture context

Verification: cargo build/test/clippy --all-targets -D warnings and
cargo fmt --check all pass (lib stub, zero deps)
2026-10-25 05:32:29 +00:00