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).
6.9 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | |||
|---|---|---|---|---|---|---|---|---|---|---|
| w1-test-doubles | Wave 1 — test doubles (the in-memory seams) | completed |
|
narrow | low | component | implementation |
Description
Establish the test-double convention (adapted from the sibling crates) and land the in-memory seams every later wave's contract tests run against:
- In-memory
IdentityProvider— registered fingerprints →Identityresolutions over alkcall's trait; the double the auth bridge and dispatch tests resolve against. - In-memory vault seam — the encrypt/decrypt round-trip plus the failure postures (locked / absent / tampered) behind the same seam the key sources consume, so the custody tests run without a live vault service. If alkvault 0.1 ships an in-memory construction, wrap it; otherwise a local test double behind the source trait — the task pins which, flagged for the wave-1 gate.
- In-memory
HostKeyPolicy— a configurable record/verdict double (accept/reject per host, decision log inspectable) for the dial and acceptor tests. - ed25519 test-key fixtures — throwaway test keys (generated at
test time or committed static PEMs — the task pins which; committed
keys are throwaway fixtures, not secrets) with recorded
ssh-keygen -lffingerprints, shared with the fingerprint parity tests and every later auth/mapping test.
The convention: doubles live in-crate (test module or #[cfg(test)]
utility module per the sibling posture), every protocol wave's gate
runs its machines against them, and no double leaks into src/
non-test code.
Acceptance Criteria
- In-memory
IdentityProvider, vault seam, andHostKeyPolicydoubles in place behind their production seams - ed25519 test-key fixtures with recorded fingerprints available to the test suite
- The doubles exercise the wave-1 seams end to end (a round-trip test: register fingerprint → resolve; encrypt → source → decode; policy verdict honored)
- No double code outside test-gated compilation
cargo test,cargo clippy --all-targets -- -D warnings,cargo fmt --checkpass
References
- docs/architecture/decisions/004-auth-dispositions.md (the
IdentityProvidersurface) - docs/architecture/decisions/005-at-rest-key-custody.md (the custody seam the vault double backs)
- docs/research/poc-2-vault-keys.md (the failure postures the vault double reproduces)
- The alkgit test-double convention (tasks/implementation/core/ w1-test-doubles.md — reading reference, never copied code)
Notes
- Vault-double shape (recorded, flagged for the wave-1 gate): alkvault
0.1 ships an in-memory construction —
VaultServiceHandle::new()is an in-process vault thatunlock_newarms in-memory. The double is a wrapper (TestVaultintests/common/mod.rs) around that construction, not a local re-impl behind the source trait: the real decrypt taxonomy, GCM integrity behavior, and rotation semantics are exercised verbatim through the productionVaultKeySource/VaultHostKeySourceseams, and the POC-2 §3 postures (locked / absent / tampered / wrong seed) ride the real seams. - Fixture decision (recorded): committed static OpenSSH-PEM test
keys, minted by
ssh-keygenat vector-generation time — not generated at test time (determinism, no tooling dependency). Committed private halves are throwaway fixtures by the task's own posture, documented as such intests/vectors/fingerprints.txtand in the common module docs. - Location decision (recorded): the doubles live only under
tests/common/mod.rs, reached withmod common;— the alkgit convention, adapted. Nothing doubles-related is reachable fromlib.rs; no feature gates them.src/-unit tests that need the fixture material read the committed files viainclude_str!(src/key_source.rstests), never a copy — the single fixture set is shared by the src-side and tests/-side suites. dead_code is allowed module-wide intests/common/(each test binary compiles the whole shared module and never exercises all of it). - The fixture set was unified and re-minted (flagged for the gate):
the previous state had two overlapping throwaway sets — public-only
vectors under
tests/vectors/(fingerprint parity) and inline private-PEM constants insrc/key_source.rs— and the inline PEM constants, while decodable by russh, were rejected by OpenSSH itself (ssh-keygen→ "error in libcrypto"): unusable as cross-issuer fixtures. All four keys (alpha/bravo/charlie/delta) were freshly minted with OpenSSH_9.6p1's ssh-keygen, their fingerprints recorded byte-verbatim intests/vectors/fingerprints.txt, and the two sets unified into one fixture table (FIXTURE_KEYS) — committed.key+.pubfiles, served to the fingerprint parity tests, the vault round-trip, and every later auth/mapping test. The old vector-only set was retired (its keys had no private halves). - The row/stamp discipline is established in
tests/common/mod.rs's module docs (adapted from the sibling crates): rows state properties and carry greppableContract stamp:items citing the pinning ADR § —grep -rn "Contract stamp:" tests/is the inventory (11 stamps across the 11 landed rows). - No
src/non-test changes:src/key_source.rschanged only inside its#[cfg(test)]module (fixtureinclude_str!s + one parity row);tests/common/mod.rsandtests/doubles.rsare the new surfaces.
Summary
The wave-1 test-double convention landed: tests/common/mod.rs carries
MemIdentityProvider (registered fingerprints → alkcall Identity
resolutions; token path resolves none — ADR-004's fingerprint-only
disposition), TestVault (a wrapper over alkvault 0.1's shipped
in-memory construction — the pinned resolution of the flagged
vault-double question), MemHostKeyPolicy (exact (host, fingerprint)
rules + explicit default verdict — fail-closed by default, permissive
only by explicit choice — with a fully inspectable decision log), and
the unified ed25519 fixture table (FIXTURE_KEYS: four committed
ssh-keygen-minted OpenSSH-PEM key pairs with recorded
ssh-keygen -lf fingerprints in tests/vectors/fingerprints.txt). The
end-to-end rows in tests/doubles.rs run the seams through the
production surfaces: register → resolve, seal → source → decode
(round-trip and the locked/absent/tampered postures), verdict →
honored-and-logged. src/key_source.rs and
tests/fingerprint_parity.rs were moved onto the shared fixture files
(one fixture set, no copies; the previous inline PEMs were discovered
to be OpenSSH-rejected and were replaced by freshly minted keys). All
doubles live in test-only compilation (tests/), with nothing
doubles-related reachable from the public API. Verified: cargo test
(33 + 9 + 5 green; also --all-features), cargo clippy --all-targets -- -D warnings, cargo fmt --check clean.