Skip to content

Instantly share code, notes, and snippets.

@ctron
Last active September 3, 2026 14:49
Show Gist options
  • Select an option

  • Save ctron/6bfcb575068f52a2fb90a5ab0c1176b9 to your computer and use it in GitHub Desktop.

Select an option

Save ctron/6bfcb575068f52a2fb90a5ab0c1176b9 to your computer and use it in GitHub Desktop.

Correlation Test Suite (TC-5639) β€” Scenario Evaluation

Evaluation of 18 test scenarios (S1–S18) against their referenced Jira tickets and the governing specifications (CSAF v2.0, OSV Schema, VEX consumer requirements, RPM versioning).

S1–S14 from commit 8e614fea (PR #2613). S15–S18 from open PRs #2621, #2625, #2626, #2627 (2026-09-03).

Overall verdict: all 18 scenarios have correct expectations per spec.

Three scenarios fully pass today (S6, S7, S8). Thirteen are #[ignore] with partial or full assertion failures. Two (S1, S10) are #[ignore] but show interesting partial passes that reveal the engine's CPE-filter behavior.

Legend: 🟒 assertion passes Β· πŸ”΄ assertion fails Β· 🟑 vacuous pass (right answer, wrong reason) Β· πŸ’₯ test crashes before reaching this assertion


S1 β€” Cross-stream bind-libs

Field Value
Jira TC-5640 β€” /vulnerability/analyze returns false "affected" for RHEL RPMs (cross-stream version-range matching)
Status #[ignore] β€” 8/18 pass, 10/18 fail
Bug RPM version-range check is not stream-aware; an el8 NVR matches el9/el10 fix ranges because rpmvercmp doesn't understand dist tags (.el8 vs .el9)

What the test expects:

SBOM variant CVE-2022-0396 CVE-2023-5517 CVE-2024-4076
el8.10 (at fix) πŸ”΄ not_affected πŸ”΄ not_affected πŸ”΄ not_affected
el8.10 describing-CPE 🟒 not_affected 🟒 not_affected 🟒 not_affected
el9.0 below-fix 🟒 affected πŸ”΄ not_affected 🟒 affected
el9.0 at-fix 🟒 affected πŸ”΄ not_affected πŸ”΄ not_affected
el9.0 above-fix 🟒 affected πŸ”΄ not_affected πŸ”΄ not_affected
el10 🟒 not_affected πŸ”΄ affected πŸ”΄ affected

Key finding: The el8.10 describing-CPE variant passes all 3 assertions β€” the CPE-context filter correctly blocks cross-stream matches when the describing CPE is on the root node. The plain el8.10 (no CPE) fails because the filter has nothing to engage on. The el10 assertions fail because known_affected entries for el10 (bare, no version) create no matchable rows (TC-5732).

Spec evaluation:

CSAF v2.0 Β§3.1.3 binds each component to a product stream via relationships in the product_tree. The composite product_id (e.g. red_hat_enterprise_linux_8:bind-libs) carries an implicit CPE scope. A consumer MUST only match an SBOM component against product_status entries whose product_id shares the same stream CPE.

rpmvercmp (rpm-version(7)) is purely mechanical β€” it compares segments left-to-right with no awareness that .el8 and .el9 denote different distribution streams. Cross-stream comparison is semantically invalid; the CSAF product identity (CPE context) must be used to prevent it.

The expectation that el8 packages are judged only against el8 fix lines (and likewise for el9, el10) is correct per CSAF product_tree semantics. CVE-2022-0396 remaining affected on el9 (no el9 fix exists) is also correct β€” absence of a fixed entry means no remediation.

Verdict: CORRECT


S2 β€” Wrong-scheme golang/OCI

Field Value
Jira TC-5170 β€” Trustify returns vulnerabilities for SBOM sub-components instead of the queried PURL
Status #[ignore] β€” 2/5 pass, 3/5 fail
Bug get_product_statuses_for_purl doesn't filter by version scheme; RPM version ranges returned for Maven/OCI/any PURL sharing the same base name

What the test expects:

SBOM variant CVE-2023-44487
storage3 in-range 🟒 affected
RPM golang πŸ”΄ not_affected
RPM golang in-range πŸ”΄ not_affected
OCI golang πŸ”΄ not_affected
el8cpe in-range 🟒 not_affected

Key finding: The el8cpe variant passes β€” when the SBOM carries a describing CPE for RHEL 8, the CPE-context filter correctly blocks the Storage 3 advisory. The RPM/OCI variants without a describing CPE fail.

Spec evaluation:

The CSAF advisory scopes golang as known_affected under the Red Hat Storage 3 product tree (CPE: cpe:/a:redhat:storage:3). The advisory's product_identification_helper binds the component to a specific product stream. Matching an unrelated pkg:rpm/... or pkg:oci/... PURL against a Storage 3 advisory is a product identity violation per CSAF Β§3.1.3.

Even when the bare package name matches (golang), the PURL type and product CPE differ. The version-in-range check for RPM/OCI variants is a category error β€” product identity must be established first.

Verdict: CORRECT


S3 β€” Wrong-product curl/hummingbird

Field Value
Jira TC-5171 β€” Trustify returns purl_statuses with RPM version ranges and RHEL CPE contexts for non-RPM packages
Status #[ignore] β€” 6/12 pass, 6/12 fail
Bug CSAF advisories for one Red Hat product (hummingbird) matched against a different product's PURLs (RHEL 8 curl) without checking CPE context

What the test expects:

SBOM variant CVE-2024-2398 CVE-2025-10148 CVE-2025-10966 CVE-2025-13034
el8 curl (past fix) πŸ”΄ not_affected πŸ”΄ not_affected πŸ”΄ not_affected 🟒 affected
el8 curl below-fix 🟒 affected πŸ”΄ not_affected πŸ”΄ not_affected 🟒 affected
el8 curl with el8 CPE 🟒 not_affected 🟒 not_affected 🟒 not_affected πŸ”΄ affected

Key finding: The el8 CPE variant correctly blocks hummingbird advisories for the first 3 CVEs (CPE filter engaged), but CVE-2025-13034 fails β€” its bare known_affected (no version) creates no matchable row (TC-5732), so even the correctly-scoped el8 advisory is missed.

Spec evaluation:

CSAF product_tree.relationships bind curl to specific product streams. Hummingbird's curl and RHEL 8's curl have distinct CPE contexts. A consumer MUST resolve the full product_id (including stream CPE) before evaluating product_status.

For CVE-2025-10148 and CVE-2025-10966, the advisory carries explicit known_not_affected entries for RHEL 8 curl. Per VEX consumer requirements (CISA Use Cases for VEX, CSAF Β§3.2.3.9), known_not_affected is an authoritative negative β€” the consumer MUST suppress the finding.

CVE-2025-13034 has a bare known_affected for el8 curl (no version) β€” meaning "all versions in this stream are affected." This is correctly expected as affected.

Verdict: CORRECT


S4 β€” Wrong-product chardet/satellite

Field Value
Jira TC-5171 β€” same as S3
Status #[ignore] β€” 3/6 pass, 3/6 fail
Bug Same CPE-context issue: Satellite advisories matched to RHEL 8 python3-chardet

What the test expects:

SBOM variant CVE-2018-11751 CVE-2018-3258 CVE-2019-0231
el8 python3-chardet πŸ”΄ not_affected πŸ”΄ not_affected πŸ”΄ not_affected
el8 chardet + el8 CPE 🟒 not_affected 🟒 not_affected 🟒 not_affected

Key finding: With a describing CPE on the SBOM, the CPE-context filter correctly blocks all Satellite advisories. Without it, all 3 CVEs leak through as false positives.

Spec evaluation:

Clean case of product-scope violation. python3-chardet appears in the CSAF product_tree only under Red Hat Satellite (el7). RHEL 8 has no chardet entry at all β€” the component is absent from the RHEL 8 product stream in the advisory. A consumer finding no matching product_id for the SBOM's CPE context should report zero vulnerabilities.

Verdict: CORRECT


S5 β€” At-fix openssl

Field Value
Jira TC-5641 β€” SBOM Vulnerabilities screen (/sbom/{id}/advisory) unchanged 3.0 vs 3.1 β€” product_status path skips version_matches
Status #[ignore] β€” 2/4 pass, 2/4 fail
Bug product_status matching in /sbom/advisory matches by name only with no version comparison; patched RPMs still reported affected (234 name-matches, 0 pass version_matches, 16 over-reported CVEs)

What the test expects:

SBOM variant CVE-2022-4304 CVE-2023-0215
below-fix (1.1.1k-7.el8) 🟒 affected 🟒 affected
at-fix (1.1.1k-9.el8_7) πŸ”΄ not_affected πŸ”΄ not_affected

Key finding: Below-fix correctly shows affected (name match + version in range). At-fix incorrectly also shows affected because product_status skips version_matches entirely β€” name match alone triggers the result.

Spec evaluation:

Both CVEs are fixed at openssl-1.1.1k-9.el8_7 per the CSAF advisory. CSAF product_status.fixed references the product_id of the specific fixed build. An SBOM component at or above the fix version must be reported as not_affected (the fix is applied). Below the fix version, the component falls within the affected range.

Per RPM versioning: 1.1.1k-7.el8 < 1.1.1k-9.el8_7 (release segment 7 < 9). Version comparison is straightforward within the same stream.

Verdict: CORRECT


S6 β€” OSV baseline urllib3 (regression guard)

Field Value
Jira None (regression guard)
Status 🟒 PASSING β€” 9/9 pass

What the test expects:

SBOM variant / PURL CVE-2023-45803
pkg:pypi/urllib3@1.26.17 🟒 affected
pkg:pypi/urllib3@1.26.18 🟒 not_affected
pkg:rpm/redhat/python3-urllib3 🟒 not_affected

Tests all three endpoints: /sbom/advisory, /vulnerability/analyze, /purl/{key}.

Spec evaluation:

OSV advisory GHSA-g4mx-q9vg-27p4 declares: introduced: "0", fixed: "1.26.18", ecosystem: PyPI. Per OSV spec, fixed is an exclusive upper bound β€” 1.26.17 is in range [0, 1.26.18) and is affected; 1.26.18 is at the fix boundary and is NOT affected.

The RPM variant (pkg:rpm/redhat/python3-urllib3) is a different ecosystem entirely. OSV matching is ecosystem-scoped; a PyPI advisory does not apply to RPM packages.

Verdict: CORRECT (textbook OSV range evaluation)


S7 β€” CPE-only hummingbird node

Field Value
Jira TC-5630 β€” SBOM vulnerability count mismatch: CPE-only nodes without a PURL are dropped from detail endpoints
Status 🟒 PASSING β€” 3/3 pass

What the test expects:

SBOM variant CVE-2026-12151 CVE-2026-16730 CVE-2026-33815
cpeonly_hummingbird 🟒 affected 🟒 affected 🟒 affected

Only /sbom/{id}/advisory is tested β€” /vulnerability/analyze and /purl/{key} require a PURL, which this CPE-only node does not have.

Spec evaluation:

CVE records include affected[].cpes for product identification. CPE is a valid identification method alongside PURL. An SBOM component identified solely by CPE (no PURL) should still correlate against CVE affected entries whose CPE matches.

The Jira notes that while this test passes for /sbom/advisory, the detail endpoints still drop CPE-only matches (list count 44, detail count 28). The test correctly limits its scope to the working endpoint.

Verdict: CORRECT


S8 β€” Epoch mismatch openjdk

Field Value
Jira TC-5733 β€” rpmver_cmp ignores RPM epoch β€” asymmetric epoch yields wrong affected verdict
Status 🟒 PASSING β€” 6/6 pass (bug is latent)
Bug rpmver_cmp doesn't tokenize : for epoch; when the SBOM PURL has ?epoch= but the advisory omits it (or vice versa), comparison misaligns. Currently latent until version_matches is applied on the affected path.

What the test expects:

SBOM variant CVE-2026-41254 CVE-2026-46968 CVE-2026-47010
no-epoch PURL 🟒 affected 🟒 affected 🟒 affected
with-epoch PURL 🟒 affected 🟒 affected 🟒 affected

Key finding: All 6 assertions pass today. The epoch bug is latent β€” it only manifests once version_matches is applied on the affected path (which TC-5641/TC-5751 will enable). The test remains #[ignore] as a proactive regression guard for when that fix lands.

Spec evaluation:

Per rpm-version(7), epoch is the most significant component of the EVR (Epoch:Version-Release) tuple. Omitted epoch defaults to implicit 0. Therefore epoch=0 and no epoch are semantically identical, and the comparison result MUST be epoch-invariant when both effectively carry epoch 0.

The test correctly asserts identical verdicts for both variants. If a future fix adds epoch awareness to rpmver_cmp, both SBOMs (both below the el8 fix) should still produce "affected."

Verdict: CORRECT


S9 β€” Sub-stream openssl el8

Field Value
Jira TC-5640 β€” same root cause as S1
Status #[ignore] β€” 1/2 pass, 1/2 fail
Bug Same cross-stream issue but within the same RHEL major: el8.2 EUS builds mis-compared against el8 GA / el8.10 fix ranges

What the test expects:

SBOM variant CVE-2023-0286
el8.2 below-fix (1.1.1c-15.el8_2) 🟒 affected
el8.2 patched (1.1.1c-21.el8_2) πŸ”΄ not_affected

Key finding: Below-fix correctly matches (version in range). Patched fails because the engine does not apply version_matches to the product_status path β€” the name match alone triggers the result, same as S5.

Spec evaluation:

CSAF advisories for RHEL EUS streams scope their product_status entries to specific sub-stream CPEs (e.g. cpe:/o:redhat:rhel_eus:8.2). An el8.2 SBOM must be compared against the el8.2-specific fix, not the el8 GA or el8.10 fix line. The advisory's fixed product_id includes the sub-stream CPE context.

Within the el8.2 stream, RPM version comparison is straightforward: 1.1.1c-15.el8_2 < 1.1.1c-21.el8_2 (release 15 < 21).

Verdict: CORRECT


S10 β€” Combined describing-CPE baseline

Field Value
Jira TC-5750 β€” CPE-context filter disabled for SBOMs whose product CPE is on a child node; TC-5730 β€” known_not_affected ignored
Status #[ignore] β€” 4/5 pass, 1/5 fail
Bug sbom_describing_cpe only populated from Describes-relationship nodes; child/OS CPEs produce no row; filter escape hatch disables filtering entirely

What the test expects:

SBOM variant CVE-2022-4304 CVE-2023-45803 CVE-2024-4076 CVE-2024-6602
combined_el8 (openssl + urllib3) 🟒 affected 🟒 affected 🟒 not_affected β€”
thunderbird root-CPE β€” β€” β€” 🟒 not_affected
thunderbird child-CPE β€” β€” β€” πŸ”΄ not_affected

Key finding: 4 of 5 assertions pass. Only the child-CPE variant fails, precisely confirming TC-5750: the CPE-context filter works when the describing CPE is on the root node (root-CPE passes) but not when it is on a child/OS component (child-CPE fails). The combined_el8 SBOM also uses a root CPE and passes all 3 assertions.

Spec evaluation:

This scenario combines multiple spec requirements:

  1. CSAF product scoping: CVE-2024-4076 (bind) is not present in the el8 SBOM β€” not_affected. Correct per product_tree matching.
  2. OSV ecosystem matching: CVE-2023-45803 (urllib3) matches via PyPI ecosystem, independent of the SBOM's describing CPE. OSV matching is ecosystem-scoped, not product-CPE-scoped. Correct.
  3. CSAF known_not_affected: CVE-2024-6602 has explicit known_not_affected for the thunderbird el8 product. Per VEX consumer requirements, this MUST suppress the finding.
  4. Child-CPE equivalence: CycloneDX and SPDX allow the product CPE to appear on any component (root or child OS package). The CPE context filter must work regardless of hierarchy position.

Verdict: CORRECT


S11 β€” Bare known_affected firefox

Field Value
Jira TC-5732 β€” Version-less CSAF known_affected produces no matchable row β€” genuine vulnerability missed (false negative)
Status #[ignore] β€” 0/2 pass (1 fail, 1 vacuous)
Bug Bare known_affected (no version) in csaf/creator.rs creates no row; coupled with describing-CPE filter, sub-stream fixed rows excluded β€” false negative for backport errata

What the test expects:

SBOM variant CVE-2023-6135
main_el8 firefox πŸ”΄ affected
eus8.8 patched firefox 🟑 not_affected (vacuous)

Key finding: main_el8 returns an empty advisory list β€” bare known_affected creates no correlation row at all (false negative). The eus8.8 assertion nominally passes, but only because the entire CVE is absent from correlation β€” not because the engine correctly applied a fixed status for the sub-stream. This is a vacuous pass.

Spec evaluation:

CSAF allows known_affected entries that reference a product_id without a version qualifier. This means "the component in this product stream is affected" β€” all versions are implicitly vulnerable unless overridden by a more specific status (e.g. a fixed entry for a sub-stream).

For the main el8 stream (GA), bare known_affected β€” affected for any version. For the EUS 8.8 sub-stream, a fixed entry exists with the patched build β€” not_affected. The fixed status for the specific sub-stream takes precedence.

This is consistent with CSAF Β§6.1.6 (no contradicting statuses within one vulnerability) β€” the GA known_affected and the EUS 8.8 fixed reference different product_ids (different sub-stream CPEs), so there is no contradiction.

Verdict: CORRECT


S12 β€” known_not_affected ignored thunderbird

Field Value
Jira TC-5730 β€” Correlation ignores CSAF known_not_affected: explicitly not-affected packages still reported affected
Status #[ignore] β€” 0/3 pass (1 fail, 2 crash)
Bug Correlation queries only read status='affected'; no suppression step consults not_affected. Vendor's explicit "not vulnerable" declaration is inert

What the test expects:

Endpoint CVE-2024-6602
/sbom/advisory πŸ”΄ not_affected
/vulnerability/analyze πŸ’₯ not_affected
/purl/{key} πŸ’₯ not_affected

Tests all three endpoints. Includes a control VEX file (without the known_not_affected entry) for contrast.

Key finding: The /sbom/advisory assertion fails (CVE-2024-6602 present when it should be suppressed). The /vulnerability/analyze call then crashes with an actix deserialization panic, preventing the /purl assertion from being reached. The crash is a secondary bug β€” likely an unexpected response shape when the PURL resolves to inconsistent data.

Spec evaluation:

This is one of the most fundamental VEX requirements. CSAF v2.0 Β§3.2.3.9 defines known_not_affected as an authoritative vendor statement that the product is NOT vulnerable. The CISA VEX Use Cases document states that a VEX consumer encountering not_affected MUST suppress the vulnerability for that product β€” no remediation needed.

Ignoring known_not_affected violates both the CSAF specification and the VEX operational model. It produces false positives that directly contradict the vendor's assessment.

Verdict: CORRECT


S13 β€” Aliasless OSV afire

Field Value
Jira TC-5731 β€” OSV/CSAF advisory with no CVE alias is dropped from correlation (false negative)
Status #[ignore] β€” 0/3 pass
Bug OSV loader gates all correlation on CVE-prefixed aliases; ~41% of crates.io OSV feed has no CVE alias. GHSA-only / PYSEC / RUSTSEC / MAL advisories are ingested but create no purl_status

What the test expects:

Endpoint GHSA-3227-r97m-8j95
/sbom/advisory πŸ”΄ affected
/vulnerability/analyze πŸ”΄ affected
/purl/{key} πŸ”΄ affected

Tests all three endpoints. Uses the GHSA id as the vulnerability identifier (not a CVE).

Key finding: All three endpoints return empty results. The OSV advisory is ingested but creates zero correlation rows because the loader requires a CVE-prefixed alias to proceed. Complete false negative.

Spec evaluation:

OSV Schema Β§1: the id field is the primary, authoritative identifier. The aliases field is optional β€” it links related identifiers but is not required. A GHSA, RUSTSEC, PYSEC, or MAL id is a fully valid standalone vulnerability identifier.

The OSV IsVulnerable evaluation algorithm (Β§5) operates on the affected[] array using package + ranges/versions. It does not require or reference aliases at any step.

GHSA-3227-r97m-8j95 declares afire affected in range [0.2.1, 1.1.0) with ecosystem type. Version 1.0.0 is within this range β€” affected.

Gating correlation on CVE aliases creates a systematic blind spot for ~41% of the crates.io advisory feed and similar proportions in other ecosystems.

Verdict: CORRECT


S14 β€” Product-status version-filter netty

Field Value
Jira TC-5750 β€” CPE-context filter disabled for child-node CPEs; TC-5751 β€” Apply version_matches to product_status CTEs
Status #[ignore] β€” 2/3 pass, 1/3 fail
Bug Product-status matching applies the product stream's version range (e.g. RH-SSO [7.0.0, 8.0.0)) to the component's version (netty 4.1.45.Final) β€” a category error

What the test expects:

Endpoint CVE-2021-37136
/sbom/advisory 🟒 affected
/vulnerability/analyze πŸ”΄ affected
/purl/{key} 🟒 affected

Tests all three endpoints.

Key finding: /sbom/advisory and /purl correctly report affected, but /vulnerability/analyze returns empty β€” a cross-endpoint inconsistency, which is exactly what the parent epic TC-5639 documents. The three endpoints use independent SQL codepaths that apply matching rules inconsistently.

Spec evaluation:

The CSAF product_tree structure for this advisory is:

vendor -> Red Hat
  +- product_family -> RH-SSO
       +- product_name -> Red Hat Single Sign-On 7
            +- [relationship] -> netty-codec-http (component)

The version range [7.0.0, 8.0.0) on the product_name branch refers to the RH-SSO product stream version, NOT to netty's version (4.1.45.Final). Comparing the component version against the product stream range is semantically invalid β€” the two version spaces are unrelated.

The correct evaluation: the SBOM's describing CPE matches the advisory's product CPE (RH-SSO 7), and the component (netty-codec-http) appears in known_affected under that product β€” affected. No component-version comparison against the product stream range should occur.

Verdict: CORRECT


S15 β€” RPM version-comparison openssh (PR #2621)

Field Value
Jira TC-5170 β€” child-node CPE escape hatch disables version_matches; TC-5640 β€” rpmvercmp ignores dist tag
PR #2621
Status #[ignore] β€” 6/9 pass, 3/9 fail
Bug Two defects isolated: (1) child-node CPE β†’ product_status matches by name only, no version_matches; (2) rpmvercmp ignores dist tags β†’ uncovered sub-stream .el8_10 compared against .el8_8 fix

What the test expects:

Product (enterprise_linux:8) and package (openssh) held constant; varies CPE placement (root vs child), sub-stream coverage, and version relative to fix. Uses real CVE-2023-38408 CSAF.

Group SBOM CPE on openssh Sub-stream in VEX? Expected Engine today
A root/same rootcpe el8_8 below-fix root 8.0p1-4.el8_8 yes affected 🟒 affected
A rootcpe el8_8 at-fix root 8.0p1-19.el8_8 yes not_affected 🟒 not_affected
A rootcpe el8_8 above-fix root 8.0p1-29.el8_8 yes not_affected 🟒 not_affected
B root/different rootcpe el8_10 below-fix root 8.0p1-4.el8_10 no not_affected πŸ”΄ affected (TC-5640)
B rootcpe el8_10 at-fix root 8.0p1-19.el8_10 no not_affected 🟒 not_affected
B rootcpe el8_10 above-fix root 8.0p1-29.el8_10 no not_affected 🟒 not_affected
C child/same child el8 below-fix child 8.0p1-4.el8_8 yes affected 🟒 affected
C child el8 at-fix child 8.0p1-19.el8_8 yes not_affected πŸ”΄ affected (TC-5170)
C child el8 above-fix child 8.0p1-29.el8_8 yes not_affected πŸ”΄ affected (TC-5170)

Key findings:

  • Group A (root-CPE, same sub-stream) is fully correct β€” version_matches works when CPE is captured.
  • B-below leaks via TC-5640: the el8_10 build matches the el8_8 fix because the dist tag is ignored. At/above don't leak because release β‰₯ the borrowed fix release.
  • C-at/above leak via TC-5170: child-node CPE triggers the escape hatch, product_status skips version_matches entirely.
  • The A↔C contrast (identical builds, only CPE placement differs) cleanly isolates the CPE-capture effect.

Verdict: CORRECT


S16 β€” Cross-scheme golang PURL-query (PR #2625)

Field Value
Jira TC-5170 β€” cross-scheme name-only match
PR #2625
Status #[ignore] β€” 1/3 pass, 2/3 fail
Bug get_product_statuses_for_purl matches golang by base name without checking PURL scheme or product context

What the test expects:

Non-RPM golang PURLs (OCI, Maven) must not inherit a product_status whose version range belongs to RPM golang under Red Hat Storage 3. Uses synthetic CVE-2023-44487 CSAF.

SBOM CPE on pkg@version (scheme) Expected Engine today
golang_rpm_storage3 root golang@3.5.0 (rpm) affected 🟒 affected
golang_oci none golang@1.25 (oci) not_affected πŸ”΄ affected (TC-5170)
golang_maven none golang@3.5.0 (maven) not_affected πŸ”΄ affected (TC-5170)

Key finding: Positive control (RPM Storage 3) fires correctly. OCI and Maven both leak β€” the TC-5170 cross-scheme name-only match. The positive control passes by a coincidental version match (component major 3 = product major 3).

Verdict: CORRECT


S17 β€” Cross-product OCP-kernel vs Go (PR #2626)

Field Value
Jira TC-5171 β€” CPE context not checked (couplings TC-5640, TC-5750)
PR #2626
Status #[ignore] β€” 4/5 pass, 1/5 fail
Bug RHEL 8 kernel name-matches the OCP-scoped kernel entry because the CPE context isn't checked

What the test expects:

A plain RHEL 8 kernel must not match the OCP-scoped kernel entry that a Go CVE advisory bundles. Uses real CVE-2023-24538 CSAF. Two axes: cross-product CPE-context (RHEL 8 kernel) and version (go-toolset).

Axis SBOM CPE on pkg@version Expected Engine today
CPE-context kernel_rhel8 child kernel@4.18.0-553.el8_10 not_affected πŸ”΄ affected (TC-5171/5750)
CPE-context kernel_rhel8_rootcpe root kernel@4.18.0-553.el8_10 not_affected 🟒 not_affected
version gotoolset below-fix child go-toolset@1.19.4-1.el7_9 affected 🟒 affected
version gotoolset at-fix child go-toolset@1.19.9-1.el7_9 not_affected 🟒 not_affected
version gotoolset above-fix child go-toolset@1.19.11-1.el7_9 not_affected 🟒 not_affected

Key finding: Only the child-CPE kernel variant fails β€” the escape-hatch cross-product match. Root-CPE kernel is correctly scoped. Go-toolset version axis is fully correct on main (within-substream version handling works). Isolates the bug to the cross-product kernel leak.

Verdict: CORRECT


S18 β€” RHEL 8 curl not-affected override (PR #2627)

Field Value
Jira TC-5171 + TC-5730 β€” cross-product match overrides explicit known_not_affected (coupling TC-5640)
PR #2627
Status #[ignore] β€” 4/5 pass, 1/5 fail
Bug RHEL 9 fix-range matches RHEL 8 curl by name, overriding the el8 known_not_affected

What the test expects:

An explicit RHEL 8 curl known_not_affected must not be overridden by a cross-product match. Uses real CVE-2022-32207 CSAF. Two axes: CPE-context (el8 curl) and version (el9 curl).

Axis SBOM CPE on curl Expected Engine today
CPE-context curl_rhel8_rootcpe root 7.61.1-34.el8 not_affected 🟒 not_affected
CPE-context curl_rhel8_notaffected child 7.61.1-34.el8 not_affected πŸ”΄ affected (TC-5171/5730)
version curl_rhel9 below-fix child 7.76.1-10.el9_0.5 affected 🟒 affected
version curl_rhel9 at-fix child 7.76.1-14.el9_0.5 not_affected 🟒 not_affected
version curl_rhel9 above-fix child 7.76.1-16.el9_0.5 not_affected 🟒 not_affected

Key finding: Only the child-CPE el8 variant fails β€” the el9 fix overrides the explicit el8 known_not_affected via the escape hatch. Root-CPE el8 is correctly scoped. The el9 version axis is fully correct (version_matches works within-product). Isolates the bug to the cross-product bleed β€” version handling itself is fine within the correct product.

Verdict: CORRECT


Summary

Scenario Jira Spec basis Assertions Status
S1 TC-5640 CSAF product_tree / CPE scoping 8/18 🟒 #[ignore]
S2 TC-5170 CSAF product_tree / CPE scoping 2/5 🟒 #[ignore]
S3 TC-5171 CSAF product_tree + VEX known_not_affected 6/12 🟒 #[ignore]
S4 TC-5171 CSAF product_tree / CPE scoping 3/6 🟒 #[ignore]
S5 TC-5641 CSAF product_status + RPM version comparison 2/4 🟒 #[ignore]
S6 β€” OSV range evaluation 9/9 🟒 Passing
S7 TC-5630 CVE affected[].cpes / CPE matching 3/3 🟒 Passing
S8 TC-5733 RPM epoch semantics (implicit 0) 6/6 🟒 Passing (latent)
S9 TC-5640 CSAF sub-stream CPE scoping 1/2 🟒 #[ignore]
S10 TC-5750 / TC-5730 CSAF CPE scoping + VEX known_not_affected + OSV 4/5 🟒 #[ignore]
S11 TC-5732 CSAF bare known_affected semantics 0/2 🟒 #[ignore]
S12 TC-5730 CSAF known_not_affected / VEX MUST suppress 0/3 🟒 #[ignore] + πŸ’₯
S13 TC-5731 OSV schema β€” id is primary, aliases optional 0/3 🟒 #[ignore]
S14 TC-5750 / TC-5751 CSAF product_tree version scope (stream, not component) 2/3 🟒 #[ignore]
S15 TC-5170 / TC-5640 CSAF CPE capture + RPM dist-tag scoping 6/9 🟒 #[ignore] (PR #2621)
S16 TC-5170 CSAF product_tree / PURL scheme scoping 1/3 🟒 #[ignore] (PR #2625)
S17 TC-5171 CSAF product_tree / cross-product CPE scoping 4/5 🟒 #[ignore] (PR #2626)
S18 TC-5171 / TC-5730 CSAF known_not_affected + cross-product CPE scoping 4/5 🟒 #[ignore] (PR #2627)

Overall (S1–S14): 46/81 assertions pass (57%).

Overall (S1–S18): 61/103 assertions pass (59%). S15–S18 add 22 assertions (15 pass, 7 fail).

Distinct bugs covered

Bug Scenarios Spec violation category
TC-5170 S2, S15, S16 Product identity β€” version scheme not checked
TC-5171 S3, S4, S17, S18 Product identity β€” CPE context not checked
TC-5630 S7 CPE-only nodes dropped from detail endpoints
TC-5640 S1, S9, S15 Cross-stream RPM version matching
TC-5641 S5 product_status skips version_matches
TC-5730 S10, S12, S18 known_not_affected ignored
TC-5731 S13 Non-CVE alias advisories dropped
TC-5732 S11 Bare known_affected creates no row
TC-5733 S8 RPM epoch handling (latent)
TC-5750 S10, S14, S17 Child-node CPE not recognized

Key observations from per-cell results

  • No incorrect expectations found. All test assertions align with the governing specifications.
  • The CPE-context filter works on root-node CPEs β€” S1 describing-CPE, S2 el8cpe, S3 el8-CPE, S4 el8-CPE, S10 root-CPE all pass when the describing CPE is on the root/describes node. S10 child-CPE is the only variant that fails, precisely confirming TC-5750.
  • S8 is latent β€” all 6 assertions pass today. The epoch bug only triggers once version_matches is applied on the affected path (which TC-5641/TC-5751 will enable). The test is correctly #[ignore] as a proactive regression guard.
  • S14 exposes cross-endpoint inconsistency β€” /sbom/advisory and /purl pass, but /vulnerability/analyze fails. This confirms the independent-SQL-codepath problem documented in the parent epic TC-5639.
  • S11's eus8.8 pass is vacuous β€” it passes because bare known_affected creates no correlation at all, not because the fixed status is correctly applied.
  • S12 has a secondary crash bug β€” after the /sbom/advisory assertion, the /vulnerability/analyze call triggers an actix deserialization panic, preventing the /purl assertion from running.
  • S13 is a complete false negative β€” all 3 endpoints return empty for a GHSA advisory with no CVE alias, the highest-impact bug by volume (~41% of crates.io feed).

Failures by root cause

35 assertions fail across 12 ignored scenarios. Below they are grouped by the underlying engine bug, showing which fix would resolve which failures. Some failures have overlapping causes (noted with +); either fix alone would resolve them.

1. No version_matches on product_status path β€” TC-5641 / TC-5751

Bug: /sbom/advisory matches packages by name only. No version comparison is applied, so patched RPMs are still reported affected.

Impact: 7 failing assertions (+ several S1 failures it shares with TC-5640).

Scenario SBOM CVE Expected Actual
S5 openssl at-fix CVE-2022-4304 not_affected πŸ”΄ affected
S5 openssl at-fix CVE-2023-0215 not_affected πŸ”΄ affected
S9 openssl el8.2 patched CVE-2023-0286 not_affected πŸ”΄ affected
S1 bind-libs el8.10 (no CPE) CVE-2022-0396 not_affected πŸ”΄ affected
S1 bind-libs el8.10 (no CPE) CVE-2023-5517 not_affected πŸ”΄ affected
S1 bind-libs el8.10 (no CPE) CVE-2024-4076 not_affected πŸ”΄ affected
S3 curl el8 past-fix (no CPE) CVE-2024-2398 not_affected πŸ”΄ affected

Fix: Apply version_matches to the product_status name/namespace CTEs in product_advisory_info_sql and batch_severity_counts_sql.


2. CPE context / product identity not checked β€” TC-5170 / TC-5171

Bug: Advisory matching does not filter by product CPE. Advisories for product A (Satellite, hummingbird, Storage 3) match packages from product B (RHEL 8) when the package name overlaps.

Impact: 10 failing assertions (some overlap with TC-5730).

Scenario SBOM CVE Expected Actual
S2 golang RPM CVE-2023-44487 not_affected πŸ”΄ affected
S2 golang RPM in-range CVE-2023-44487 not_affected πŸ”΄ affected
S2 golang OCI CVE-2023-44487 not_affected πŸ”΄ affected
S3 curl el8 past-fix CVE-2025-10148 not_affected πŸ”΄ affected (+TC-5730)
S3 curl el8 past-fix CVE-2025-10966 not_affected πŸ”΄ affected (+TC-5730)
S3 curl el8 below-fix CVE-2025-10148 not_affected πŸ”΄ affected (+TC-5730)
S3 curl el8 below-fix CVE-2025-10966 not_affected πŸ”΄ affected (+TC-5730)
S4 chardet el8 (no CPE) CVE-2018-11751 not_affected πŸ”΄ affected
S4 chardet el8 (no CPE) CVE-2018-3258 not_affected πŸ”΄ affected
S4 chardet el8 (no CPE) CVE-2019-0231 not_affected πŸ”΄ affected

Fix: Filter product_status matches by the SBOM's describing CPE against the advisory's product-tree CPE context.

Note: S3's CVE-2025-10148/10966 failures overlap with TC-5730 (known_not_affected ignored). Either fix alone resolves them β€” CPE filtering would prevent the match; honoring known_not_affected would suppress the result.


3. known_not_affected ignored β€” TC-5730

Bug: Correlation queries only read status='affected'. There is no suppression step that consults known_not_affected. A vendor's explicit "not vulnerable" declaration is inert.

Impact: 1 direct failure + 1 crash + 4 shared with TC-5171.

Scenario SBOM CVE Expected Actual
S12 thunderbird el8 (advisory) CVE-2024-6602 not_affected πŸ”΄ affected
S12 thunderbird el8 (analyze) CVE-2024-6602 not_affected πŸ”΄ affected (+ πŸ’₯ deser crash)
S12 thunderbird el8 (purl) CVE-2024-6602 not_affected πŸ”΄ affected
S3 curl el8 past-fix CVE-2025-10148 not_affected πŸ”΄ affected (+TC-5171)
S3 curl el8 past-fix CVE-2025-10966 not_affected πŸ”΄ affected (+TC-5171)
S3 curl el8 below-fix CVE-2025-10148 not_affected πŸ”΄ affected (+TC-5171)
S3 curl el8 below-fix CVE-2025-10966 not_affected πŸ”΄ affected (+TC-5171)

Fix: Add a suppression step: after collecting affected matches, exclude any product_id that also appears in known_not_affected.


4. Bare known_affected creates no row β€” TC-5732

Bug: CSAF known_affected entries without a version qualifier create no row in csaf/creator.rs. Combined with the describing-CPE filter, sub-stream fixed rows are excluded, leaving no matches at all (false negative).

Impact: 5 failing assertions + 1 vacuous pass.

Scenario SBOM CVE Expected Actual
S11 firefox main el8 CVE-2023-6135 affected πŸ”΄ empty (false negative)
S11 firefox eus8.8 patched CVE-2023-6135 not_affected 🟑 vacuously passes
S1 bind-libs el10 CVE-2023-5517 affected πŸ”΄ empty (false negative)
S1 bind-libs el10 CVE-2024-4076 affected πŸ”΄ empty (false negative)
S3 curl el8 (el8 CPE) CVE-2025-13034 affected πŸ”΄ empty (false negative)

Fix: Generate a matchable row for bare known_affected product_ids in csaf/creator.rs, representing "all versions affected."


5. Cross-stream RPM version matching β€” TC-5640

Bug: rpmvercmp doesn't understand dist tags (.el8 vs .el9). Cross-stream comparisons produce wrong results. Currently mostly masked by TC-5641 (no version_matches applied at all), but these will surface once version_matches is enabled.

Impact: 5 failing assertions (partially masked by TC-5641).

Scenario SBOM CVE Expected Actual Notes
S1 bind-libs el9 below-fix CVE-2023-5517 not_affected πŸ”΄ affected el10 range leaks to el9
S1 bind-libs el9 at-fix CVE-2023-5517 not_affected πŸ”΄ affected el10 range leaks
S1 bind-libs el9 at-fix CVE-2024-4076 not_affected πŸ”΄ affected el10 range leaks
S1 bind-libs el9 above-fix CVE-2023-5517 not_affected πŸ”΄ affected el10 range leaks
S1 bind-libs el9 above-fix CVE-2024-4076 not_affected πŸ”΄ affected el10 range leaks

Fix: Add stream awareness to version matching β€” compare dist tags or require CPE-context match before applying version ranges.

Note: TC-5640 and TC-5641 interact. Once TC-5641 is fixed (version_matches enabled), the cross-stream failures that TC-5640 causes will become directly observable. Currently they're obscured because no version comparison happens at all.


6. Child-node CPE not recognized β€” TC-5750

Bug: sbom_describing_cpe is only populated from nodes with a Describes relationship. When the product CPE sits on a child/OS component, no CPE filter row is created, and the filter's escape hatch disables filtering entirely.

Impact: 1 failing assertion.

Scenario SBOM CVE Expected Actual
S10 thunderbird el8 child-CPE CVE-2024-6602 not_affected πŸ”΄ affected

Fix: Also populate sbom_describing_cpe from child components that carry an OS-level CPE (e.g. nodes with cpe:/o:redhat:enterprise_linux).

Note: The root-CPE variant (same scenario) passes, confirming the filter works correctly when the CPE is on the root node.


7. Non-CVE alias advisories dropped β€” TC-5731

Bug: The OSV loader gates all correlation on CVE-prefixed aliases. Advisories with only a GHSA/RUSTSEC/PYSEC/MAL id are ingested but create no purl_status β€” complete false negative.

Impact: 3 failing assertions (total silence across all endpoints).

Scenario SBOM Vuln ID Expected Actual
S13 afire@1.0.0 (advisory) GHSA-3227-r97m-8j95 affected πŸ”΄ empty
S13 afire@1.0.0 (analyze) GHSA-3227-r97m-8j95 affected πŸ”΄ empty
S13 afire@1.0.0 (purl) GHSA-3227-r97m-8j95 affected πŸ”΄ empty

Fix: Remove the CVE-alias gate in the OSV loader. Use the advisory's id field as the primary vulnerability identifier.

Note: This is the highest-impact bug by volume β€” ~41% of crates.io OSV advisories have no CVE alias.


8. Cross-endpoint inconsistency β€” TC-5639

Bug: Independent SQL codepaths apply matching rules inconsistently. The same SBOM/package yields different vulnerability sets depending on which endpoint is queried.

Impact: 1 failing assertion (direct evidence of the parent epic's thesis).

Scenario Endpoint CVE Result
S14 /sbom/advisory CVE-2021-37136 🟒 found
S14 /vulnerability/analyze CVE-2021-37136 πŸ”΄ empty
S14 /purl CVE-2021-37136 🟒 found

Fix: Unify the matching logic across all three endpoints, or ensure the product_status CTEs in /vulnerability/analyze follow the same rules as /sbom/advisory and /purl.


9. RemediationSummary round-trip deserialization failure

Bug: RemediationSummary (in purl/model/summary/remediation.rs) has #[serde(skip_serializing)] pub id: Uuid. This skips id when writing JSON but still requires it when reading JSON. The /vulnerability/analyze endpoint serializes remediations without id, so AnalysisResponseV3 cannot be deserialized from its own output.

Impact: S12's /vulnerability/analyze call crashes with missing field 'id' at line 1 column 32595. The endpoint actually returns correct data (338 KB, CVE-2024-6602 as affected across 10 product streams), but the test harness panics during deserialization.

This is not a correlation bug β€” it's a serde annotation bug that prevents any test from deserializing an analyze response that includes remediations. S14's analyze call avoids it because its response is empty.

Root cause: remediation.rs:9 should use #[serde(skip_serializing, default)] or #[serde(skip)] instead of #[serde(skip_serializing)] alone.

Additional finding from raw response inspection:

When bypassing deserialization, S12's actual endpoint results are:

Endpoint CVE-2024-6602 Status
/sbom/advisory present πŸ”΄ affected (TC-5730)
/vulnerability/analyze present (10 purl_statuses, 338 KB) πŸ”΄ affected (TC-5730)
/purl present (10 purl_statuses) πŸ”΄ affected (TC-5730)

All three endpoints consistently return CVE-2024-6602 as affected β€” the known_not_affected suppression (TC-5730) is the only actual bug. The deserialization crash is a secondary issue that masks the consistent false-positive result.


Root cause impact summary

# Root cause Ticket Fails Type
1 No version_matches on product_status TC-5641 7 False positive
2 CPE context not checked TC-5170/TC-5171 10 False positive
3 known_not_affected ignored TC-5730 2+πŸ’₯ False positive
4 Bare known_affected no row TC-5732 5 False negative
5 Cross-stream RPM matching TC-5640 5 False positive
6 Child-node CPE not recognized TC-5750 1 False positive
7 Non-CVE alias dropped TC-5731 3 False negative
8 Cross-endpoint inconsistency TC-5639 1 Inconsistency

False positives (25 fails): Bugs 1, 2, 3, 5, 6 β€” the engine reports vulnerabilities that should not apply.

False negatives (8 fails): Bugs 4, 7 β€” the engine misses vulnerabilities that should be reported.

Latent: TC-5733 (RPM epoch) β€” 0 current fails; will surface once TC-5641 enables version_matches on the affected path.

Dependency graph between fixes

TC-5641 (version_matches)
   β”‚
   β”œβ”€β”€ unblocks TC-5640 (cross-stream) β€” currently masked
   └── unblocks TC-5733 (epoch) β€” currently latent

TC-5170/5171 (CPE context) and TC-5730 (known_not_affected) overlap on 4 cells in S3. Either fix alone resolves them, but both are needed for correctness.

TC-5732 (bare known_affected) is independent β€” it causes false negatives that no other fix addresses.


TC-5641 fix investigation: version_matches(package_version, product_version_range) is semantically wrong

Deep-dive into the naive fix for TC-5641 ("add version_matches() to the product_status CTEs in product_advisory_info_sql() and batch_severity_counts_sql()") reveals the approach is incorrect.

The problem with the naive fix

The product_version_range table stores the product version range (derived from the product's CPE version during CSAF ingestion), not the package version range:

  • RHEL 8 CPE cpe:/o:redhat:enterprise_linux:8 β†’ lenient-semver parses "8" β†’ version range [8.0.0, 9.0.0) with RPM scheme
  • Quarkus 2.13 CPE cpe:/a:redhat:quarkus:2.13 β†’ version range [2.0.0, 3.0.0) with RPM scheme

Calling version_matches(sp.version, vr.*) where sp.version is the package version (e.g., zookeeper@3.9.2 or openssl@1.1.1k-9.el8_7) against a product version range (e.g., [8.0.0, 9.0.0)) is semantically meaningless.

The purl endpoint code confirms this at purl/model/details/purl.rs:285:

// NOTE: no version_matches filter here. The version_range in
// product_status refers to the *product* version (e.g. Quarkus
// 2.x), not the *package* version (e.g. keycloak-core 18.0.6).

Evidence from testing

Applying the naive fix (version_matches(sp.version, vr.*)) to both product_advisory_info_sql() and batch_severity_counts_sql():

  1. case_12_ds6_quarkus_severity regresses: expected {"high":2, "medium":13, "low":1} β†’ actual {"high":2, "medium":6, "low":1}. Seven legitimate matches eliminated because package versions (e.g., resteasy-core@4.7.9.Final-redhat-00001) don't fall within the product version range [2.0.0, 3.0.0) for Quarkus 2.x.

  2. case_08_multiple_sboms_both_match regresses: the zookeeper SBOM's high-severity match disappears because zookeeper@3.9.2 doesn't fall within any product version range.

  3. S5 still fails after the fix: Debug logging shows the product_status path returns 0 rows for both below-fix and at-fix SBOMs (correctly for the wrong reason β€” package versions are outside the product range). But 4 false-positive ID sets still come from the purl_status path (SeaORM first query), caused by cross-stream matching (TC-5640):

    at-fix SBOM: Collected 4 ID sets from first query ... Combined 4 total ID sets
    

    The VEX creates purl_status rows for openssl across all RHEL 8 streams (BaseOS 8.7, AppStream 8.8, EUS 8.6). The AppStream fix at 1.1.1k-12.el8 creates an affected range (*, 1.1.1k-12.el8) that includes the BaseOS at-fix version 1.1.1k-9.el8_7. The CPE context filter (CONTEXT_CPE_FILTER_SQL) only checks major version (vendor=redhat, product=enterprise_linux, version=8) via split_part(version, '.', 1), so it allows the AppStream purl_status to match against the BaseOS SBOM.

The analyze endpoint has the same bug (TC-5751)

The /vulnerability/analyze endpoint (vulnerability/service/mod.rs:626-632) already uses version_matches($2, version_range.*) on the product_status path with the package version β€” and S14 shows this causes false negatives:

S14 β€” /vulnerability/analyze returns empty while the other two endpoints correctly report affected

Correct approach for TC-5641

Instead of comparing the package version against the product version range, the product_status path should compare the SBOM's describing-CPE version against the product version range. This validates that the SBOM's product falls within the advisory's product scope.

For example, for an SBOM describing RHEL 8.10 (cpe:/o:redhat:enterprise_linux:8::baseos), the CPE version "8.10" should be checked against the product version range [8.0.0, 9.0.0):

  • rpmvercmp("8.10", "8.0.0") β†’ 8 == 8, 10 > 0 β†’ 8.10 > 8.0.0 βœ“ (above low bound)
  • rpmvercmp("8.10", "9.0.0") β†’ 8 < 9 β†’ 8.10 < 9.0.0 βœ“ (below high bound)
  • Result: version_matches returns true β†’ match is valid

This would look something like (in product_advisory_info_sql()):

JOIN product_version_range pvr ON ps.product_version_range_id = pvr.id
JOIN version_range vr ON pvr.version_range_id = vr.id
WHERE (
    ps.context_cpe_id IS NULL
    OR EXISTS (
        SELECT 1 FROM filtered_cpes fc
        WHERE fc.id = ps.context_cpe_id
          AND version_matches(fc.version, vr.*)
    )
    OR NOT EXISTS (SELECT 1 FROM filtered_cpes LIMIT 1)
)

This replaces the current flat context_cpe_id IN (allowed_cpe_ids) check with a version-aware check that also validates the CPE version falls within the product version range.

Note: This fix alone won't make S5 pass β€” that also requires fixing TC-5640 (cross-stream purl_status matching in the first SeaORM query). The S5 false positive comes from the purl_status path, not the product_status path.

TC-5640 root cause in S5

The cross-stream false positive in S5 traces through:

  1. VEX creates purl_status for pkg:rpm/redhat/openssl with context CPE cpe:/a:redhat:enterprise_linux:8::appstream and affected range (*, 1.1.1k-12.el8)
  2. SBOM describes cpe:/o:redhat:enterprise_linux:8::baseos
  3. CONTEXT_CPE_FILTER_SQL generalizes to (redhat, enterprise_linux, 8) which matches both baseos and appstream CPEs
  4. At-fix version 1.1.1k-9.el8_7 < AppStream fix 1.1.1k-12.el8 β†’ matches affected range β†’ false positive

The CPE context filter needs sub-stream awareness (distinguishing baseos from appstream, or EUS 8.6 from BaseOS 8.7) to prevent this.

Updated dependency graph

TC-5641 (version_matches β€” must use CPE version, not package version)
   β”‚
   β”œβ”€β”€ unblocks TC-5640 (cross-stream) β€” currently masked
   β”‚     └── S5 at-fix: 4 false-positive purl_status rows from
   β”‚         AppStream range leaking to BaseOS SBOM via
   β”‚         CONTEXT_CPE_FILTER_SQL major-version generalization
   β”‚
   └── unblocks TC-5733 (epoch) β€” currently latent

TC-5751 (analyze endpoint) β€” same root cause as TC-5641 but already
   applies the WRONG version_matches (package vs product), causing
   S14's false-negative empty result

GitHub PRs

Scenario PRs (test(correlation))

PR Scenario Title Bugs targeted Status
#2613 S1–S14 test: add vulnerability correlation test suite (TC-5639) All 9 root causes βœ… Merged 2026-09-01
#2621 S15 test(correlation): add S15 openssh RPM version-comparison scenario TC-5170, TC-5640 🟑 Open
#2625 S16 test(correlation): add S16 cross-scheme golang PURL-query scenario TC-5170 🟑 Open
#2626 S17 test(correlation): add S17 cross-product OCP-kernel vs Go scenario TC-5171 🟑 Open
#2627 S18 test(correlation): add S18 RHEL 8 curl not-affected override scenario TC-5171, TC-5730 🟑 Open

Related fix PRs

PR Title Root cause Scenarios unblocked Status
#2582 fix: vuln correlation fixes Multiple β€” βœ… Merged 2026-08-20
#2599 fix(ingestor): materialize OS-node CPEs into sbom_describing_cpe (TC-5749) TC-5750 (child-node CPE) S10, S15-C, S17, S18 🟑 Open
#2602 fix(db): match a fully-unbounded version range against all versions (TC-5732) TC-5732 (bare known_affected) S11, S1-el10, S3-el8-CPE 🟑 Open
#2615 fix(rpm): fix rpmver_cmp caret ordering and add epoch support TC-5640 (cross-stream), TC-5733 (epoch) S1, S8, S9, S15-B 🟑 Open
#2624 fix: remove dead id field from RemediationSummary Root cause 9 (serde) S12 crash βœ… Merged 2026-09-03

S15–S18 analysis: what the new scenarios add

S15 (openssh, PR #2621) adds the sharpest isolation of two interacting bugs. By holding the product and package constant and varying only CPE placement and sub-stream, it produces three clean contrasts: A↔C proves the CPE-capture effect (TC-5170/5750); A↔B proves the dist-tag cross-stream match (TC-5640). The B group also reveals that at/above-fix versions escape TC-5640 by coincidence (release β‰₯ borrowed fix release), not by correct stream scoping.

S16 (golang, PR #2625) reproduces S2's cross-scheme bug with a tighter setup β€” 3 SBOMs, one CVE, synthetic CSAF. The positive control (RPM Storage 3) verifies the match path isn't over-suppressed. OCI and Maven variants confirm the name-only match persists across PURL types.

S17 (kernel/go-toolset, PR #2626) is the strongest cross-product test: a Go CVE advisory (OCP 4.13) bundles a kernel fix. A plain RHEL 8 kernel should never match, but does when the CPE is on a child node. The go-toolset version axis (below/at/above) confirms within-substream version handling is correct β€” the bug is exclusively the cross-product CPE bleed.

S18 (curl, PR #2627) combines TC-5171 and TC-5730: an explicit known_not_affected for RHEL 8 curl is overridden by a cross-product match against the RHEL 9 fix. This is the most severe interaction β€” a vendor's authoritative "not vulnerable" declaration is contradicted by a cross-stream leak. The el9 version axis confirms version handling is fine within the correct product scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment