Skip to content

fix(sbom): classify sidecar oversized images as TooLarge - #880

Merged
matthyx merged 1 commit into
kubescape:mainfrom
manumathon:fix/sbom-sidecar-too-large-classification
Aug 7, 2026
Merged

fix(sbom): classify sidecar oversized images as TooLarge#880
matthyx merged 1 commit into
kubescape:mainfrom
manumathon:fix/sbom-sidecar-too-large-classification

Conversation

@manumathon

@manumathon manumathon commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Overview

Fix the sidecar SBOM path to classify oversized images the same way as the in-process path. This change maps gRPC FailedPrecondition to ErrImageTooLarge and updates SBOM handling to mark fresh SBOMs as TooLarge while preserving content-bearing SBOMs on the generic Incomplete path.

How to Test

go test ./pkg/sbomscanner/v1/ -run 'TestIntegration_ImageTooLarge|TestCreateSBOM_ImageTooLarge' -count=1
go test ./pkg/sbommanager/v1/ -run 'TooLargeImmediatelyViaSidecar|PreservesContentOnSidecarTooLarge' -count=1

Related issues/PRs

Summary by CodeRabbit

  • New Features

    • Images exceeding the maximum allowed size are now explicitly flagged as too large without consuming retry attempts.
  • Bug Fixes

    • Enhanced error handling to distinguish image size limit violations from other failure conditions, preserving existing SBOM content when applicable.
  • Tests

    • Added test coverage for oversized image handling scenarios.

Map sidecar FailedPrecondition responses to ErrImageTooLarge so SBOM processing treats oversized images as terminal TooLarge failures instead of retrying them as generic Incomplete errors.

Signed-off-by: Manu <kiratcodes99@gmail.com>
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 15fb5ac6-cac2-4d1a-96bf-a65b18421992

📥 Commits

Reviewing files that changed from the base of the PR and between 8866b6c and 36de36d.

📒 Files selected for processing (6)
  • pkg/sbommanager/v1/sbom_manager.go
  • pkg/sbommanager/v1/sbom_manager_reprocessing_test.go
  • pkg/sbomscanner/v1/client.go
  • pkg/sbomscanner/v1/integration_test.go
  • pkg/sbomscanner/v1/server.go
  • pkg/sbomscanner/v1/types.go

📝 Walkthrough

Walkthrough

Changes

Sidecar image-size error handling

Layer / File(s) Summary
Scanner error contract and mapping
pkg/sbomscanner/v1/types.go, pkg/sbomscanner/v1/server.go, pkg/sbomscanner/v1/client.go, pkg/sbomscanner/v1/integration_test.go
The scanner defines and propagates ErrImageTooLarge. The client maps FailedPrecondition responses to this error. Integration tests assert the sentinel error.
SBOM manager status handling
pkg/sbommanager/v1/sbom_manager.go, pkg/sbommanager/v1/sbom_manager_reprocessing_test.go
The sidecar path marks fresh SBOMs as TooLarge, preserves content-bearing SBOMs through retry handling, and reports ReasonImageTooLarge.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ScannerServer
  participant ScannerClient
  participant SBOMManager
  participant SBOMStorage
  ScannerServer->>ScannerClient: Return FailedPrecondition
  ScannerClient->>ScannerClient: Map response to ErrImageTooLarge
  ScannerClient->>SBOMManager: Return ErrImageTooLarge
  SBOMManager->>SBOMStorage: Mark fresh SBOM TooLarge
  SBOMManager->>SBOMStorage: Retry content-bearing SBOM
  SBOMManager->>SBOMStorage: Mark repeated failure Incomplete
Loading

Possibly related PRs

Suggested labels: release

Suggested reviewers: entlein

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary fix for sidecar handling of oversized images.
Linked Issues check ✅ Passed The changes map FailedPrecondition to ErrImageTooLarge and apply the required TooLarge, retry, and reporting behavior [#877].
Out of Scope Changes check ✅ Passed All code and test changes directly support oversized-image handling in the sidecar SBOM path.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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.

if ok && (st.Code() == codes.Unavailable || st.Code() == codes.Aborted) {
return nil, fmt.Errorf("%w: %v", ErrScannerCrashed, err)
}
if ok && st.Code() == codes.FailedPrecondition {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

FailedPrecondition is currently the sidecar transport signal for ErrImageTooLarge.

@matthyx matthyx moved this to Needs Reviewer in KS PRs tracking Aug 6, 2026

@matthyx matthyx left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved ✅

This is a faithful, minimal implementation of the fix described in #877. The sidecar branch mirrors the in-process branch semantics exactly — including the wipSbomHadContent guard that keeps a content-bearing SBOM away from the TooLarge one-way door — and both new tests are the correct counterparts to the existing in-process ones.

Verification performed locally (at 36de36d)

Check Result
go build ./... pass
go vet ./pkg/sbomscanner/... ./pkg/sbommanager/... pass
go test ./pkg/sbomscanner/... ./pkg/sbommanager/... pass
codes.FailedPrecondition producers repo-wide exactly one (server.go:60) — the mapping is unambiguous today

Correctness review

  • client.go — the new mapping is placed after the Unavailable/AbortedErrScannerCrashed check, so a crashed sidecar still wins. Correct ordering.
  • sbom_manager.go — the new branch is checked before the generic fallback and after ErrScannerCrashed, matching the in-process precedence. It correctly does not call SetSBOMScannerReady(false): an oversized image leaves the sidecar healthy.
  • markSBOMStatus(..., TooLarge, nil) with no ScannerMemoryLimitAnnotation is right here — that annotation exists to re-open the OOM-crash path when the memory limit changes, and an image-size limit breach is not memory-driven. Same as the in-process path.
  • Test_..._PreservesContentOnSidecarTooLarge — I traced the loop: iterations 1–2 only increment the budget, iteration 3 pins Incomplete, iterations 4–5 short-circuit on the Incomplete + same-tool-version case. patchCalls == 1 is the correct assertion.
  • Wire contract is still covered — the integration test now asserts the sentinel, but server_test.go:TestCreateSBOM_ImageTooLarge still asserts codes.FailedPrecondition at the raw pb layer, so relaxing the integration assertion loses nothing.
  • Backward compatible under sidecar/node-agent version skew in both directions.

CodeRabbit found nothing actionable, and I found no blockers either. Three non-blocking notes inline — the gofmt one is worth folding in before merge since it's a one-character fix.

var (
ErrScannerCrashed = errors.New("SBOM scanner sidecar crashed during scan")
ErrScannerNotReady = errors.New("SBOM scanner sidecar not ready")
ErrImageTooLarge = errors.New("image size exceeds maximum allowed size")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit (worth fixing before merge): this line isn't gofmt-clean — the new entry breaks the var block's = alignment.

$ gofmt -d pkg/sbomscanner/v1/types.go
-	ErrImageTooLarge = errors.New("image size exceeds maximum allowed size")
+	ErrImageTooLarge   = errors.New("image size exceeds maximum allowed size")

No CI gate catches it (go-basic-tests.yaml runs build + tests, no gofmt/lint step), so this won't turn the PR red — but the next person with format-on-save will produce a spurious diff here. For the record, the gofmt findings in client.go and server.go are import-ordering issues that already exist on main; only this one is new.

Separate, optional: the repo now has two distinct sentinels with byte-identical messages — syftutil.ErrImageTooLarge and this one. errors.Is does not relate them, which is exactly why sbom_manager.go has to check a different sentinel per branch. That's correct as written, but easy to misread. Since this package already imports syftutil (server.go), var ErrImageTooLarge = syftutil.ErrImageTooLarge would collapse them into one identity and make both branches match the same target. Your call — the current split is defensible if you want the transport sentinel to stay independent of the syft layer.

if ok && (st.Code() == codes.Unavailable || st.Code() == codes.Aborted) {
return nil, fmt.Errorf("%w: %v", ErrScannerCrashed, err)
}
if ok && st.Code() == codes.FailedPrecondition {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Non-blocking, but the consequence is severe enough to flag. This is correct today — I grepped the repo and codes.FailedPrecondition is produced in exactly one place (server.go:60), so the mapping is unambiguous.

The concern is what happens when that stops being true. FailedPrecondition is a natural code to reach for on a future precondition failure ("layer paths not mounted", "scanner not initialized", ...). The moment a second one is added, this branch silently converts it to ErrImageTooLarge, and sbom_manager.go writes TooLarge — which, per the comment at sbom_manager.go:381-386, is a storage-layer one-way door where GuaranteedUpdate drops every future write. The SBOM would be permanently frozen and unfixable by any later version. Low probability, unbounded blast radius, and the failure is silent.

Two cheap ways to bound it, pick either:

  1. Match code and message. You already changed server.go:60 to send ErrImageTooLarge.Error(), but nothing consumes that — the coupling is currently write-only. Both binaries ship from this repo, so message matching is safe here and narrows the check to exactly the intended condition.
  2. Keep the code-only check and add a one-line comment at server.go:60 reserving FailedPrecondition for image-too-large, pointing at this branch as the consumer. Cheaper, and enough to stop the next person.

Option 2 alone is fine by me.

} else {
s.markSBOMStatus(sbomName, helpersv1.TooLarge, nil)
}
s.reportFailure(notif, imageTag, imageID, scanfailure.ReasonImageTooLarge, scanErr)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Test-coverage gap, non-blocking. #877 asked for a test asserting TooLarge and ReasonImageTooLarge and no retry-budget consumption. The two new tests nail the first and third — but not the reason.

newTestManagerWithScannerErr leaves failureReporter nil, and reportFailure returns immediately on a nil reporter, so this line never executes under test. That matters because the wrong user-facing reason was impact #2 in the issue: operators see "Failed to generate software inventory (SBOM)" instead of "Image exceeds the maximum size limit", which is the whole signal that raising maxImageSize is the remedy. Right now nothing would catch a regression that swaps this back to ReasonSBOMGenerationFailed.

In fairness this is symmetric with existing coverage — the in-process Test_..._MarksFreshImageTooLargeImmediately doesn't assert the reason either, and http_failure_reporter_test.go only tests the reporter in isolation, not which reason the manager hands it. So this is a pre-existing convention, not a regression you introduced.

A fake reporter capturing FailureReason into a slice, wired through newTestManagerWithScannerErr, would close it for both paths in a few lines. Happy to see it land as a follow-up rather than hold this PR.

@matthyx
matthyx merged commit b17e274 into kubescape:main Aug 7, 2026
9 of 15 checks passed
@matthyx matthyx moved this from Needs Reviewer to To Archive in KS PRs tracking Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

SBOM sidecar path misclassifies oversized images as Incomplete instead of TooLarge

2 participants