# ----------------------------------------------------------------------------- # reachable-cve.rego # Sprint: SPRINT_20260118_027_Policy_cve_release_gates # Task: TASK-027-08 - OPA/Rego Policy Examples # Description: Reachability-aware CVE blocking policy # ----------------------------------------------------------------------------- package stellaops.gates.reachable import future.keywords.if import future.keywords.in # Default allow if no reachable high-severity CVEs default allow = true # Block if any reachable CVE exceeds severity threshold allow = false if { some cve in input.cve_findings is_blocking_reachable(cve) cve.cvss_score >= severity_threshold } # Determine if CVE's reachability state is blocking is_blocking_reachable(cve) if { cve.is_reachable == true } is_blocking_reachable(cve) if { cve.reachability_state in blocking_states } # Reachability states that trigger blocking blocking_states := {"confirmed_reachable", "runtime_observed", "statically_reachable"} # Non-blocking reachability states non_blocking_states := {"not_reachable", "unknown"} # Get severity threshold with environment override support severity_threshold := env_config.severity_threshold if { env_config := input.config.environments[input.environment] env_config.severity_threshold } else := input.config.severity_threshold if { input.config.severity_threshold } else := 7.0 # Default threshold (High severity) # Denial messages with reachability details deny[msg] if { some cve in input.cve_findings is_blocking_reachable(cve) cve.cvss_score >= severity_threshold msg := sprintf("Reachable CVE %s exceeds severity threshold: CVSS %.1f >= %.1f (state: %s)", [ cve.cve_id, cve.cvss_score, severity_threshold, object.get(cve, "reachability_state", "reachable") ]) } # Collect blocking CVEs blocking_cves := [cve | some cve in input.cve_findings is_blocking_reachable(cve) cve.cvss_score >= severity_threshold ] # Collect allowed unreachable CVEs (for reporting) allowed_unreachable := [cve | some cve in input.cve_findings cve.cvss_score >= severity_threshold not is_blocking_reachable(cve) ] # Summary for reporting summary := { "total_cves": count(input.cve_findings), "reachable_high_severity": count(blocking_cves), "unreachable_high_severity": count(allowed_unreachable), "severity_threshold": severity_threshold, "blocking_cves": [cve.cve_id | some cve in blocking_cves], "allowed_unreachable": [cve.cve_id | some cve in allowed_unreachable], }