Skip to content

Add SBOM compliance checker script (SPDX/CycloneDX, scores 1-10)#91

Open
jasinner wants to merge 1 commit into
RedHatProductSecurity:mainfrom
jasinner:validate-sbom
Open

Add SBOM compliance checker script (SPDX/CycloneDX, scores 1-10)#91
jasinner wants to merge 1 commit into
RedHatProductSecurity:mainfrom
jasinner:validate-sbom

Conversation

@jasinner
Copy link
Copy Markdown
Contributor

python3 sbom/validate_sbom.py <sbom-file.json[.gz]>

Area Checks
Document structure spdxVersion, dataLicense, SPDXID, documentNamespace format & Red Hat URI
creationInfo UTC timestamp format, Tool: entry, Organization: Red Hat (required for RTPA2)
Relationships At least one DESCRIBES, RPM GENERATED_FROM/CONTAINS chains
Package fields name, versionInfo, downloadLocation, licenseConcluded/Declared, checksums (SHA256 for RPMs/OCI)
Supplier Organization: Red Hat required for pkg:rpm/redhat/ and OCI packages
PURL/RPM redhat namespace, arch qualifier, epoch via ?epoch=N not embedded, no distro, repository_id over repository_url
PURL/OCI repository_url (release SBOMs), tag, SHA256 digest, %3A encoding
PURL/Generic download_url qualifier required
PURL/Maven repository_url pointing to maven.repository.redhat.com

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: f32534d0-878b-44d3-bb0b-e33a87d5d365

📥 Commits

Reviewing files that changed from the base of the PR and between 9026fa4 and 706b444.

📒 Files selected for processing (1)
  • sbom/validate_sbom.py

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added an SBOM validation CLI that auto-detects SPDX and CycloneDX JSON (including .json.gz), validates against Red Hat security guidance, and produces human-readable or JSON reports.
    • Reports include deduped findings, occurrence counts, sample locations, a 1–10 compliance score, severity filtering, and exit codes based on score thresholds.
    • Enhanced purl parsing and type-specific checks for RPM/OCI/Maven/Generic artifacts.

Walkthrough

A new CLI tool sbom/validate_sbom.py loads .json/.json.gz SBOMs, detects SPDX 2.3 or CycloneDX 1.6, validates document/component rules and PURLs against Red Hat guidelines, deduplicates and aggregates findings, computes a compliance score, and outputs colored or JSON reports with exit codes.

Changes

SBOM Validation Tool

Layer / File(s) Summary
Data Models and Scoring
sbom/validate_sbom.py
Finding and ValidationResult dataclasses track validation issues with deduplication, sample location aggregation, and compliance score computation based on unique finding types with penalties for high-frequency critical/major findings.
PURL Parsing and Validation
sbom/validate_sbom.py
parse_purl() extracts package URL components including subpath and qualifiers; validate_purl() enforces Red Hat rules for rpm, oci, maven, and generic purls (qualifiers, digests, checksums, required attributes) and emits findings.
SPDX 2.3 Validator
sbom/validate_sbom.py
validate_spdx() checks document-level fields and creationInfo, requires DESCRIBES relationships, validates package mandatory fields and supplier expectations, enforces purl presence for non-product packages, validates deduped purls, checks RPM/OCI checksums and SHA256, and verifies SRPM relationship chains.
CycloneDX 1.6 Validator
sbom/validate_sbom.py
validate_cyclonedx() enforces bomFormat/specVersion, metadata UTC timestamp and Red Hat supplier, tools presence, main component purl, component type/name/version/purl, supplier/manufacturer presence, and RPM/OCI hash requirements; missing dependency graph yields INFO.
SBOM Loading and Format Detection
sbom/validate_sbom.py
load_sbom() reads .json and .json.gz; detect_format() identifies SPDX vs CycloneDX; validate() orchestrates loading, detection, validator dispatch, and parse-failure reporting.
Result Reporting and Display
sbom/validate_sbom.py
print_report() formats and optionally colorizes findings, groups by severity, shows aggregated counts and sample locations, reports unique vs total counts, and displays a compliance-score bar with thresholds and labels.
CLI Interface and Main Flow
sbom/validate_sbom.py
main() parses --no-color, --json, --min-severity, runs validation, filters findings for display, supports JSON output including pre-filter totals, and returns exit codes based on score or parse failure.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add SBOM compliance checker script (SPDX/CycloneDX, scores 1-10)' directly and clearly describes the main change: addition of an SBOM compliance checker supporting both SPDX and CycloneDX formats with 1-10 scoring.
Description check ✅ Passed The description provides a detailed table of compliance checks and validates against the changeset content, clearly relating to the SBOM validator implementation with specific checks for document structure, relationships, package fields, supplier information, and PURL validation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sbom/validate_sbom.py`:
- Around line 942-947: The docstring claims exit code 3 for "File could not be
parsed" but main() only returns 0/1/2; to fix, change main() (the return logic
around final_score) to explicitly return 3 when a parse failure is detected:
check the parse failure indicator (prefer a dedicated boolean set when parsing
fails, or scan the findings list for a CRITICAL "File could not be parsed"
finding) before evaluating final_score, and return 3 if present; otherwise keep
the existing final_score -> 0/1/2 mapping. Alternatively, if you prefer not to
add a parse-specific exit, update the module docstring to remove the exit code 3
description so it matches main() behavior.
- Around line 807-809: The code currently mutates the module-level
_SEVERITY_COLORS dict when use_color is False, breaking re-use and tests;
instead, create a local copy (e.g., colors = dict(_SEVERITY_COLORS)), modify
that local copy when use_color is False (set values to ""), and update all calls
to the helper _c() within the function to use this local colors mapping (pass it
as an extra parameter or capture it in a closure) so the global _SEVERITY_COLORS
remains unchanged.
- Around line 924-925: The JSON counts are being taken from the filtered result
(result.counts() and result.unique_counts()) but final_score was computed before
filtering; capture the pre-filter counts and unique counts into local variables
(e.g., counts_before and unique_counts_before) before the filtering that happens
in the block around result.findings, then use those captured variables in the
JSON payload instead of calling result.counts()/result.unique_counts() so the
counts align with final_score; update any references to counts in the output
generation to use those pre-filter variables and leave the filtering of
result.findings as-is.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: e2d3a70c-bbfb-4813-af6b-adf7c2da6631

📥 Commits

Reviewing files that changed from the base of the PR and between 8148585 and 9026fa4.

📒 Files selected for processing (1)
  • sbom/validate_sbom.py

Comment thread sbom/validate_sbom.py Outdated
Comment thread sbom/validate_sbom.py Outdated
Comment thread sbom/validate_sbom.py
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.

1 participant