nautalid 0.1.0

Scratch container substrate — TLS 1.3 HTTP/2+3 kernel, LID/AetherDB, optional filter bus (GPL-3.0-or-later).
//! Surface configuration validation — fail startup on misconfiguration.

use std::path::PathBuf;

use super::config::SurfaceConfig;
use super::kdl::KdlSurfaceOverrides;

#[derive(Debug, thiserror::Error)]
pub enum SurfaceConfigError {
    #[error("NAUTALID_STATIC=1 requires NAUTALID_STATIC_ROOT")]
    StaticNoRoot,
    #[error("NAUTALID_PROXY=1 requires NAUTALID_PROXY_UPSTREAM")]
    ProxyNoUpstream,
    #[error("NAUTALID_GRPC=1 requires NAUTALID_GRPC_LISTEN (host:port)")]
    GrpcNoListen,
    #[error("NAUTALID_STATIC_ROOT does not exist: {0}")]
    StaticRootMissing(PathBuf),
    #[error(transparent)]
    Kdl(#[from] super::kdl::KdlSurfaceError),
}

/// Load and validate surface config from env + optional KDL overrides.
pub fn load_from_env() -> Result<SurfaceConfig, SurfaceConfigError> {
    let kdl = KdlSurfaceOverrides::from_env()?;
    let mut cfg = SurfaceConfig::from_env();
    kdl.apply(&mut cfg);
    validate(&cfg)?;
    Ok(cfg)
}

fn validate(cfg: &SurfaceConfig) -> Result<(), SurfaceConfigError> {
    if crate::surfaces::env_enabled("NAUTALID_STATIC") && cfg.static_files.is_none() {
        return Err(SurfaceConfigError::StaticNoRoot);
    }
    if let Some(static_files) = &cfg.static_files {
        if !static_files.root.exists() {
            return Err(SurfaceConfigError::StaticRootMissing(static_files.root.clone()));
        }
    }
    if crate::surfaces::env_enabled("NAUTALID_PROXY") && cfg.proxy.is_none() {
        return Err(SurfaceConfigError::ProxyNoUpstream);
    }
    if crate::surfaces::env_enabled("NAUTALID_GRPC") && cfg.grpc.is_none() {
        return Err(SurfaceConfigError::GrpcNoListen);
    }
    Ok(())
}