# ----------------------------------------------------------------------------- # kev-blocker.rego # Sprint: SPRINT_20260118_027_Policy_cve_release_gates # Task: TASK-027-08 - OPA/Rego Policy Examples # Description: CISA KEV catalog blocking policy # ----------------------------------------------------------------------------- package stellaops.gates.kev import future.keywords.if import future.keywords.in # Default allow if no KEV CVEs found default allow = true # Block if any CVE is in KEV catalog allow = false if { some cve in relevant_cves cve.is_kev == true } # Get CVEs to evaluate (optionally filtered by reachability) relevant_cves := [cve | some cve in input.cve_findings config_only_reachable cve.is_reachable == true ] relevant_cves := input.cve_findings if { not config_only_reachable } # Configuration flags config_only_reachable if { input.config.only_reachable == true } # Denial messages with KEV details deny[msg] if { some cve in relevant_cves cve.is_kev == true not cve.kev_due_date msg := sprintf("CVE %s is in CISA KEV catalog (actively exploited)", [cve.cve_id]) } deny[msg] if { some cve in relevant_cves cve.is_kev == true cve.kev_due_date msg := sprintf("CVE %s is in CISA KEV catalog, due date: %s", [ cve.cve_id, cve.kev_due_date ]) } # Collect all KEV CVEs kev_cves := [cve | some cve in relevant_cves cve.is_kev == true ] # Check for overdue KEV CVEs (if current_time provided) overdue_kev_cves := [cve | some cve in kev_cves cve.kev_due_date input.current_time time.parse_rfc3339_ns(cve.kev_due_date) < time.parse_rfc3339_ns(input.current_time) ] # Summary for reporting summary := { "total_cves": count(relevant_cves), "kev_count": count(kev_cves), "overdue_count": count(overdue_kev_cves), "kev_cves": [{"cve_id": cve.cve_id, "due_date": cve.kev_due_date} | some cve in kev_cves ], }