Skip to content

fix: translate os-release distro IDs to SSG datastream short codes#110

Open
trevor-vaughan wants to merge 1 commit into
mainfrom
fix/91-centos-detection
Open

fix: translate os-release distro IDs to SSG datastream short codes#110
trevor-vaughan wants to merge 1 commit into
mainfrom
fix/91-centos-detection

Conversation

@trevor-vaughan

Copy link
Copy Markdown
Member

CentOS Stream reports ID=centos in os-release, but SSG ships its
datastream as ssg-cs10-ds.xml. The old code built filenames from the
raw ID, so CentOS Stream fell through to the RHEL datastream where
every rule came back notapplicable.

  • Add distroAliases map covering centos→cs, sles/sled/sle_hpc→sle,
    sle-micro/sl-micro→slmicro, opensuse-leap/opensuse-tumbleweed→opensuse,
    and amzn→al
  • Extract parseDistroInfo(io.Reader) and matchDatastream(fs.FS) from
    their file-bound originals so tests can run without real filesystem
    access
  • Replace filepath.Walk matching with candidate-list lookup against
    fs.ReadDir for clearer priority ordering
  • Add tests for every alias, per-distro parsing, versionless match,
    missing-field and I/O error paths, and ReadDir failure
  • Add CHANGELOG entry

Closes #91

Assisted-by: Claude Opus 4.6
Signed-off-by: Trevor Vaughan tvaughan@redhat.com

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

✅ CRAP Load Analysis: PASS

Summary

Metric Value
Functions analysed 17
Avg complexity 4.5
Avg line coverage 68.2%
Avg CRAP score 6.7
CRAPload (>= 15) 1
Avg contract coverage 80%
Avg GazeCRAP score 5.4
GazeCRAPload (>= 15) 0
Regressions 0
Improvements 0
New functions 17

Quadrant Distribution

Quadrant Count
Q1 Safe 5
Q2 Complex but Tested 0
Q3 Simple but Underspecified 0
Q4 Dangerous 0

New Functions

Status Function CRAP GazeCRAP Note
+ cmd/openscap-provider/config/config.go:getDatastreamsDir 6 N/A new
+ cmd/openscap-provider/config/config.go:getSystemInfoFile 6 N/A new
+ cmd/openscap-provider/config/config.go:normalizeCPE 4 N/A new
+ cmd/openscap-provider/config/config.go:cpeMatches 5 N/A new
+ cmd/openscap-provider/config/config.go:EnsureDirectories 3.072 12 new
+ cmd/openscap-provider/config/config.go:ResolveDatastream 6.730277986476334 6 new
+ cmd/openscap-provider/config/config.go:SanitizeInput 2 2 new
+ cmd/openscap-provider/config/config.go:SanitizePath 2.032 2 new
+ cmd/openscap-provider/config/config.go:IsXMLFile 5.018782870022539 5 new
+ cmd/openscap-provider/config/config.go:expandPath 4.074074074074074 N/A new
+ cmd/openscap-provider/config/config.go:validatePath 6.5625 N/A new
+ cmd/openscap-provider/config/config.go:ensureDirectory 4.03125 N/A new
+ cmd/openscap-provider/config/config.go:extractCPEFromOsRelease 5 N/A new
+ cmd/openscap-provider/config/config.go:getSystemCPE 6 N/A new
+ cmd/openscap-provider/config/config.go:extractCPEFromDatastream 7.009973539588846 N/A new
+ cmd/openscap-provider/config/config.go:matchDatastreamByCPE 12.008192990441511 N/A new
+ cmd/openscap-provider/config/config.go:findMatchingDatastream 30 N/A new

View full analysis logs

@trevor-vaughan trevor-vaughan marked this pull request as ready for review July 2, 2026 20:27
@trevor-vaughan trevor-vaughan requested review from a team as code owners July 2, 2026 20:27
hbraswelrh
hbraswelrh previously approved these changes Jul 2, 2026

@hbraswelrh hbraswelrh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review: #110 — fix: translate os-release distro IDs to SSG datastream short codes

Verdict: APPROVE

Clean, well-tested bug fix. The io.Reader/fs.FS refactoring is the right approach for testability. All aliases are covered by tests. Documentation updated. All CI checks pass. No security, alignment, or constitution concerns.

Highlights

  • distroAliases map centralizes all ID-to-shortcode mappings in one location
  • Candidate-list approach with priority ordering is clearer and more correct than the previous filepath.Walk scan
  • 287 new test lines covering every alias, per-distro parsing, error paths, and edge cases
  • Regression test (TestMatchDatastream_CentOSStream) directly reproduces the original failure scenario
  • Documentation correctly updated for expanded distro support

Linked Issue Coverage (#91)

Criterion Status
Add centoscs short-code alias COVERED
Prefer exact-distro match before ID_LIKE fallback COVERED
Unit test with ID="centos" and ssg-cs10-ds.xml fixture COVERED
Surface 100% notapplicable as error/warning NOT IN SCOPE (tracked in complyctl#609)

This review was generated by /review-pr (AI-assisted).

@marcusburghardt marcusburghardt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design Concern: Static Alias Table + False-Match Risk on Multi-Datastream Systems

The refactoring to io.Reader/fs.FS interfaces and the candidate-list approach are clean improvements. However, the distroAliases static map has two structural issues that should be addressed before merging.

1. Static coupling to CaC/content naming conventions

CaC/content uses version-dependent short codes for CentOS derivatives (products/rhel8/CMakeLists.txt:32, products/rhel9/CMakeLists.txt:25, ssg/constants.py:512-515):

RHEL parent Derivative call Output datastream
rhel8 ssg_build_derivative_product(${PRODUCT} "centos" "centos8") ssg-centos8-ds.xml
rhel9 ssg_build_derivative_product(${PRODUCT} "centos" "cs9") ssg-cs9-ds.xml
rhel10 ssg_build_derivative_product(${PRODUCT} "centos" "cs10") ssg-cs10-ds.xml

The blanket centos → cs alias assumes this mapping is version-independent, which CaC/content's own history proves false. Every time CaC/content adds or renames a product, this table requires a provider code change and release.

2. False-match risk on multi-datastream systems

Fedora's scap-security-guide package builds with SSG_PRODUCT_DEFAULT=TRUE (CMakeLists.txt:85), shipping all 38+ datastreams (Ubuntu, Debian, SUSE, etc.) in the same directory. On such systems, the ID_LIKE fallback in the candidate search can match an unrelated datastream. For example, a derivative distro with ID_LIKE="fedora" and no SSG content of its own would fall through to ssg-fedora-ds.xml, whose CPE platform check would then zero the scan — exactly the silent failure this PR aims to fix.

The auto-detection mechanism should be precise: better to fail with a clear error (the user can specify variables.datastream manually) than to silently select the wrong datastream.

Most distros need no alias at all

Only ~5 distro families have os-release ID values that differ from their SSG filename short code. The rest match directly:

Works without alias Needs alias
rhel, fedora, debian, ubuntu, ol, almalinux, alinux, anolis, tencentos centos→cs (version-dependent), amzn→al, sles/sled→sle, sle-micro→slmicro, opensuse-leap→opensuse

Suggested direction: CPE-based matching

Each SSG datastream embeds a CPE dictionary (<cpe-item name="cpe:/o:centos:centos:10">) that is the authoritative platform metadata — it's what oscap itself evaluates to determine applicability. Most Linux distros publish a matching CPE_NAME field in /etc/os-release. A hybrid approach could:

  1. Fast path: Try filename candidates from raw os-release IDs + version (no alias table — covers the majority)
  2. CPE fallback: If no filename match, parse the CPE dictionary from each ssg-*-ds.xml and match against the system's CPE_NAME (the provider already uses antchfx/xmlquery for datastream XML parsing in xccdf/datastream.go)
  3. Manual override: The existing variables.datastream configuration already handles edge cases

This eliminates the alias table, automatically adapts to new CaC/content products, and prevents false matches because CPE comparison is platform-specific rather than filename-heuristic.

This review was generated by /review-pr (AI-assisted).

Comment thread cmd/openscap-provider/config/config.go Outdated
Comment thread cmd/openscap-provider/config/config.go Outdated
CentOS Stream and other Enterprise Linux variants now correctly detect
their SSG datastreams instead of falling back to RHEL or failing with
"notapplicable" results.

Root cause: the provider built datastream filenames from raw os-release
ID values (e.g., "centos" -> ssg-centos-ds.xml), but SSG ships CentOS
Stream as ssg-cs10-ds.xml. This caused a lookup miss, falling back to
RHEL where every rule returned notapplicable.

Solution: replace static distroAliases table with CPE-based matching.
Parse CPE_NAME from /etc/os-release, extract CPE items from each SSG
datastream's embedded dictionary, and match os-release CPE against
datastream CPEs. Returns first matching datastream.

Added environment variable overrides for non-standard deployments:
- SSG_CONTENT_DIR: override /usr/share/xml/scap/ssg/content location
- OS_RELEASE_FILE: override /etc/os-release location

Fixes: #91

Assisted-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Trevor Vaughan <tvaughan@redhat.com>
@trevor-vaughan trevor-vaughan force-pushed the fix/91-centos-detection branch from 2ff8d40 to 9a768da Compare July 8, 2026 18:44
@trevor-vaughan

Copy link
Copy Markdown
Member Author

@marcusburghardt I took a whack at a complete refactor based on detecting the CPE values.

Overwrite since the old work is to be abandoned.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

openscap provider auto-selects the wrong SCAP datastream on CentOS Stream, zeroing the scan

3 participants