Renames the written-usage rule into practice across the contract surface: docs/ (architecture, research, plans, sdd), tasks/ (all 43 task files, taskgraph validate passes), AGENTS.md, README.md, CHANGELOG.md, and the .opencode/agents/ prompts. Every replacement is a sense-preserving rewrite (colons, semicolons, commas, parentheses, sentence splits, varied), never a mechanical swap; no spaced hyphens were substituted. Enum fields, frontmatter, tables, wire data, and cited identifiers survive verbatim; en dashes inside numeric ranges keep their meaning. Verification: taskgraph validate (43 tasks), repo grep clean (single exempt hit: the verification command's own search pattern in AGENTS.md), cargo test, clippy --all-targets -D warnings, fmt --check, doc all green.
139 lines
6.9 KiB
Markdown
139 lines
6.9 KiB
Markdown
---
|
|
id: w1-test-doubles
|
|
name: "Wave 1: test doubles (the in-memory seams)"
|
|
status: completed
|
|
depends_on: [w1-error-model, w1-key-sources, w1-host-key-policy]
|
|
scope: narrow
|
|
risk: low
|
|
impact: component
|
|
level: 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 →
|
|
`Identity` resolutions 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, with the task pinning which;
|
|
committed keys are throwaway fixtures, not secrets) with recorded
|
|
`ssh-keygen -lf` fingerprints, 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, and `HostKeyPolicy`
|
|
doubles 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 --check` pass
|
|
|
|
## References
|
|
|
|
- docs/architecture/decisions/004-auth-dispositions.md (the
|
|
`IdentityProvider` surface)
|
|
- 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 that `unlock_new` arms in-memory. The double is a
|
|
**wrapper** (`TestVault` in `tests/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 production `VaultKeySource` /
|
|
`VaultHostKeySource` seams, 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-keygen` at 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 in `tests/vectors/fingerprints.txt` and in the common module docs.
|
|
- **Location decision (recorded):** the doubles live only under
|
|
`tests/common/mod.rs`, reached with `mod common;` (the alkgit
|
|
convention, adapted). Nothing doubles-related is reachable from
|
|
`lib.rs`; no feature gates them. `src/`-unit tests that need the
|
|
fixture material read the committed *files* via `include_str!`
|
|
(`src/key_source.rs` tests), never a copy; the single fixture set
|
|
is
|
|
shared by the src-side and tests/-side suites. dead_code is allowed
|
|
module-wide in `tests/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/`, used for fingerprint parity, and
|
|
inline private-PEM constants in `src/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 in `tests/vectors/fingerprints.txt`,
|
|
and the two sets unified into one fixture table, `FIXTURE_KEYS`
|
|
(committed `.key` + `.pub` files, 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 greppable `Contract stamp:` items citing the pinning
|
|
ADR §, and `grep -rn "Contract stamp:" tests/` is the inventory
|
|
(11
|
|
stamps across the 11 landed rows).
|
|
- No `src/` non-test changes: `src/key_source.rs` changed only inside
|
|
its `#[cfg(test)]` module (fixture `include_str!`s + one parity row);
|
|
`tests/common/mod.rs` and `tests/doubles.rs` are the new surfaces.
|
|
|
|
## Summary
|
|
|
|
The wave-1 test-double convention landed: `tests/common/mod.rs` carries
|
|
`MemIdentityProvider` (registered fingerprints → alkcall `Identity`
|
|
resolutions; the 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 plus an explicit default verdict; fail-closed by default and
|
|
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. |