Summary
Add a new top-level key suppressed_findings to the policy evaluation result, alongside the existing findings and violations.
{
"skipped": false,
"skip_reason": "",
"violations": ["..."],
"findings": [
{ "external_id": "CVE-2023-45288", "package_purl": "pkg:golang/...", "severity": "HIGH", ... }
],
"suppressed_findings": [
{
"external_id": "CVE-2023-45283",
"package_purl": "pkg:golang/...",
"severity": "HIGH",
"chainloop_finding_id": "fnd_01J...",
"chainloop_assessment_ids": ["asm_01J...", "asm_01K..."]
}
]
}
Semantics
- Each item in
suppressed_findings uses the same Rego object as items in findings (e.g. a PolicyVulnerabilityFinding), plus two new optional fields:
chainloop_finding_id (string) — the Chainloop finding ID this Rego finding maps to.
chainloop_assessment_ids (array of strings) — the assessment IDs that drove the suppression.
findings keeps containing every emitted finding (suppressed and non-suppressed alike) so the ingestion pipeline keeps tracking them. suppressed_findings is the subset that did not contribute to violations because the platform-side assessment matched.
- Invariant: for every
f ∈ suppressed_findings, f ∈ findings. Ingestion can ignore suppressed_findings entirely if it wants.
- Empty array (or absent) when no suppression happened — same convention as
violations.
Scope
- Extend
engine.EvaluationResult with a new SuppressedFindings slice.
- Parse
suppressed_findings from the Rego result rule output and from the WASM policy output JSON.
- Add
chainloop_finding_id and chainloop_assessment_ids to the three finding proto types (PolicyVulnerabilityFinding, PolicySASTFinding, PolicyLicenseViolationFinding) as optional fields.
- Update the Rego boilerplate so policies can declare
suppressed_findings and have it default to [] and be wired into the result object automatically.
- Tests for parsing in both engines.
Ingestion-side use of the new field (filtering violations, surfacing suppressed in UI) is out of scope for this issue and can be done in follow-ups.
Summary
Add a new top-level key
suppressed_findingsto the policy evaluation result, alongside the existingfindingsandviolations.{ "skipped": false, "skip_reason": "", "violations": ["..."], "findings": [ { "external_id": "CVE-2023-45288", "package_purl": "pkg:golang/...", "severity": "HIGH", ... } ], "suppressed_findings": [ { "external_id": "CVE-2023-45283", "package_purl": "pkg:golang/...", "severity": "HIGH", "chainloop_finding_id": "fnd_01J...", "chainloop_assessment_ids": ["asm_01J...", "asm_01K..."] } ] }Semantics
suppressed_findingsuses the same Rego object as items infindings(e.g. aPolicyVulnerabilityFinding), plus two new optional fields:chainloop_finding_id(string) — the Chainloop finding ID this Rego finding maps to.chainloop_assessment_ids(array of strings) — the assessment IDs that drove the suppression.findingskeeps containing every emitted finding (suppressed and non-suppressed alike) so the ingestion pipeline keeps tracking them.suppressed_findingsis the subset that did not contribute to violations because the platform-side assessment matched.f ∈ suppressed_findings,f ∈ findings. Ingestion can ignoresuppressed_findingsentirely if it wants.violations.Scope
engine.EvaluationResultwith a newSuppressedFindingsslice.suppressed_findingsfrom the Regoresultrule output and from the WASM policy output JSON.chainloop_finding_idandchainloop_assessment_idsto the three finding proto types (PolicyVulnerabilityFinding,PolicySASTFinding,PolicyLicenseViolationFinding) as optional fields.suppressed_findingsand have it default to[]and be wired into theresultobject automatically.Ingestion-side use of the new field (filtering violations, surfacing suppressed in UI) is out of scope for this issue and can be done in follow-ups.