diff --git a/backend/internal/api/handlers/crowdsec_dashboard.go b/backend/internal/api/handlers/crowdsec_dashboard.go index 35243efd..ee53f8b6 100644 --- a/backend/internal/api/handlers/crowdsec_dashboard.go +++ b/backend/internal/api/handlers/crowdsec_dashboard.go @@ -610,7 +610,12 @@ func (h *CrowdsecHandler) ExportDecisions(c *gin.Context) { sanitizeCSVField(d.Host), sanitizeCSVField(d.Country), d.CreatedAt.UTC().Format(time.RFC3339), - d.ExpiresAt.UTC().Format(time.RFC3339), + func() string { + if d.ExpiresAt != nil { + return d.ExpiresAt.UTC().Format(time.RFC3339) + } + return "" + }(), }) } w.Flush() diff --git a/backend/internal/api/handlers/crowdsec_handler.go b/backend/internal/api/handlers/crowdsec_handler.go index 157012a2..b6bbf66c 100644 --- a/backend/internal/api/handlers/crowdsec_handler.go +++ b/backend/internal/api/handlers/crowdsec_handler.go @@ -2299,13 +2299,14 @@ func (h *CrowdsecHandler) BanIP(c *gin.Context) { // Log to security_decisions for dashboard aggregation if h.Security != nil { parsedDur, _ := time.ParseDuration(duration) + expiry := time.Now().Add(parsedDur) _ = h.Security.LogDecision(&models.SecurityDecision{ IP: ip, Action: "block", Source: "crowdsec", RuleID: reason, Scenario: "manual", - ExpiresAt: time.Now().Add(parsedDur), + ExpiresAt: &expiry, }) } h.dashCache.Invalidate("dashboard") diff --git a/backend/internal/models/security_decision.go b/backend/internal/models/security_decision.go index d5befa2f..ff22e15d 100644 --- a/backend/internal/models/security_decision.go +++ b/backend/internal/models/security_decision.go @@ -18,7 +18,7 @@ type SecurityDecision struct { CreatedAt time.Time `json:"created_at" gorm:"index;compositeIndex:idx_sd_source_created,sort:desc;compositeIndex:idx_sd_source_scenario_created,sort:desc;compositeIndex:idx_sd_source_ip_created,sort:desc"` // Dashboard enrichment fields (Issue #26, PR-1) - Scenario string `json:"scenario" gorm:"index;compositeIndex:idx_sd_source_scenario_created"` - Country string `json:"country" gorm:"index;size:2"` - ExpiresAt time.Time `json:"expires_at" gorm:"index"` + Scenario string `json:"scenario" gorm:"index;compositeIndex:idx_sd_source_scenario_created"` + Country string `json:"country" gorm:"index;size:2"` + ExpiresAt *time.Time `json:"expires_at,omitempty" gorm:"index"` }