From c30db6a9557a63ca931dba90348000102abfd1de Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 2 Dec 2024 14:46:58 -0800 Subject: [PATCH] bake: fix entitlements path checks for local outputs Previous check based on dest attributes was not correct as the attributes already get converted before validation happens. Because the local path is not preserved for single-file outputs and gets replaced by io.Writer, a temporary array variable was needed. This value should instead be added to ExportEntry struct in BuildKit in future revision. Signed-off-by: Tonis Tiigi (cherry picked from commit c6e403ad7f239409a28355be9a494805d895759b) --- bake/bake.go | 3 ++- bake/entitlements.go | 13 ++---------- bake/entitlements_test.go | 24 ++++------------------ build/build.go | 43 ++++++++++++++++++++------------------- controller/build/build.go | 2 +- controller/pb/export.go | 29 ++++++++++++++------------ 6 files changed, 47 insertions(+), 67 deletions(-) diff --git a/bake/bake.go b/bake/bake.go index 10f6cf1e..f3eea4f7 100644 --- a/bake/bake.go +++ b/bake/bake.go @@ -1329,7 +1329,8 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) { if err != nil { return nil, err } - bo.Exports, err = controllerapi.CreateExports(outputs) + + bo.Exports, bo.ExportsLocalPathsTemporary, err = controllerapi.CreateExports(outputs) if err != nil { return nil, err } diff --git a/bake/entitlements.go b/bake/entitlements.go index b7160481..116051ff 100644 --- a/bake/entitlements.go +++ b/bake/entitlements.go @@ -113,17 +113,8 @@ func (c EntitlementConf) check(bo build.Options, expected *EntitlementConf) erro roPaths[p] = struct{}{} } - for _, out := range bo.Exports { - if out.Type == "local" { - if dest, ok := out.Attrs["dest"]; ok { - rwPaths[dest] = struct{}{} - } - } - if out.Type == "tar" { - if dest, ok := out.Attrs["dest"]; ok && dest != "-" { - rwPaths[dest] = struct{}{} - } - } + for _, p := range bo.ExportsLocalPathsTemporary { + rwPaths[p] = struct{}{} } for _, ce := range bo.CacheTo { diff --git a/bake/entitlements_test.go b/bake/entitlements_test.go index 16cd8bc6..ef1bbdec 100644 --- a/bake/entitlements_test.go +++ b/bake/entitlements_test.go @@ -10,7 +10,6 @@ import ( "github.com/docker/buildx/build" "github.com/docker/buildx/controller/pb" "github.com/docker/buildx/util/osutil" - "github.com/moby/buildkit/client" "github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/util/entitlements" "github.com/stretchr/testify/require" @@ -279,25 +278,10 @@ func TestValidateEntitlements(t *testing.T) { { name: "ExportLocal", opt: build.Options{ - Exports: []client.ExportEntry{ - { - Type: "local", - Attrs: map[string]string{ - "dest": dir1, - }, - }, - { - Type: "local", - Attrs: map[string]string{ - "dest": filepath.Join(dir1, "subdir"), - }, - }, - { - Type: "local", - Attrs: map[string]string{ - "dest": dir2, - }, - }, + ExportsLocalPathsTemporary: []string{ + dir1, + filepath.Join(dir1, "subdir"), + dir2, }, }, expected: EntitlementConf{ diff --git a/build/build.go b/build/build.go index 3a2e7663..4663d1f4 100644 --- a/build/build.go +++ b/build/build.go @@ -62,27 +62,28 @@ const ( type Options struct { Inputs Inputs - Ref string - Allow []entitlements.Entitlement - Attests map[string]*string - BuildArgs map[string]string - CacheFrom []client.CacheOptionsEntry - CacheTo []client.CacheOptionsEntry - CgroupParent string - Exports []client.ExportEntry - ExtraHosts []string - Labels map[string]string - NetworkMode string - NoCache bool - NoCacheFilter []string - Platforms []specs.Platform - Pull bool - SecretSpecs []*controllerapi.Secret - SSHSpecs []*controllerapi.SSH - ShmSize opts.MemBytes - Tags []string - Target string - Ulimits *opts.UlimitOpt + Ref string + Allow []entitlements.Entitlement + Attests map[string]*string + BuildArgs map[string]string + CacheFrom []client.CacheOptionsEntry + CacheTo []client.CacheOptionsEntry + CgroupParent string + Exports []client.ExportEntry + ExportsLocalPathsTemporary []string // should be removed after client.ExportEntry update in buildkit v0.19.0 + ExtraHosts []string + Labels map[string]string + NetworkMode string + NoCache bool + NoCacheFilter []string + Platforms []specs.Platform + Pull bool + SecretSpecs []*controllerapi.Secret + SSHSpecs []*controllerapi.SSH + ShmSize opts.MemBytes + Tags []string + Target string + Ulimits *opts.UlimitOpt Session []session.Attachable Linked bool // Linked marks this target as exclusively linked (not requested by the user). diff --git a/controller/build/build.go b/controller/build/build.go index 7a57dc7d..5e0c89c2 100644 --- a/controller/build/build.go +++ b/controller/build/build.go @@ -93,7 +93,7 @@ func RunBuild(ctx context.Context, dockerCli command.Cli, in *controllerapi.Buil } opts.Session = append(opts.Session, ssh) - outputs, err := controllerapi.CreateExports(in.Exports) + outputs, _, err := controllerapi.CreateExports(in.Exports) if err != nil { return nil, nil, nil, err } diff --git a/controller/pb/export.go b/controller/pb/export.go index 3de33eb3..af60bc88 100644 --- a/controller/pb/export.go +++ b/controller/pb/export.go @@ -10,15 +10,16 @@ import ( "github.com/pkg/errors" ) -func CreateExports(entries []*ExportEntry) ([]client.ExportEntry, error) { +func CreateExports(entries []*ExportEntry) ([]client.ExportEntry, []string, error) { var outs []client.ExportEntry + var localPaths []string if len(entries) == 0 { - return nil, nil + return nil, nil, nil } var stdoutUsed bool for _, entry := range entries { if entry.Type == "" { - return nil, errors.Errorf("type is required for output") + return nil, nil, errors.Errorf("type is required for output") } out := client.ExportEntry{ @@ -49,20 +50,21 @@ func CreateExports(entries []*ExportEntry) ([]client.ExportEntry, error) { if supportDir { if entry.Destination == "" { - return nil, errors.Errorf("dest is required for %s exporter", out.Type) + return nil, nil, errors.Errorf("dest is required for %s exporter", out.Type) } if entry.Destination == "-" { - return nil, errors.Errorf("dest cannot be stdout for %s exporter", out.Type) + return nil, nil, errors.Errorf("dest cannot be stdout for %s exporter", out.Type) } fi, err := os.Stat(entry.Destination) if err != nil && !os.IsNotExist(err) { - return nil, errors.Wrapf(err, "invalid destination directory: %s", entry.Destination) + return nil, nil, errors.Wrapf(err, "invalid destination directory: %s", entry.Destination) } if err == nil && !fi.IsDir() { - return nil, errors.Errorf("destination directory %s is a file", entry.Destination) + return nil, nil, errors.Errorf("destination directory %s is a file", entry.Destination) } out.OutputDir = entry.Destination + localPaths = append(localPaths, entry.Destination) } if supportFile { if entry.Destination == "" && out.Type != client.ExporterDocker { @@ -70,32 +72,33 @@ func CreateExports(entries []*ExportEntry) ([]client.ExportEntry, error) { } if entry.Destination == "-" { if stdoutUsed { - return nil, errors.Errorf("multiple outputs configured to write to stdout") + return nil, nil, errors.Errorf("multiple outputs configured to write to stdout") } if _, err := console.ConsoleFromFile(os.Stdout); err == nil { - return nil, errors.Errorf("dest file is required for %s exporter. refusing to write to console", out.Type) + return nil, nil, errors.Errorf("dest file is required for %s exporter. refusing to write to console", out.Type) } out.Output = wrapWriteCloser(os.Stdout) stdoutUsed = true } else if entry.Destination != "" { fi, err := os.Stat(entry.Destination) if err != nil && !os.IsNotExist(err) { - return nil, errors.Wrapf(err, "invalid destination file: %s", entry.Destination) + return nil, nil, errors.Wrapf(err, "invalid destination file: %s", entry.Destination) } if err == nil && fi.IsDir() { - return nil, errors.Errorf("destination file %s is a directory", entry.Destination) + return nil, nil, errors.Errorf("destination file %s is a directory", entry.Destination) } f, err := os.Create(entry.Destination) if err != nil { - return nil, errors.Errorf("failed to open %s", err) + return nil, nil, errors.Errorf("failed to open %s", err) } out.Output = wrapWriteCloser(f) + localPaths = append(localPaths, entry.Destination) } } outs = append(outs, out) } - return outs, nil + return outs, localPaths, nil } func wrapWriteCloser(wc io.WriteCloser) func(map[string]string) (io.WriteCloser, error) {