Files
git.stella-ops.org/examples/policies/opa/reachable-cve.rego

82 lines
2.5 KiB
Rego

# -----------------------------------------------------------------------------
# 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],
}