feat: Implement health checks, rate limiting, and security headers for services, update Node.js versions, and add Prettier configuration for frontend.

This commit is contained in:
2026-03-12 17:09:05 -03:00
parent 5e3db5f2a2
commit f9f1238310
21 changed files with 966 additions and 109 deletions
+47 -2
View File
@@ -15,12 +15,17 @@ use axum::{
middleware,
routing::{delete, get, post, put},
};
use common::health::{self, HealthState};
use dotenvy::dotenv;
use sqlx::postgres::PgPoolOptions;
use std::env;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use tower_governor::governor::GovernorConfigBuilder;
use tower_governor::GovernorLayer;
use tower_http::cors::{Any, CorsLayer};
use tower_http::set_header::SetResponseHeaderLayer;
#[tokio::main]
async fn main() {
@@ -29,11 +34,16 @@ async fn main() {
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let pool = PgPoolOptions::new()
.max_connections(5)
.max_connections(10)
.min_connections(2)
.acquire_timeout(Duration::from_secs(30))
.connect(&db_url)
.await
.expect("Failed to connect to database");
// Initialize health state
let health_state = HealthState::default();
sqlx::migrate!("./migrations")
.run(&pool)
.await
@@ -88,6 +98,15 @@ async fn main() {
.allow_methods(Any)
.allow_headers(Any);
// Rate limiting configuration
let governor_conf = Arc::new(
GovernorConfigBuilder::default()
.per_second(10)
.burst_size(50)
.finish()
.unwrap(),
);
// Rutas protegidas que requieren autenticación y contexto de organización
let protected_routes = Router::new()
.route(
@@ -299,13 +318,39 @@ async fn main() {
"/branding",
get(handlers_branding::get_organization_branding),
)
// Health check routes
.merge(health::health_routes(pool.clone()).with_state(health_state))
.nest_service("/assets", tower_http::services::ServeDir::new("uploads"))
.merge(protected_routes)
// Security headers
.layer(SetResponseHeaderLayer::overriding(
http::header::STRICT_TRANSPORT_SECURITY,
http::HeaderValue::from_static("max-age=31536000; includeSubDomains"),
))
.layer(SetResponseHeaderLayer::overriding(
http::header::X_CONTENT_TYPE_OPTIONS,
http::HeaderValue::from_static("nosniff"),
))
.layer(SetResponseHeaderLayer::overriding(
http::header::X_FRAME_OPTIONS,
http::HeaderValue::from_static("SAMEORIGIN"),
))
.layer(SetResponseHeaderLayer::overriding(
http::header::X_XSS_PROTECTION,
http::HeaderValue::from_static("1; mode=block"),
))
.layer(SetResponseHeaderLayer::overriding(
http::header::REFERRER_POLICY,
http::HeaderValue::from_static("strict-origin-when-cross-origin"),
))
.layer(cors)
.layer(GovernorLayer {
config: governor_conf,
})
.with_state(pool);
let addr = SocketAddr::from(([0, 0, 0, 0], 3001));
tracing::info!("CMS Service listening on {}", addr);
tracing::info!("CMS Service listening on {} with rate limiting and security headers", addr);
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
axum::serve(listener, public_routes).await.unwrap();
}