From f45d125efd86bef4aea0ea1693fb5d89e1d46d60 Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Thu, 15 Dec 2022 11:31:22 +0000 Subject: [PATCH 1/2] dockerfile: apply no-cache to generated sboms If any of the stages that we would have generated sboms for match the no-cache filter, then the no-cache filter should also be applied to the sbom generation. Signed-off-by: Justin Chadwell --- frontend/attestations/sbom/sbom.go | 17 ++++++++++------- frontend/dockerfile/builder/build.go | 8 +++++++- frontend/dockerfile/dockerfile2llb/convert.go | 8 ++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/frontend/attestations/sbom/sbom.go b/frontend/attestations/sbom/sbom.go index 4d3ef36eecaa..54e8e316a2a2 100644 --- a/frontend/attestations/sbom/sbom.go +++ b/frontend/attestations/sbom/sbom.go @@ -31,7 +31,7 @@ const ( // build-contexts or multi-stage builds. Handling these separately allows the // scanner to optionally ignore these or to mark them as such in the // attestation. -type Scanner func(ctx context.Context, name string, ref llb.State, extras map[string]llb.State) (result.Attestation[llb.State], error) +type Scanner func(ctx context.Context, name string, ref llb.State, extras map[string]llb.State, opts ...llb.ConstraintsOpt) (result.Attestation[llb.State], error) func CreateSBOMScanner(ctx context.Context, resolver llb.ImageMetaResolver, scanner string) (Scanner, error) { if scanner == "" { @@ -55,7 +55,7 @@ func CreateSBOMScanner(ctx context.Context, resolver llb.ImageMetaResolver, scan return nil, errors.Errorf("scanner %s does not have cmd", scanner) } - return func(ctx context.Context, name string, ref llb.State, extras map[string]llb.State) (result.Attestation[llb.State], error) { + return func(ctx context.Context, name string, ref llb.State, extras map[string]llb.State, opts ...llb.ConstraintsOpt) (result.Attestation[llb.State], error) { var env []string env = append(env, cfg.Config.Env...) env = append(env, "BUILDKIT_SCAN_DESTINATION="+outDir) @@ -64,17 +64,20 @@ func CreateSBOMScanner(ctx context.Context, resolver llb.ImageMetaResolver, scan env = append(env, "BUILDKIT_SCAN_SOURCE_EXTRAS="+path.Join(srcDir, "extras/")) } - opts := []llb.RunOption{ - llb.Dir(cfg.Config.WorkingDir), - llb.Args(args), + runOpts := []llb.RunOption{ llb.WithCustomName(fmt.Sprintf("[%s] generating sbom using %s", name, scanner)), } + for _, opt := range opts { + runOpts = append(runOpts, opt) + } + runOpts = append(runOpts, llb.Dir(cfg.Config.WorkingDir)) + runOpts = append(runOpts, llb.Args(args)) for _, e := range env { k, v, _ := strings.Cut(e, "=") - opts = append(opts, llb.AddEnv(k, v)) + runOpts = append(runOpts, llb.AddEnv(k, v)) } - runscan := llb.Image(scanner).Run(opts...) + runscan := llb.Image(scanner).Run(runOpts...) runscan.AddMount(path.Join(srcDir, "core", CoreSBOMName), ref, llb.Readonly) for k, extra := range extras { runscan.AddMount(path.Join(srcDir, "extras", ExtraSBOMPrefix+k), extra, llb.Readonly) diff --git a/frontend/dockerfile/builder/build.go b/frontend/dockerfile/builder/build.go index 8c429efa46e9..f9dd3643cd63 100644 --- a/frontend/dockerfile/builder/build.go +++ b/frontend/dockerfile/builder/build.go @@ -613,7 +613,13 @@ func Build(ctx context.Context, c client.Client) (_ *client.Result, err error) { if scanner != nil { for i, p := range expPlatforms.Platforms { - att, err := scanner(ctx, p.ID, scanTargets[i].Core, scanTargets[i].Extras) + target := scanTargets[i] + + var opts []llb.ConstraintsOpt + if target.IgnoreCache { + opts = append(opts, llb.IgnoreCache) + } + att, err := scanner(ctx, p.ID, target.Core, target.Extras, opts...) if err != nil { return nil, err } diff --git a/frontend/dockerfile/dockerfile2llb/convert.go b/frontend/dockerfile/dockerfile2llb/convert.go index a898e3f725cc..546187202afa 100644 --- a/frontend/dockerfile/dockerfile2llb/convert.go +++ b/frontend/dockerfile/dockerfile2llb/convert.go @@ -88,6 +88,8 @@ type ConvertOpt struct { type SBOMTargets struct { Core llb.State Extras map[string]llb.State + + IgnoreCache bool } func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, *Image, *SBOMTargets, error) { @@ -103,9 +105,15 @@ func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, if ds.scanContext { sbom.Extras["context"] = ds.opt.buildContext } + if ds.ignoreCache { + sbom.IgnoreCache = true + } for _, dsi := range findReachable(ds) { if ds != dsi && dsi.scanStage { sbom.Extras[dsi.stageName] = dsi.state + if dsi.ignoreCache { + sbom.IgnoreCache = true + } } } From d3700c0a5aa306242acdf31a5e7ed5abd5250c50 Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Thu, 15 Dec 2022 17:49:18 +0000 Subject: [PATCH 2/2] solver: apply no-cache to generated sboms The fallback scanner should also respect the no-cache value if set. Signed-off-by: Justin Chadwell --- control/control.go | 8 +++++++- solver/llbsolver/proc/sbom.go | 8 ++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/control/control.go b/control/control.go index 27d61e82970f..ef0f2cf59597 100644 --- a/control/control.go +++ b/control/control.go @@ -395,8 +395,14 @@ func (c *Controller) Solve(ctx context.Context, req *controlapi.SolveRequest) (* if err != nil { return nil, errors.Wrapf(err, "failed to parse sbom generator %s", src) } + + useCache := true + if v, ok := req.FrontendAttrs["no-cache"]; ok && v == "" { + // disable cache if cache is disabled for all stages + useCache = false + } ref = reference.TagNameOnly(ref) - procs = append(procs, proc.SBOMProcessor(ref.String())) + procs = append(procs, proc.SBOMProcessor(ref.String(), useCache)) } if attrs, ok := attests["provenance"]; ok { diff --git a/solver/llbsolver/proc/sbom.go b/solver/llbsolver/proc/sbom.go index dd68ef9b6dcf..2d7e969ba547 100644 --- a/solver/llbsolver/proc/sbom.go +++ b/solver/llbsolver/proc/sbom.go @@ -13,7 +13,7 @@ import ( "github.com/pkg/errors" ) -func SBOMProcessor(scannerRef string) llbsolver.Processor { +func SBOMProcessor(scannerRef string, useCache bool) llbsolver.Processor { return func(ctx context.Context, res *llbsolver.Result, s *llbsolver.Solver, j *solver.Job) (*llbsolver.Result, error) { // skip sbom generation if we already have an sbom if sbom.HasSBOM(res.Result) { @@ -44,7 +44,11 @@ func SBOMProcessor(scannerRef string) llbsolver.Processor { } st := llb.NewState(defop) - att, err := scanner(ctx, p.ID, st, nil) + var opts []llb.ConstraintsOpt + if !useCache { + opts = append(opts, llb.IgnoreCache) + } + att, err := scanner(ctx, p.ID, st, nil, opts...) if err != nil { return nil, err }