- ADR-001: inherit the alknet TLS design as the baseline; deviations recorded as alktls ADRs - ADR-002: TlsError ships the ADR-088 six-variant shape from day one (typed #[from] sources; NoqWrap; no string catch-all) - ADR-003: the QUIC feature is noq (iroh's extracted fork), pre- consumer rename; default = [] per the lean-crate convention (corrects the extracted code's default = ["quinn"]) - ADR-004: complete accessors — for_tcp_tls() adopted, rustls_config() adopted; server accessors borrow (&self), client accessors consume - ADR-005: identity + credentials + fingerprint types move into alktls; auth layer stays out - ADR-006: eight-module layout; seed tests + integration invariant pins (exact nine-scheme list, client enable_early_data) - specs: overview (transport picture, terminology), server.md (ACME lifecycle, invariants), client.md (verifier selection matrix, root- store fallback); open-questions.md promotes OQ-TLS-01..08 (all resolved at entry) - Cargo.toml: quinn feature -> noq (per ADR-003); AGENTS.md aligned Architecture review pass done: 0 critical, 2 major (ADR-002 AcmeConfig doc comment contradiction; ADR-003 unrecorded default deviation) and 8 minors all addressed; cross-references verified against alknet ADRs, rustls/noq/iroh sources. Verified: cargo test, test --all-features, clippy -D warnings, fmt --check, doc --no-deps
4.2 KiB
status, last_updated
| status | last_updated |
|---|---|
| accepted | 2026-09-10 |
ADR-006: Module layout and test surface
Status
Accepted (2026-09-10)
Context
The extracted crate is organized as four modules plus the error
(lib.rs, server.rs, client.rs, pem.rs, signing.rs) with all
tests as in-module #[cfg(test)] blocks. alktls adds three modules of
moved types (ADR-005) and, per the repo's conventions, needs a
decided module map and test layout before the port starts.
Two shape questions need answers: where the moved types live relative to the config constructors, and how the seed tests port (no external workspace exists here, so in-module tests are the only cross-module surface a full-crate crate has).
Decision
Module layout (one module per file, re-exported from lib.rs):
src/
├── lib.rs — crate docs, TlsError (ADR-002), re-exports
├── identity.rs — TlsIdentity, Ed25519SecretKey, AcmeDirectory (ADR-005)
├── credentials.rs — ConnectionCredentials, RemoteIdentity (ADR-005)
├── fingerprint.rs — fingerprint_from_cert_der, extract_ed25519_raw_key_from_spki,
│ DER parser (ADR-005)
├── server.rs — TlsServerConfig, build_rustls_server_config,
│ RawKeyCertResolver, AcceptAnyCertVerifier,
│ SelfSignedCert / generate_self_signed_cert
├── client.rs — TlsClientConfig, select_server_verifier,
│ build_client_auth, RawKeyClientCertResolver,
│ NoClientCertResolver, FingerprintPinVerifier,
│ load_platform_root_cert_store
├── pem.rs — load_cert_chain, load_private_key
└── signing.rs — Ed25519SigningKey (rustls SigningKey + Signer)
Public API surface is lib.rs re-exports only (AGENTS.md convention
12); modules are pub for discoverability but the re-export block is
the documented surface.
Feature gates stay on types and accessors, not modules. The
noq feature gates for_noq() + NoqWrap; the tcp feature gates
for_tcp_tls(); the acme feature gates the ACME branch of
TlsServerConfig::new + the spawned task + the futures dep. Unlike
the alktunnels/alktty backends, there are no substrate modules to
gate — the transport-specific code is accessor-shaped.
Test surface:
- Port the extracted crate's in-module tests as the seed (they assert
the behavior-preservation invariants:
max_early_data_sizeon the server paths,enable_early_dataon the client config, the nine-scheme list, resolver behavior, PEM error paths, signing). - Add
tests/integration tests for the cross-module surfaces a single crate has:TlsServerConfig::new→for_noq()/for_tcp_tls()round-trips per identity variant;TlsClientConfigverifier selection matrix (Some/None× raw-key/X.509); the root-store fallback against an empty platform store;acme-tls/1append on the ACME path only. - Pin the exact nine-scheme list in an integration test
(Phase 0 OQ-TLS-05's regression-proof shape — the extracted
in-module test only checks membership of two schemes), and pin
enable_early_data = trueon the client config (the client half of the 0-RTT invariant). TlsIdentity::Acme'sunreachable!inbuild_rustls_server_configbecomes a config error (the extracted code relies on an internal dispatch invariant; the port replaces theunreachable!with theAcmeConfigvariant, keeping no-panics-in-library-code).
Consequences
Positive:
- The port is mechanically guided: module map + seed tests make the Phase 2 port a diff against the extracted source.
- The invariant assertions move from "documented" to "tested" at both unit and integration level.
Negative:
- Integration tests that wrap real QUIC endpoints are out of scope (they belong to transport crates); the seam tests assert config construction, not handshakes — the scope boundary holds.
References
- AGENTS.md conventions 1, 9, 12 — comments, feature gates, module structure
docs/research/phase-0.md§Gaps #5, OQ-TLS-05 — the test-surface question- ADR-002 —
TlsError(noConfig(String)catch-all) - ADR-005 — the moved modules