mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-09 04:18:52 +00:00
feat(M48): continuous TLS health monitoring — endpoint state machine, shared tlsprobe, 8 API endpoints, GUI
Adds continuous TLS endpoint health monitoring that closes the deploy→verify→monitor loop. After M25 verifies a deployment succeeded once, M48 continuously confirms it stays healthy. Key components: - Shared `internal/tlsprobe/` package extracted from network scanner for reuse - Health status state machine: healthy → degraded (2 failures) → down (5 failures), plus cert_mismatch when served fingerprint differs from expected - 8th scheduler loop (60s tick, per-endpoint configurable intervals) - PostgreSQL migration 000011: endpoint_health_checks + endpoint_health_history tables - 8 REST API endpoints (CRUD, history, acknowledge, summary) - Health Monitor GUI page with summary bar, status table, create modal, auto-refresh - 38 new tests (5 tlsprobe + 11 domain + 10 service + 8 handler + 4 frontend) - All coverage thresholds maintained (service 68%, handler 83%, domain 87%, middleware 63%) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -259,6 +259,29 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize health check service (M48)
|
||||
var healthCheckService *service.HealthCheckService
|
||||
var healthCheckHandler *handler.HealthCheckHandler
|
||||
if cfg.HealthCheck.Enabled {
|
||||
healthCheckRepo := postgres.NewHealthCheckRepository(db)
|
||||
healthCheckService = service.NewHealthCheckService(
|
||||
healthCheckRepo,
|
||||
auditService,
|
||||
logger,
|
||||
cfg.HealthCheck.MaxConcurrent,
|
||||
time.Duration(cfg.HealthCheck.DefaultTimeout)*time.Millisecond,
|
||||
cfg.HealthCheck.HistoryRetention,
|
||||
cfg.HealthCheck.AutoCreate,
|
||||
)
|
||||
healthCheckHandler = handler.NewHealthCheckHandler(healthCheckService)
|
||||
logger.Info("health check service enabled",
|
||||
"interval", cfg.HealthCheck.CheckInterval.String(),
|
||||
"max_concurrent", cfg.HealthCheck.MaxConcurrent)
|
||||
} else {
|
||||
// Create a no-op health check handler for route registration
|
||||
healthCheckHandler = handler.NewHealthCheckHandler(nil)
|
||||
}
|
||||
|
||||
logger.Info("initialized all handlers")
|
||||
|
||||
// Create context with cancellation
|
||||
@@ -289,6 +312,11 @@ func main() {
|
||||
sched.SetDigestInterval(cfg.Digest.Interval)
|
||||
logger.Info("digest scheduler enabled", "interval", cfg.Digest.Interval.String())
|
||||
}
|
||||
if healthCheckService != nil {
|
||||
sched.SetHealthCheckService(healthCheckService)
|
||||
sched.SetHealthCheckInterval(cfg.HealthCheck.CheckInterval)
|
||||
logger.Info("health check scheduler enabled", "interval", cfg.HealthCheck.CheckInterval.String())
|
||||
}
|
||||
|
||||
// Start scheduler
|
||||
logger.Info("starting scheduler")
|
||||
@@ -319,6 +347,7 @@ func main() {
|
||||
Verification: verificationHandler,
|
||||
Export: exportHandler,
|
||||
Digest: *digestHandler,
|
||||
HealthChecks: healthCheckHandler,
|
||||
})
|
||||
// Register EST (RFC 7030) handlers if enabled
|
||||
if cfg.EST.Enabled {
|
||||
|
||||
Reference in New Issue
Block a user