Skip to content

Rego policy eval produces SARIF-Report with duplicate results #1504

@timbastin

Description

@timbastin

The policy evaluation produces currently a sarif report with duplicate result entries.

How to reproduce

Here is the rego policy and the command i fired up:

devguard-scanner attestations registry.opencode.de/open-code/oci/debian:13-minimal --policy example.rego

Here is the .rego policy:

# METADATA
# title: example Policy
# custom:
#   description: example description
#   priority: 1
#   predicateType: https://cyclonedx.org/vex
#   relatedResources: []
#   tags:
#   - Legal
#   complianceFrameworks: []

package compliance

import rego.v1

# helper functions to extract info from vulnerabilities

# figure out how severe a vulnerability is
# we prefer cvss ratings when available, otherwise use whatever rating comes first
severity(vulnerability) := lower(rating.severity) if {
  some rating in vulnerability.ratings
  startswith(rating.method, "CVSS")
} else := lower(vulnerability.ratings[0].severity) if {
  count(vulnerability.ratings) > 0
}

# check if this vulnerability actually affects us
is_exploitable(vulnerability) if {
  vulnerability.analysis.state == "exploitable"
}

# check if we're still figuring out if this vulnerability matters
is_in_triage(vulnerability) if {
  vulnerability.analysis.state == "in_triage"
}

# check if someone marked this as a false alarm
is_false_positive(vulnerability) if {
  vulnerability.analysis.justification == "false_positive"
}

# check if vulnerability is unhandled (either exploitable or open)
is_affected(vuln) if is_exploitable(vuln)
is_affected(vuln) if is_in_triage(vuln)

# then use it simply
in_triage_vulns := [vuln |
  vuln := input.vulnerabilities[_]
  is_in_triage(vuln)
]

# list all critical or high vulnerabilities still being investigated
high_or_critical_in_triage_vulns := [vuln |
  vuln := in_triage_vulns[_]
  severity(vuln) in {"critical", "high"}
]

# count how many got dismissed as false positives
cve_false_positive := count([vuln |
  vuln := input.vulnerabilities[_]
  is_false_positive(vuln)
])

# count vulnerabilities that match a severity level and are exploitable
count_exploitable_or_open(severity_level) := count([vuln |
  vuln := input.vulnerabilities[_]
  severity(vuln) == severity_level
  is_affected(vuln)
])

# build violation messages for each unhandled vulnerability
violations := [sprintf("%s (%s severity) is in triage and must be handled.", [vuln.id, severity(vuln)]) | vuln := high_or_critical_in_triage_vulns[_]]

cve_critical := count_exploitable_or_open("critical")
cve_high := count_exploitable_or_open("high")
cve_medium := count_exploitable_or_open("medium")
cve_low := count_exploitable_or_open("low")
cve_open := count(in_triage_vulns)

# figure out when the last update happened
# grab all the timestamps we can find from the vulnerability data
all_timestamps := [timestamp |
  vuln := input.vulnerabilities[_]
  timestamp := [vuln.analysis.lastUpdated, vuln.analysis.firstIssued][_]
  timestamp != ""
]

# find the most recent one
last_update := max([time.parse_rfc3339_ns(ts) | ts := all_timestamps[_]]) if {
  count(all_timestamps) > 0
} else := 0

# decide if the container is compliant
# rule is simple: no critical or high severity exploitable vulnerabilities allowed

default compliant := false

compliant := true if {
  count(high_or_critical_in_triage_vulns) == 0
}

# put everything together in the final result
result := {
  "compliant": compliant,
  "violations": violations,
  "cve_critical": cve_critical,
  "cve_high": cve_high,
  "cve_medium": cve_medium,
  "cve_low": cve_low,
  "cve_open": cve_open,
  "cve_false_positive": cve_false_positive,
  "last_update_unix": last_update / 1000 / 1000,
}
# output with duplicate results
{
  "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
  "runs": [
    {
      "results": [
        {
          "kind": "pass",
          "locations": [
            {
              "message": {
                "text": "The attestation is compliant with the policy."
              },
              "physicalLocation": {
                "artifactLocation": {
                  "description": {
                    "text": ""
                  },
                  "uri": "oci://registry.opencode.de/open-code/oci/debian:13-minimal"
                }
              }
            }
          ],
          "message": {
            "text": "Policy compliant"
          },
          "properties": {
            "tags": [
              "Legal"
            ],
            "AdditionalProperties": {
              "precision": "high"
            }
          },
          "ruleID": "example.rego"
        },
        {
          "kind": "pass",
          "locations": [
            {
              "message": {
                "text": "The attestation is compliant with the policy."
              },
              "physicalLocation": {
                "artifactLocation": {
                  "description": {
                    "text": ""
                  },
                  "uri": "oci://registry.opencode.de/open-code/oci/debian:13-minimal"
                }
              }
            }
          ],
          "message": {
            "text": "Policy compliant"
          },
          "properties": {
            "tags": [
              "Legal"
            ],
            "AdditionalProperties": {
              "precision": "high"
            }
          },
          "ruleID": "example.rego"
        },
        {
          "kind": "pass",
          "locations": [
            {
              "message": {
                "text": "The attestation is compliant with the policy."
              },
              "physicalLocation": {
                "artifactLocation": {
                  "description": {
                    "text": ""
                  },
                  "uri": "oci://registry.opencode.de/open-code/oci/debian:13-minimal"
                }
              }
            }
          ],
          "message": {
            "text": "Policy compliant"
          },
          "properties": {
            "tags": [
              "Legal"
            ],
            "AdditionalProperties": {
              "precision": "high"
            }
          },
          "ruleID": "example.rego"
        },
        {
          "kind": "pass",
          "locations": [
            {
              "message": {
                "text": "The attestation is compliant with the policy."
              },
              "physicalLocation": {
                "artifactLocation": {
                  "description": {
                    "text": ""
                  },
                  "uri": "oci://registry.opencode.de/open-code/oci/debian:13-minimal"
                }
              }
            }
          ],
          "message": {
            "text": "Policy compliant"
          },
          "properties": {
            "tags": [
              "Legal"
            ],
            "AdditionalProperties": {
              "precision": "high"
            }
          },
          "ruleID": "example.rego"
        }
      ],
      "tool": {
        "driver": {
          "name": "devguard-attestations",
          "rules": [
            {
              "fullDescription": {
                "text": "Example description"
              },
              "help": {
                "text": "Example description"
              },
              "id": "example.rego",
              "name": "example Policy",
              "properties": {
                "tags": [
                  "Legal"
                ],
                "AdditionalProperties": {
                  "complianceFrameworks": [],
                  "predicateType": "https://cyclonedx.org/vex",
                  "priority": 1,
                  "relatedResources": []
                }
              },
              "shortDescription": {
                "text": "example Policy"
              }
            }
          ]
        }
      }
    }
  ],
  "version": "2.1.0"
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions