Review of the three new crates (alknet-tls, alknet-endpoint, alknet-client) + revised core found compile-blocking inconsistencies, stale claims, and dep-graph contradictions. All resolved: Critical: - C1: CallClient::connect / ChannelClient::connect_quic REMOVED (not delegated) — keeping them as thin wrappers over AlknetClient::dial_quic would make protocol crates depend on alknet-client, contradicting the dep graph. Callers compose dial + take-over (2 lines). - C2: alknet-client feature gates now pull alknet-core/quinn + alknet-core/iroh (for Connection::from_quinn_with_alpn / from_iroh). - C3: rustls-native-certs + webpki-roots added to alknet-tls deps (always-present, not feature-gated — CA-verify path is transport-agnostic). Warning: - W1: CallCredentials/RemoteIdentity moved to alknet-core (from alknet-call) — the dial must not depend on the call protocol; not a two-way-door, it determines the dep graph. - W2: webpki-roots fallback implemented in spec (ADR-088 §5 added) — the code claimed a fallback that never existed; now the store is never empty, NoRootAnchors unreachable, containerized deployments work. - W3: EndpointError removed entirely (BindFailed + HandlerNotFound both vestigial after ADR-083); shutdown() is now infallible. - W4: FingerprintPinVerifier moved to alknet-tls (from alknet-call) — alknet-call sheds quinn/rustls/rustls-pemfile/rustls-native-certs entirely; CallClient becomes a pure protocol crate. Plus: ClientError removed (only produced by removed connect); S1 (CallCredentials → ClientVerifierContext mapping + auth_token stripped at TLS boundary documented); amendment notes on ADR-017, ADR-069, ADR-080, ADR-082, ADR-087, ADR-090; overview crate graph + README index updated. 29 files, consistency-reviewed.
5.3 KiB
OQ-63: TlsError Shape
-
Origin:
docs/architecture/crates/tls/README.md(TlsErroris referenced as theResulterror type inTlsServerConfig::new,TlsClientConfig::new,for_quinn(), and the crate's public signatures, but is never sketched or defined); ADR-082 (same —TlsErrorin signatures, no shape); ADR-087 (extends the surface toTlsClientConfig::new— the client-side error variants). -
Status: resolved (ADR-088)
-
Door type: one-way (the error type is the public API surface of
alknet-tls; changing it after consumers exist is a breaking change to every assembly-layer call site) -
Priority: high (an implementer cannot write the crate without deciding this; guessing produces divergent shapes — one thin
rustls::Errorwrapper vs a 10-variant enum with per-path context) -
Impacts: Blocks
alknet-tlsimplementation — bothTlsServerConfig::newandTlsClientConfig::newreferenceTlsErrorin their signatures. Blocks the hub's assembly-layer wiring (which calls both). This is the next decision needed before the TLS crate can be implemented. -
Resolution: Decided (ADR-088).
TlsErroris a single#[non_exhaustive]enum with one variant per failure category, owned byalknet-tls(not re-exported from core). The variants, grounded in the actual error-producing call sites and the dependency-crate sources (rustls 0.23.41, rustls-pemfile 2.2.0, rcgen 0.13.2, quinn-proto 0.11.15, rustls-acme 0.12.1):- Cert/key loading (
X509: file read + PEM parse;SelfSigned: rcgen generation) — currentlyio::Error-wrapped in the core code. - rustls config construction (
builder_with_provider/with_safe_default_protocol_versions/with_single_cert/with_cert_resolver) — currentlyrustls::Error-wrapped. - quinn wrap (
QuicServerConfig::try_from(rustls::ServerConfig)) — the one path wherefor_quinn()can fail; currentlyio::Error::other(e)-wrapped. - ACME —
rustls-acmehas its own error types; the ACME task runs in the background and surfaces errors via events (logged, not returned fromnew), sonew's ACME path may only need to cover "ACME feature not enabled butTlsIdentity::Acmeconfigured" (currently anio::ErrorKind::Unsupported). - Client verifier construction (ADR-087) —
TlsClientConfig::newbuilds arustls::ClientConfigwith ADR-034's verifier selection. Failure modes: verifier construction error (bad fingerprint format, CA store init failure), unknown-remote fail-closed (not an error to return — it's aResult::Errthe caller gets for trying to connect to an unknown raw-key remote), provider init failure. These overlap with the server-side rustls-build errors but have client-specific context (verifier selection inputs).
The open question was the granularity: a single
TlsErrorenum with variants per failure category (cert-load, rustls-build, quinn-wrap, acme-disabled) vs a thin wrapper aroundrustls::Error/io::Error. Resolved: the single-enum shape. The thin wrapper is actively wrong here — three findings from the dependency-crate source drive the decision: (1)for_quinn()fails withNoInitialCipherSuite, a distinct type fromrustls::Error— a thinrustls::Errorwrapper cannot represent thefor_quinn()failure; (2)rustls_pemfile::Erroris not astd::error::Error(noDisplay, noErrorimpl), so pemfile's BufRead APIs returnio::Error— a#[from] rustls_pemfile::Errorwould not compile; (3)WebPkiServerVerifier::build()returnsVerifierBuilderError, notrustls::Error— a thin wrapper cannot represent "empty CA root store" as a first-class failure. The six variants:CertLoad(io::Error),SelfSigned(rcgen::Error),Rustls(rustls::Error),VerifierBuild(VerifierBuilderError),QuinnWrap(NoInitialCipherSuite)(quinn-gated),AcmeConfig(String). ACMEEventError/OrderErrorare deliberately absent — they are stream events, logged not returned fromnew. The unknown-raw-key fail-closed is deliberately absent — it is a handshake-time rejection (dial time), not a config-construction error (newtime). See ADR-088 for the full rationale, the variant definitions, and the "what is NOT a variant" list.Subsidiary question: does
TlsErrorlive inalknet-tls(owned by the crate that produces it) or is it re-exported fromalknet-core? Resolved:alknet-tls, owned by the crate that produces it.EndpointErroris removed entirely after ADR-083 (both variants vestigial); core has no endpoint error type and does not need to know aboutTlsError. Re-exporting from core would invert the ownership (core re-exporting a type from a crate that depends on it). - Cert/key loading (
-
Cross-references: ADR-088 (the resolution — single enum, owned by
alknet-tls, six variants), ADR-082 (the extraction that introducesTlsError), ADR-083 (the endpoint refactor that removesEndpointErrorentirely, makingTlsErrorthe sole TLS error surface), ADR-087 (extends the surface to client-side variants),crates/alknet-core/src/endpoint.rs(the currentio::Error-wrapping pattern the new type replaces),crates/alknet-call/src/client/call_client.rs(the currentString-wrapping pattern on the client side)