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
| 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
| 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
| 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
| 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
| 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
| 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)
| 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
| 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
| 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
| 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:
- CSAF product scoping: CVE-2024-4076 (bind) is not present in the el8 SBOM β not_affected. Correct per product_tree matching.
- 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.
- CSAF known_not_affected: CVE-2024-6602 has explicit
known_not_affectedfor the thunderbird el8 product. Per VEX consumer requirements, this MUST suppress the finding. - 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
| 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
| 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
| 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
| 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_10build matches theel8_8fix 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
| 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).
| 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 |
- 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_matchesis 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/advisoryand/purlpass, but/vulnerability/analyzefails. 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_affectedcreates no correlation at all, not because thefixedstatus is correctly applied. - S12 has a secondary crash bug β after the
/sbom/advisoryassertion, the/vulnerability/analyzecall triggers an actix deserialization panic, preventing the/purlassertion 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).
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.
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.
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.
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 | 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.
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 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).Applying the naive fix (version_matches(sp.version, vr.*)) to both
product_advisory_info_sql() and batch_severity_counts_sql():
-
case_12_ds6_quarkus_severityregresses: 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. -
case_08_multiple_sboms_both_matchregresses: the zookeeper SBOM's high-severity match disappears becausezookeeper@3.9.2doesn't fall within any product version range. -
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 setsThe 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.el8creates an affected range(*, 1.1.1k-12.el8)that includes the BaseOS at-fix version1.1.1k-9.el8_7. The CPE context filter (CONTEXT_CPE_FILTER_SQL) only checks major version (vendor=redhat, product=enterprise_linux, version=8) viasplit_part(version, '.', 1), so it allows the AppStream purl_status to match against the BaseOS SBOM.
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/analyzereturns empty while the other two endpoints correctly report affected
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.
The cross-stream false positive in S5 traces through:
- VEX creates purl_status for
pkg:rpm/redhat/opensslwith context CPEcpe:/a:redhat:enterprise_linux:8::appstreamand affected range(*, 1.1.1k-12.el8) - SBOM describes
cpe:/o:redhat:enterprise_linux:8::baseos CONTEXT_CPE_FILTER_SQLgeneralizes to(redhat, enterprise_linux, 8)which matches both baseos and appstream CPEs- At-fix version
1.1.1k-9.el8_7< AppStream fix1.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.
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
| 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 |
| 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 (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.