Files
alktls/tasks/integration-suite.md
T
glm-5.3-flash 87b69e19e6 generation 4: integration suite — seam round-trips + invariant pins
tests/server_seams.rs:
- TlsServerConfig::new per identity variant → rustls_config() +
  for_tcp_tls (tcp) + for_noq (noq); ALPN + max_early_data_size=u32::MAX
  asserted per path; Acme-no-feature → AcmeConfig cell

tests/client_seams.rs:
- TlsClientConfig::new per credentials cell → into_rustls_config +
  for_noq; enable_early_data=true + single-value ALPN pinned

tests/invariant_pins.rs:
- nine-scheme exact-list pin (vec equality, order included)
- verifier-selection + client-auth presentation matrices via public
  API (Debug probe for the pub(super) verifier, direct resolver
  introspection); root-store fallback non-empty

tests/acme_lifecycle.rs (#![cfg(feature = acme)]):
- spawn-and-return, acme-tls/1 in ALPN, resolver wiring, 0-RTT on the
  ACME branch; blackhole + staging URLs — zero network I/O

Verification: all five feature combos green (default 68+13, noq 72+16,
tcp 71+13, acme 68+11, all-features 75+17), clippy -D warnings,
fmt --check, doc --no-deps
2026-09-10 15:00:06 +00:00

131 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: integration-suite
name: Integration suite — invariant pins + feature-matrix + seam round-trips (tests/)
status: completed
depends_on: [port-server, port-client]
scope: broad
risk: medium
impact: phase
level: implementation
tags: [tests, integration, invariants, phase-gate]
---
## Description
The `tests/` integration suite per ADR-006: the cross-module surfaces
the in-module seed tests cannot cover. A full-crate crate has no
workspace consumers to lean on, so this suite is the invariant gate
before the alknet rewrite consumes the crate.
### The suites
1. **Server seam round-trips** — for each `TlsIdentity` variant
(X509 via generated PEM files in a tempdir, RawKey via
`Ed25519SecretKey::generate`, SelfSigned):
`TlsServerConfig::new``for_noq()` (all-features) /
`for_tcp_tls()` / `rustls_config()` all succeed; the rustls config
carries the expected ALPN list and `max_early_data_size`.
2. **Client seam round-trips**`TlsClientConfig::new` per
credentials cell → `for_noq()` / `into_rustls_config()`;
`enable_early_data` pinned true; ALPN single-value list.
3. **Verifier-selection matrix** — the full `local_identity` ×
`remote_identity` construction matrix (the port-client unit
assertions promoted to integration level, exercising the public API
only).
4. **The nine-scheme exact-list pin** — the regression-proof shape
(exact vec equality, not membership).
5. **Root-store fallback**`load_platform_root_cert_store` (or the
config built from it) yields a non-empty store even when the
platform store is empty (webpki-roots merge; assert non-emptiness
and count > 0).
6. **ACME lifecycle** (`--features acme`): construct an `Acme` identity
with staging URL + tempdir cache; assert spawn-and-return semantics,
`acme-tls/1` in the ALPN list, and the resolver wiring (no network
I/O — do NOT hit Let's Encrypt).
7. **Feature-matrix gate**: `default = []` compiles + tests pass;
`--features noq`; `--features tcp`; `--features acme`;
`--all-features` (the gate is also a CI-verifiable convention, but
the suite includes the combination that exercises every
feature-gated accessor).
### Out of scope (explicitly)
Real handshakes (transport crates' job — the scope boundary), network
ACME orders, iroh (no iroh dep exists here), SOCKS5, dispatch.
## Work
1. Write the `tests/` files (one per suite group is fine).
2. Promote any in-module assertions that exercise cross-module
behavior to integration level (keep the in-module ones too).
3. Wire the exact-list and `enable_early_data` pins.
## Verification
- [x] Full suite green across all five feature combos
- [x] The nine-scheme test asserts exact list equality
- [x] `enable_early_data == true` asserted on a client config
- [x] ACME test performs no network I/O (staging URL is constructed,
never contacted)
- [x] `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check`,
`cargo doc --no-deps` (doc comments render)
## Acceptance Criteria
- [x] All 7 suites exist and pass
- [x] The suite runs green with a single `cargo test --all-features`
- [x] `tests/` layout documented in the task Summary
## References
- docs/architecture/decisions/006-module-layout-and-tests.md (the test
plan)
- docs/architecture/server.md + client.md (the invariants)
- Prior art: the extracted crate's in-module tests
(`crates/alknet-tls/src/*.rs` `#[cfg(test)]` blocks)
## Notes
> Agent fills this during implementation.
## Summary
> Agent fills this on completion.
### The `tests/` layout
| File | Suites covered |
|------|----------------|
| `tests/server_seams.rs` | Suites 1 + 7(server half): `TlsServerConfig::new` per X509 (rcgen PEM pair in tempdir) / RawKey / SelfSigned → `rustls_config()` + `for_tcp_tls()` (tcp-gated) + `for_noq()` (noq-gated); ALPN + `max_early_data_size = u32::MAX` asserted per path; the Acme-no-feature → `TlsError::AcmeConfig` cell (`cfg(not(feature = "acme"))`) |
| `tests/client_seams.rs` | Suite 2: `TlsClientConfig::new` per credentials cell (pinned / CA / empty) → `into_rustls_config()` + `for_noq()` (noq-gated); `enable_early_data == true` + single-value ALPN asserted |
| `tests/invariant_pins.rs` | Suites 3 + 4 + 5: the nine-scheme exact-list pin (exact vec equality, order included); the verifier-selection matrix (Some → `FingerprintPinVerifier`, None → `WebPkiServerVerifier` — the fail-closed structure, asserted via the config's derived Debug) + client-auth presentation matrix (RawKey → `only_raw_public_keys()`, X509 → loaded chain, SelfSigned/None → nothing, Acme → `TlsError::AcmeConfig`), all through the public API; root-store fallback non-empty |
| `tests/acme_lifecycle.rs` | Suite 6 (`#![cfg(feature = "acme")]`): spawn-and-return semantics, `acme-tls/1` in the ALPN list, resolver wiring, `max_early_data_size` on the ACME branch — blackhole directory URL (`http://127.0.0.1:9`), staging URL constructed (never contacted) |
Suite 7 (the feature-matrix gate) is the verification command block below —
every combo is run, not just asserted.
### Notes / decisions
- `rustls::ClientConfig`'s `verifier` and `rustls::ServerConfig`'s
verifier are `pub(super)` at rustls 0.23.44 — the verifier identity is
asserted through the derived Debug output (the verifier's type name
appears in it); the client-auth resolver IS public
(`client_auth_cert_resolver`), so the presentation matrix asserts it
directly (`has_certs()` / `only_raw_public_keys()`).
- `alktls::TlsClientConfig.rustls_config` is `pub(crate)` — integration
level goes through `into_rustls_config()`.
- The Acme-no-feature test is `cfg(not(feature = "acme"))` (it asserts
the error only exists when the feature is absent; with the feature the
same identity legitimately constructs — that path is covered by
`acme_lifecycle`).
- Real handshakes, network ACME, iroh, SOCKS5, dispatch: out of scope
per the task (the scope boundary holds).
### Verification
- All five feature combos green: default (68 lib + 13 int), `noq` (72 +
16), `tcp` (71 + 13), `acme` (68 + 11), `--all-features` (75 + 17).
- `cargo clippy --all-targets --all-features -- -D warnings` ✓,
`cargo fmt --check` ✓, `cargo doc --no-deps` ✓.
- The ACME tests perform no network I/O (staging URL constructed, never
contacted; the lifecycle test uses `127.0.0.1:9` — a blackhole).