ROX-30570: Add ScanSBOM API to Scanner V4#18716
Conversation
dfad150 to
a394359
Compare
00f7ddd to
c595688
Compare
a394359 to
6a38701
Compare
c595688 to
d8c20d8
Compare
|
Images are ready for the commit at d8c20d8. To use with deploy scripts, first |
6a38701 to
68728a0
Compare
d8c20d8 to
aee0377
Compare
️✅ There are no secrets present in this pull request anymore.If these secrets were true positive and are still valid, we highly recommend you to revoke them. 🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request. |
53ef512 to
c203c2e
Compare
aee0377 to
159cbfd
Compare
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- In
matcherService.ScanSBOM, the media type passed tosbomer.Decodeis not normalized the same way as inValidateScanSBOMRequest, so a value like"application/spdx+json; charset=utf-8"will pass validation but fail decoding; consider reusing the same normalization (e.g.,strings.TrimSpace(strings.Split(mediaType, ";")[0])) before callingDecode. - The change in
Backends.APIServicesto only passRemoteIndexeras theReportProvider(and no longer fall back to the localIndexer) meansmatcherServicemay have a nilindexereven when a local indexer exists, which can breakGetSBOM/ScanSBOMbehavior and empty-contents handling; please confirm whether this fallback is intentionally removed or restore the local indexer as the provider when no remote indexer is configured.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `matcherService.ScanSBOM`, the media type passed to `sbomer.Decode` is not normalized the same way as in `ValidateScanSBOMRequest`, so a value like `"application/spdx+json; charset=utf-8"` will pass validation but fail decoding; consider reusing the same normalization (e.g., `strings.TrimSpace(strings.Split(mediaType, ";")[0])`) before calling `Decode`.
- The change in `Backends.APIServices` to only pass `RemoteIndexer` as the `ReportProvider` (and no longer fall back to the local `Indexer`) means `matcherService` may have a nil `indexer` even when a local indexer exists, which can break `GetSBOM`/`ScanSBOM` behavior and empty-contents handling; please confirm whether this fallback is intentionally removed or restore the local indexer as the provider when no remote indexer is configured.
## Individual Comments
### Comment 1
<location path="scanner/sbom/sbom.go" line_range="136-137" />
<code_context>
+
+// Decode decodes an SBOM into an IndexReport.
+// The mediaType specifies the format of the SBOM (e.g., "application/spdx+json").
+func (s *SBOMer) Decode(ctx context.Context, sbomData []byte, mediaType string) (*claircore.IndexReport, error) {
+ switch mediaType {
+ case MediaTypeSPDXJSON, MediaTypeSPDXText:
+ return s.decodeSPDX(ctx, sbomData)
</code_context>
<issue_to_address>
**issue (bug_risk):** Media type handling in Decode is inconsistent with validator and will reject valid values with parameters
`Decode` compares `mediaType` verbatim to `MediaTypeSPDXJSON`/`MediaTypeSPDXText`, but `ValidateScanSBOMRequest` normalizes the value (trims whitespace and strips parameters like `; charset=utf-8`). Since `ScanSBOM` passes `req.GetMediaType()` directly into `Decode`, a value such as `application/spdx+json; charset=utf-8` will validate but still be rejected here. Please normalize `mediaType` in `Decode` (or pass the normalized value from the caller) to keep behavior consistent and avoid rejecting valid requests.
</issue_to_address>
### Comment 2
<location path="scanner/cmd/scanner/main.go" line_range="261-264" />
<code_context>
srvs = append(srvs, services.NewIndexerService(b.Indexer))
}
if b.Matcher != nil {
- // Set the index report getter to the remote indexer if available, otherwise the
- // local indexer. A nil getter is ok, see implementation.
- var getter indexer.ReportGetter
- getter = b.RemoteIndexer
- if getter == nil {
- getter = b.Indexer
+ // Set the report provider to the remote indexer if available, otherwise the
+ // local indexer. A nil provider is ok, see implementation.
+ var provider indexer.ReportProvider
+ if b.RemoteIndexer != nil {
+ provider = b.RemoteIndexer
</code_context>
<issue_to_address>
**issue (bug_risk):** Dropping the local indexer fallback can leave matcherService without an indexer, breaking GetSBOM and enrich flows
Previously, matcherService always had an index provider by falling back to `b.Indexer` when `b.RemoteIndexer` was nil. Now `provider` is only set when `b.RemoteIndexer != nil`, so in deployments with only a local indexer `matcherService.indexer` (and thus `GetSBOM`/enrich) will see a nil provider, risking panics or incorrect `disableEmptyContents` behavior. Please restore the fallback to `b.Indexer` when no remote indexer is configured, while still allowing `ReportProvider` to be nil only when those features are intentionally disabled.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
🚀 Build Images ReadyImages are ready for commit b82a84d. To use with deploy scripts: export MAIN_IMAGE_TAG=4.11.x-935-gb82a84de7c |
159cbfd to
b6aa2c2
Compare
f51bffc to
14777e4
Compare
3a847e9 to
43fa702
Compare
43fa702 to
566e043
Compare
14777e4 to
daa08e5
Compare
f64c79d to
eb4aef8
Compare
vikin91
left a comment
There was a problem hiding this comment.
Reviewed with focus only on sensor code and node/VM scanning and I don't see any issues, as there are very little changes concerning those areas.
eb4aef8 to
1f16fbd
Compare
Adds ScanSBOMRequest/ScanSBOMResponse messages and the ScanSBOM RPC to the matcher service proto, along with the generated Go code. Assisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds the server-side ScanSBOM RPC handler: SBOM decoder with PURL registry for supported ecosystems, request validation (media type allowlist), and the matcher service method that decodes → matches → maps to proto. Assisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds ScanSBOM to the Scanner gRPC client interface with retry/backoff and matcher version extraction. Includes regenerated mock. Assisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the fake stub and TODO placeholders with the actual ScanSBOM client call. Removes fakeVulnReport. Assisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire the matcher's repository-to-CPE mapping into the SBOM decoder's RHEL PURL parsing pipeline using claircore's TransformerFunc mechanism. When ScanSBOM receives an SPDX document containing RHEL RPM PURLs with a repository_id qualifier but no repository_cpes, the new TransformerFunc looks up CPEs from the cached repo2cpe mapping and injects them before ParseRPMPURL runs. Without this, RHEL RPMs in externally provided SBOMs produce no vulnerability matches because ParseRPMPURL returns empty when repository_cpes is absent. The repo2cpe.Updater was previously created inside matcherImpl but never queried (it was dead code). This change moves ownership to matcherService, which creates the updater from the indexer (ReportProvider) and uses it to build the TransformerFunc. Assisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1f16fbd to
980be11
Compare
980be11 to
10440f6
Compare
10440f6 to
7783017
Compare

Description
Wires up the remaining logic to get SBOM vulnerability reporting plumbed through stackrox.
PR stack:
masterUser-facing documentation
Testing and quality
Automated testing
No automated testing. Will follow up in ROX-27690.
How I validated my change
ROX_SBOM_SCANNINGfeature flag:Matcher API
scanner v4 client
Replicate the validation from #18484: