From 1a26cfb17b364fed178d078e1e5f52814666788b Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Thu, 21 May 2026 16:17:56 +0400 Subject: [PATCH] fix(sbom): make sc sbom generate fail loudly on syft errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The standalone CLI built a SecurityConfig with SBOM.Required=false, which told the executor to fail-open: on syft errors it printed "Warning: SBOM generation failed, continuing" and returned (nil, nil). The CLI wrapper then turned that nil-nil into "Error: no SBOM generated" and exited 1 — fail-open semantics with a fail-closed exit code. For a user-invoked `sc sbom generate`, the right behavior is fail-loud: surface the real syft error (signal: killed for OOM, registry timeouts, etc.) so the caller knows why. Setting Required=true makes the executor return the underlying error directly, which the wrapper already maps to "failed to generate SBOM: ". Surfaced by a PAY-SPACE pay_space_wallet production deploy where syft was OOM-killed on a large image; Pulumi saw "no SBOM generated" exit 1 and aborted the stack update. Signed-off-by: Dmitrii Creed --- pkg/cmd/cmd_sbom/generate.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/cmd/cmd_sbom/generate.go b/pkg/cmd/cmd_sbom/generate.go index aef8c23d..1ba28c4c 100644 --- a/pkg/cmd/cmd_sbom/generate.go +++ b/pkg/cmd/cmd_sbom/generate.go @@ -67,6 +67,7 @@ func runGenerate(ctx context.Context, opts *generateOptions) error { Enabled: true, SBOM: &security.SBOMConfig{ Enabled: true, + Required: true, Format: string(format), Generator: "syft", Output: &security.OutputConfig{ @@ -91,9 +92,6 @@ func runGenerate(ctx context.Context, opts *generateOptions) error { if err != nil { return fmt.Errorf("failed to generate SBOM: %w", err) } - if generatedSBOM == nil { - return fmt.Errorf("no SBOM generated") - } // Print summary fmt.Printf("✓ SBOM generated successfully\n")