nautalid 0.1.0

Scratch container substrate — TLS 1.3 HTTP/2+3 kernel, LID/AetherDB, optional filter bus (GPL-3.0-or-later).
//! Scratch-container runtime substrate — replaces Alpine/Debian inside the image.
//!
//! A normal container base image supplies TLS roots, DNS, timezone data, and init behavior.
//! Nautalid replaces that **Linux distro layer** with pure-Rust crates in one static **musl**
//! binary shipped in **`FROM scratch`**:
//!
//! | Base image gave you | Nautalid module / crate |
//! |---------------------|-------------------------|
//! | TLS + CA store      | **rustls** + **ring** + **`webpki-roots`** (outbound); inbound TLS via [`crate::tls`] |
//! | DNS                 | **`dns`** (Hickory) |
//! | Timezones           | **`time_info`** (`chrono-tz`) |
//! | Graceful stop       | **`shutdown`** (SIGTERM / SIGINT) |
//! | Config              | env vars + **`PORT`**, **`RUST_LOG`**, optional **`IMAGE_TRUST_*`** |
//!
//! Call [`install_defaults`] once at container start before any TLS client is built.

use std::sync::Arc;

use rustls::crypto::CryptoProvider;

/// Default unprivileged UID/GID in the scratch image (no `/etc/passwd`; numeric only).
pub const SCRATCH_USER_ID: u32 = 10001;

fn tls_crypto_provider() -> CryptoProvider {
    match std::env::var("NAUTALID_TLS_CRYPTO_PROVIDER")
        .ok()
        .map(|raw| raw.trim().to_ascii_lowercase())
        .as_deref()
    {
        #[cfg(feature = "tls-aws-lc")]
        Some("aws-lc") | Some("aws-lc-rs") | Some("aws_lc_rs") => {
            rustls::crypto::aws_lc_rs::default_provider()
        }
        Some("ring") => rustls::crypto::ring::default_provider(),
        Some(other) => {
            tracing::warn!(
                provider = other,
                "unknown NAUTALID_TLS_CRYPTO_PROVIDER; using ring"
            );
            rustls::crypto::ring::default_provider()
        }
        None => rustls::crypto::ring::default_provider(),
    }
}

/// Installs the **rustls** crypto provider for this process (idempotent).
pub fn install_defaults() -> Result<(), Arc<CryptoProvider>> {
    if CryptoProvider::get_default().is_some() {
        return Ok(());
    }
    CryptoProvider::install_default(tls_crypto_provider())
}

#[cfg(test)]
mod tests {
    use rustls::crypto::CryptoProvider;

    use super::install_defaults;

    #[test]
    fn install_defaults_once() {
        match install_defaults() {
            Ok(()) => {}
            Err(_) => {
                assert!(
                    CryptoProvider::get_default().is_some(),
                    "rustls provider must be installed"
                );
            }
        }
    }
}