Skip to content

Commit 6aef94a

Browse files
reyreavmanalexey-igrychev
authored andcommitted
fix(sbom): throw warning instead of error when base/import image sbom is missing (#56)
Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
1 parent 223fe80 commit 6aef94a

3 files changed

Lines changed: 33 additions & 13 deletions

File tree

pkg/build/build_phase.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package build
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"os"
78
"strconv"
@@ -38,6 +39,7 @@ import (
3839
"github.com/werf/werf/v2/pkg/telemetry"
3940
"github.com/werf/werf/v2/pkg/util/parallel"
4041
"github.com/werf/werf/v2/pkg/werf"
42+
"github.com/werf/werf/v2/pkg/werf/global_warnings"
4143
)
4244

4345
type BuildPhaseOptions struct {
@@ -237,7 +239,8 @@ func (phase *BuildPhase) convergeSbomByImagesSets(ctx context.Context) error {
237239
}
238240

239241
if err := parallel.DoTasks(ctx, len(names), parallel.DoTasksOptions{
240-
MaxNumberOfWorkers: int(phase.Conveyor.ParallelTasksLimit),
242+
MaxNumberOfWorkers: int(phase.Conveyor.ParallelTasksLimit),
243+
InitDockerCLIForEachWorker: true,
241244
}, func(ctx context.Context, taskId int) error {
242245
name := names[taskId]
243246
images := imagesByName[name]
@@ -1445,7 +1448,8 @@ func (phase *BuildPhase) collectBaseImageSbom(ctx context.Context, img *image.Im
14451448
}
14461449

14471450
if img.GetBaseImageReference() == "" {
1448-
return nil, fmt.Errorf("unable to collect base image sbom for image %q: empty base image reference", name)
1451+
global_warnings.GlobalWarningLn(ctx, fmt.Sprintf("SBOM for base image of %q is not available: empty base image reference", name))
1452+
return nil, nil
14491453
}
14501454

14511455
var baseImageInfo *imagePkg.Info
@@ -1465,11 +1469,16 @@ func (phase *BuildPhase) collectBaseImageSbom(ctx context.Context, img *image.Im
14651469
}
14661470

14671471
if baseImageInfo == nil {
1468-
return nil, fmt.Errorf("unable to collect base image sbom for image %q: base image info not available", name)
1472+
global_warnings.GlobalWarningLn(ctx, fmt.Sprintf("SBOM for base image (from) of %q is not available: base image info not available", name))
1473+
return nil, nil
14691474
}
14701475

14711476
baseImageSbom, err := phase.sbomStep.GetImageBOM(ctx, name, img.GetBaseImageReference(), baseImageInfo)
14721477
if err != nil {
1478+
if errors.Is(err, ErrSbomNotAvailable) {
1479+
global_warnings.GlobalWarningLn(ctx, fmt.Sprintf("SBOM for base image (from) %q of %q is not available: %s", img.GetBaseImageReference(), name, err))
1480+
return nil, nil
1481+
}
14731482
return nil, fmt.Errorf("unable to get base image sbom with ref %s: %w", img.GetBaseImageReference(), err)
14741483
}
14751484

@@ -1503,11 +1512,16 @@ func (phase *BuildPhase) collectImportImageSboms(ctx context.Context, img *image
15031512
}
15041513

15051514
if importImageInfo == nil {
1506-
return nil, fmt.Errorf("unable to collect import image sbom for %q on platform %q: image info not available", importInfo.ImageName, img.TargetPlatform)
1515+
global_warnings.GlobalWarningLn(ctx, fmt.Sprintf("SBOM for imported image (import) %q of %q on platform %q is not available: image info not available", importInfo.ImageName, name, img.TargetPlatform))
1516+
continue
15071517
}
15081518

15091519
importImageSbom, err := phase.sbomStep.GetImageBOM(ctx, name, importInfo.ImageName, importImageInfo)
15101520
if err != nil {
1521+
if errors.Is(err, ErrSbomNotAvailable) {
1522+
global_warnings.GlobalWarningLn(ctx, fmt.Sprintf("SBOM for imported image (import) %q of %q is not available: %s", importInfo.ImageName, name, err))
1523+
continue
1524+
}
15111525
return nil, fmt.Errorf("unable to get import image sbom for %q: %w", importInfo.ImageName, err)
15121526
}
15131527
importImageSboms = append(importImageSboms, importImageSbom)

pkg/build/sbom_step.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package build
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"io"
78
"slices"
@@ -24,6 +25,11 @@ import (
2425
"github.com/werf/werf/v2/pkg/storage"
2526
)
2627

28+
// ErrSbomNotAvailable indicates that SBOM for the given image is not available
29+
// (e.g. it was not built by werf, or the SBOM image is missing from the registry/local storage).
30+
// Callers should handle this as a non-fatal condition by emitting a warning.
31+
var ErrSbomNotAvailable = errors.New("sbom not available")
32+
2733
type sbomStep struct {
2834
containerBackend container_backend.ContainerBackend
2935
stagesStorage storage.StagesStorage
@@ -247,7 +253,7 @@ func (step *sbomStep) findSbomImageLocally(ctx context.Context, sbomBaseImgLabel
247253

248254
func (step *sbomStep) GetImageBOM(ctx context.Context, werfImgName, imageRef string, imageInfo *image.Info) (*cdx.BOM, error) {
249255
if imageInfo == nil {
250-
return nil, fmt.Errorf("image info not available for %q", imageRef)
256+
return nil, fmt.Errorf("image info not available for %q: %w", imageRef, ErrSbomNotAvailable)
251257
}
252258

253259
return step.pullImageSbom(ctx, werfImgName, imageInfo)
@@ -290,8 +296,8 @@ func (step *sbomStep) resolveImageSbomName(baseImageInfo *image.Info) (string, e
290296
}
291297

292298
return "", fmt.Errorf(
293-
"unable to resolve SBOM name for image %q: required werf stage content digest label is missing",
294-
baseImageInfo.Name,
299+
"unable to resolve SBOM name for image %q: required werf stage content digest label is missing: %w",
300+
baseImageInfo.Name, ErrSbomNotAvailable,
295301
)
296302
}
297303

@@ -303,12 +309,12 @@ func (step *sbomStep) ensureSbomImageExists(ctx context.Context, sbomImageName,
303309
}
304310

305311
if step.isLocalStorage {
306-
return fmt.Errorf("SBOM for image %q not found locally", sourceImageName)
312+
return fmt.Errorf("SBOM for image %q not found locally: %w", sourceImageName, ErrSbomNotAvailable)
307313
}
308314

309315
logboek.Context(ctx).Default().LogF("Pulling image SBOM from %s\n", sbomImageName)
310316
if err := step.containerBackend.Pull(ctx, sbomImageName, container_backend.PullOpts{}); err != nil {
311-
return fmt.Errorf("SBOM for image %q not found in container registry: %w", sourceImageName, err)
317+
return fmt.Errorf("SBOM for image %q not found in container registry (%w): %w", sourceImageName, err, ErrSbomNotAvailable)
312318
}
313319

314320
return nil

test/e2e/build/sbom_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,12 @@ var _ = Describe("Simple build", Label("e2e", "build", "sbom", "simple"), func()
213213
Expect(err).To(HaveOccurred(), "build should fail when base image SBOM is not found")
214214
Expect(out).To(ContainSubstring("unable to get base image"))
215215
},
216-
Entry("with local repo using Vanilla Docker", simpleTestOptions{setupEnvOptions{
216+
XEntry("with local repo using Vanilla Docker", simpleTestOptions{setupEnvOptions{
217217
ContainerBackendMode: "vanilla-docker",
218218
WithLocalRepo: true,
219219
WithStagedDockerfileBuilder: false,
220220
}}),
221-
Entry("with local repo using BuildKit Docker", simpleTestOptions{setupEnvOptions{
221+
XEntry("with local repo using BuildKit Docker", simpleTestOptions{setupEnvOptions{
222222
ContainerBackendMode: "buildkit-docker",
223223
WithLocalRepo: true,
224224
WithStagedDockerfileBuilder: false,
@@ -293,12 +293,12 @@ var _ = Describe("Simple build", Label("e2e", "build", "sbom", "simple"), func()
293293
Expect(err).To(HaveOccurred(), "build should fail when base image SBOM is not found")
294294
Expect(out).To(ContainSubstring("unable to get import image sbom for"))
295295
},
296-
Entry("with local repo using Vanilla Docker", simpleTestOptions{setupEnvOptions{
296+
XEntry("with local repo using Vanilla Docker", simpleTestOptions{setupEnvOptions{
297297
ContainerBackendMode: "vanilla-docker",
298298
WithLocalRepo: true,
299299
WithStagedDockerfileBuilder: false,
300300
}}),
301-
Entry("with local repo using BuildKit Docker", simpleTestOptions{setupEnvOptions{
301+
XEntry("with local repo using BuildKit Docker", simpleTestOptions{setupEnvOptions{
302302
ContainerBackendMode: "buildkit-docker",
303303
WithLocalRepo: true,
304304
WithStagedDockerfileBuilder: false,

0 commit comments

Comments
 (0)