fix(relay): preserve PR1 loopback sidecar hardening

Signed-off-by: Brother Darryl <146fb160a3266e6165bfa385f6048c975eda9e21cf65da097a0b5ea7952532a5@buzz.block.builderlab.xyz>
This commit is contained in:
Brother Darryl
2026-08-11 12:06:01 -04:00
parent 021ad7c6d7
commit 127386d091

View File

@@ -1,4 +1,5 @@
use std::collections::{HashMap, HashSet};
use std::net::{IpAddr, Ipv4Addr};
use std::sync::atomic::Ordering;
use std::sync::Arc;
@@ -18,7 +19,7 @@ use buzz_db::{Db, DbConfig};
use buzz_pubsub::{rate_limiter::AdmissionRateLimiter, InProcessNip98ReplayGuard, PubSubManager};
use buzz_search::SearchService;
use buzz_relay::config::{Config, MAX_DRAIN_JITTER_MS};
use buzz_relay::config::{Config, RelayProfile, MAX_DRAIN_JITTER_MS};
use buzz_relay::metrics as relay_metrics;
use buzz_relay::router::{build_health_router, build_router};
use buzz_relay::state::{AppBackends, AppState};
@@ -1191,8 +1192,10 @@ async fn run_periodic_until_cancelled<Tick, TickFuture>(
/// ┌─────────────────────────────────────────────────────────┐
/// │ Listener 1: TCP BUZZ_BIND_ADDR:3000 (app router) │
/// │ Listener 2: UDS BUZZ_UDS_PATH (app, optional)│
/// │ Listener 3: TCP 0.0.0.0:8080 (health only) │
/// │ Listener 4: TCP 0.0.0.0:9102 (metrics, via │
/// │ Listener 3: TCP loopback:8080 (single-node health) │
/// │ or 0.0.0.0:8080 (production health) │
/// │ Listener 4: TCP loopback:9102 (single-node metrics) │
/// │ or 0.0.0.0:9102 (production metrics, via │
/// │ PrometheusBuilder — already bound) │
/// │ │
/// │ SIGTERM → shutting_down=true → readiness 503 │
@@ -1217,7 +1220,7 @@ async fn run_single_node(config: Config, tracer_init: telemetry::TracerInit) ->
));
}
relay_metrics::install(config.metrics_port, usage_metrics_idle_timeout_secs(60));
relay_metrics::install_loopback(config.metrics_port, usage_metrics_idle_timeout_secs(60));
let db_path =
std::env::var("BUZZ_LOCAL_DB").unwrap_or_else(|_| "buzz-local.sqlite".to_string());
let media_root =
@@ -1340,6 +1343,24 @@ async fn run_single_node(config: Config, tracer_init: telemetry::TracerInit) ->
/// roughly the 5s grace plus the ack wait.
const GRACEFUL_DRAIN_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
fn health_listener_ip(profile: RelayProfile) -> IpAddr {
match profile {
RelayProfile::SingleNode => IpAddr::V4(Ipv4Addr::LOCALHOST),
RelayProfile::Production => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
}
}
#[cfg(test)]
mod listener_tests {
use super::{health_listener_ip, RelayProfile};
#[test]
fn single_node_health_listener_is_loopback_only() {
assert!(health_listener_ip(RelayProfile::SingleNode).is_loopback());
assert!(health_listener_ip(RelayProfile::Production).is_unspecified());
}
}
async fn serve(
router: axum::Router,
health_router: axum::Router,
@@ -1347,10 +1368,11 @@ async fn serve(
) -> anyhow::Result<()> {
let config = &state.config;
let health_listener = tokio::net::TcpListener::bind(("0.0.0.0", config.health_port))
let health_host = health_listener_ip(config.profile);
let health_listener = tokio::net::TcpListener::bind((health_host, config.health_port))
.await
.map_err(|e| anyhow::anyhow!("Failed to bind health port {}: {e}", config.health_port))?;
info!(port = config.health_port, "Health probe listener started");
info!(host = %health_host, port = config.health_port, "Health probe listener started");
tokio::spawn(async move {
axum::serve(health_listener, health_router).await.ok();
});