82 lines
2.5 KiB
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],
|
|
}
|