refactor(server): move TlsSettings into its own tls_config module

`TlsSettings` and its `from_settings(&SettingsFile)` constructor
lived in `jwt_auth.rs` as a historical artifact from the Stage 6.6g
rewrite — the auth resolver only needs to know *whether* TLS is
present (for mTLS support), not the contents of the triple. The
type is really a listen-side concern that belongs next to the
rustls builder.

Moves the type into a new `fabro-server/src/tls_config.rs` module
(35 LOC). Updates three importers:

- `jwt_auth.rs` — imports `TlsSettings` from `crate::tls_config`;
  drops the `std::path::PathBuf` / `InterpString` / `ServerListenLayer`
  / `serde::Deserialize` imports that are no longer used after the
  type moved.
- `serve.rs` — splits the multi-item `use crate::jwt_auth::{...}`
  line so `TlsSettings` comes from `crate::tls_config`.
- `tls.rs` — same split.
- `tests/it/api/mtls.rs` — same split.

Pure relocation; no behavioral change. 156 fabro-server tests pass,
`cargo fmt --check --all` and `cargo clippy --workspace -- -D warnings`
are clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-04-09 18:54:04 -04:00
parent 4a3549e8da
commit b4d8d05a85
6 changed files with 54 additions and 37 deletions

View file

@ -1,4 +1,3 @@
use std::path::PathBuf;
use std::sync::Arc;
use axum::extract::FromRequestParts;
@ -10,42 +9,10 @@ use serde::Deserialize;
use tracing::warn;
use crate::error::ApiError;
use crate::tls_config::TlsSettings;
use crate::web_auth::SessionCookie;
use fabro_types::RunAuthMethod;
use fabro_types::settings::SettingsFile;
use fabro_types::settings::interp::InterpString;
use fabro_types::settings::server::ServerListenLayer;
/// Resolved TLS material used by the rustls config builder in `tls.rs`
/// when the server is listening on TCP with `[server.listen.tls]` set.
#[derive(Debug, Clone, PartialEq)]
pub struct TlsSettings {
pub cert: PathBuf,
pub key: PathBuf,
pub ca: PathBuf,
}
impl TlsSettings {
/// Extract the `[server.listen.tls]` subtree out of a `SettingsFile`.
/// Returns `None` when the server is on Unix sockets, TLS is unset, or
/// any of the three fields is missing.
#[must_use]
pub fn from_settings(file: &SettingsFile) -> Option<Self> {
let listen = file.server.as_ref()?.listen.as_ref()?;
let tls = match listen {
ServerListenLayer::Tcp { tls, .. } => tls.as_ref()?,
ServerListenLayer::Unix { .. } => return None,
};
let cert = tls.cert.as_ref().map(InterpString::as_source)?;
let key = tls.key.as_ref().map(InterpString::as_source)?;
let ca = tls.ca.as_ref().map(InterpString::as_source)?;
Some(Self {
cert: cert.into(),
key: key.into(),
ca: ca.into(),
})
}
}
/// JWT claims for service-to-service authentication.
#[derive(Debug, Deserialize)]

View file

@ -17,4 +17,5 @@ pub mod server;
mod settings_view;
pub mod static_files;
pub mod tls;
pub mod tls_config;
pub mod web_auth;

View file

@ -21,13 +21,14 @@ use fabro_types::settings::SettingsFile;
use crate::bind::{self, Bind, BindRequest};
use crate::github_webhooks::WebhookManager;
use crate::jwt_auth::{AuthMode, AuthStrategy, TlsSettings, resolve_auth_mode_with_lookup};
use crate::jwt_auth::{AuthMode, AuthStrategy, resolve_auth_mode_with_lookup};
use crate::secret_store::SecretStore;
use crate::server::{
RouterOptions, build_app_state_with_path, build_router_with_options,
reconcile_incomplete_runs_on_startup, shutdown_active_workers, spawn_scheduler,
};
use crate::tls::{ClientAuth, build_rustls_config, serve_tls_with_shutdown};
use crate::tls_config::TlsSettings;
use fabro_llm::client::Client as LlmClient;
use fabro_sandbox::SandboxProvider;

View file

@ -8,7 +8,8 @@ use rustls_pki_types::{CertificateDer, PrivateKeyDer};
use tokio::net::TcpListener;
use tracing::error;
use crate::jwt_auth::{PeerCertificates, TlsSettings};
use crate::jwt_auth::PeerCertificates;
use crate::tls_config::TlsSettings;
/// How client certificates should be verified.
#[derive(Clone, Copy)]

View file

@ -0,0 +1,46 @@
//! Resolved TLS material extracted from `[server.listen.tls]`.
//!
//! This module owns the `(cert, key, ca)` triple that the rustls config
//! builder in [`crate::tls`] consumes when the server is listening on TCP
//! with mTLS enabled. It lives outside `jwt_auth.rs` because TLS material
//! is a listen-side concern, not an authentication strategy — the auth
//! resolver only cares about *whether* TLS is present (for mTLS support),
//! not about its contents.
use std::path::PathBuf;
use fabro_types::settings::SettingsFile;
use fabro_types::settings::interp::InterpString;
use fabro_types::settings::server::ServerListenLayer;
/// Resolved TLS material used by the rustls config builder in
/// [`crate::tls`] when the server is listening on TCP with
/// `[server.listen.tls]` set.
#[derive(Debug, Clone, PartialEq)]
pub struct TlsSettings {
pub cert: PathBuf,
pub key: PathBuf,
pub ca: PathBuf,
}
impl TlsSettings {
/// Extract the `[server.listen.tls]` subtree out of a `SettingsFile`.
/// Returns `None` when the server is on Unix sockets, TLS is unset, or
/// any of the three fields is missing.
#[must_use]
pub fn from_settings(file: &SettingsFile) -> Option<Self> {
let listen = file.server.as_ref()?.listen.as_ref()?;
let tls = match listen {
ServerListenLayer::Tcp { tls, .. } => tls.as_ref()?,
ServerListenLayer::Unix { .. } => return None,
};
let cert = tls.cert.as_ref().map(InterpString::as_source)?;
let key = tls.key.as_ref().map(InterpString::as_source)?;
let ca = tls.ca.as_ref().map(InterpString::as_source)?;
Some(Self {
cert: cert.into(),
key: key.into(),
ca: ca.into(),
})
}
}

View file

@ -4,9 +4,10 @@ use crate::helpers::api;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use fabro_server::jwt_auth::{AuthMode, AuthStrategy, TlsSettings};
use fabro_server::jwt_auth::{AuthMode, AuthStrategy};
use fabro_server::server::{build_router, create_app_state};
use fabro_server::tls::{ClientAuth, build_rustls_config};
use fabro_server::tls_config::TlsSettings;
use tokio::net::TcpListener;
fn fixture_path(name: &str) -> PathBuf {