crate-init: crate skeleton — module map, feature gates, TlsError, re-export block deferred per port

- src/lib.rs: crate docs, ADR-002 TlsError verbatim (six variants,
  #[non_exhaustive], typed #[source] chains), module declarations,
  compile-assertion tests for the enum + noq-gated NoqWrap
- seven module files with doc headers only (ports land per task)
- Cargo.toml verified against ADR-003 verbatim (no edits needed)
- deviation: VerifierBuild source is rustls::client::VerifierBuilderError
  (rustls::webpki is private at pinned 0.23.44; same type, public path)

Verification: cargo build/test (default, noq, tcp, acme, all-features),
clippy -D warnings, fmt --check, doc --no-deps — all green
This commit is contained in:
glm-5.3-flash committed 2026-09-10 13:27:46 +00:00
1 parent 05b3832c88
commit f68234133f
9 files changed
+171 -16

No files matched your search

+90 -14
View File
@@ -1,27 +1,103 @@
//! alktls: shared TLS setup types — server and client rustls configs,
//! cert resolvers, verifiers, and shared signing helpers.
//! alktls: shared TLS setup types — server and client `rustls` configs,
//! cert resolvers, verifiers, ACME state-machine wiring, and the identity /
//! credential / fingerprint types that drive config construction.
//!
//! Phase 0 (exploration) — the crate shape is being established in
//! `docs/research/phase-0.md`. This placeholder keeps the scaffold
//! building until the crate skeleton lands in Phase 1.
//! The crate owns **config construction**: given an identity and an ALPN
//! list, produce a `rustls::ServerConfig` or `rustls::ClientConfig` and hand
//! it to whichever transport wrapper the deployment runs (`noq` for QUIC,
//! `tokio-rustls` for TCP+TLS). It does not dial, accept, dispatch, or
//! resolve peer identities — those belong to the dial seam, the accept
//! loop, and the auth layer.
//!
//! Core types:
//!
//! - [`TlsServerConfig`] — built once per identity + ALPN list, shared
//! across transports via [`Arc`](std::sync::Arc) (not `Clone`; it holds
//! the ACME task's `JoinHandle`).
//! - [`TlsClientConfig`] — built per dial from a [`ConnectionCredentials`] +
//! ALPN; consumed by its accessors.
//! - [`TlsError`] — the config-construction error type. Handshake outcomes
//! and ACME runtime errors are not `TlsError`s.
//!
//! Transport-specific accessors are feature-gated: `noq` (`for_noq`),
//! `tcp` (`for_tcp_tls`), `acme` (the ACME path). `default = []`.
pub mod client;
pub mod credentials;
pub mod fingerprint;
pub mod identity;
pub mod pem;
pub mod server;
pub mod signing;
// The re-export block (the documented public API surface) lands per
// module as each port task completes; the final shape is ADR-006's
// module map + overview.md §What the crate is.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum TlsError {
/// Cert or key file read / PEM parse. `rustls_pemfile` funnels its
/// own error type into `io::Error`, so one `io::Error` source covers
/// the whole loading path.
#[error("loading cert/key material: {0}")]
CertLoad(#[from] std::io::Error),
/// Self-signed cert generation (rcgen). Server `SelfSigned` path.
#[error("generating self-signed cert: {0}")]
SelfSigned(#[from] rcgen::Error),
/// rustls server or client config construction
/// (`with_safe_default_protocol_versions`, `with_single_cert`,
/// `CertifiedKey::from_der`, `RootCertStore::add`).
#[error("building rustls config: {0}")]
Rustls(#[from] rustls::Error),
/// `WebPkiServerVerifier::builder(_with_provider)..build()` — the
/// unknown-X.509-remote client path. Re-exported by rustls at
/// `rustls::client` (the `rustls::webpki` module is private at the
/// pinned 0.23.44; same type, public path).
#[error("building webpki verifier: {0}")]
VerifierBuild(#[from] rustls::client::VerifierBuilderError),
/// QUIC config wrapping — the one path where `for_noq()` fails
/// (`NoInitialCipherSuite`, not a `rustls::Error`). noq-gated.
#[cfg(feature = "noq")]
#[error("wrapping rustls config for noq: {0}")]
NoqWrap(#[from] noq_proto::crypto::rustls::NoInitialCipherSuite),
/// Config-mismatch errors that are not wrapped third-party
/// errors: ACME feature not enabled but `Acme` configured
/// (server), or `Acme` identity used for client auth. A config
/// error, not a wrapped third-party error.
#[error("TLS config error: {0}")]
Config(String),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("certificate error: {0}")]
Cert(String),
AcmeConfig(String),
}
#[cfg(test)]
mod tests {
use super::*;
use super::TlsError;
#[test]
fn error_type_constructs() {
let e = TlsError::Config("placeholder".into());
assert!(e.to_string().contains("placeholder"));
fn tls_error_matches_the_adr_002_variant_set() {
let io: TlsError = std::io::Error::other("x").into();
assert!(matches!(io, TlsError::CertLoad(_)));
let rcgen: TlsError = rcgen::Error::CouldNotParseCertificate.into();
assert!(matches!(rcgen, TlsError::SelfSigned(_)));
let rustls: TlsError = rustls::Error::General("x".into()).into();
assert!(matches!(rustls, TlsError::Rustls(_)));
let builder: TlsError = rustls::client::VerifierBuilderError::NoRootAnchors.into();
assert!(matches!(builder, TlsError::VerifierBuild(_)));
let acme = TlsError::AcmeConfig("acme feature not enabled".into());
assert!(acme.to_string().contains("acme feature not enabled"));
}
#[cfg(feature = "noq")]
#[test]
fn tls_error_noq_wrap_variant_exists() {
let _ = matches!(
Option::<TlsError>::None,
Some(TlsError::NoqWrap(_)) | Some(_)
);
}
}