From 2ff20ec51b105f8f03341e537ff4c5686779488c Mon Sep 17 00:00:00 2001 From: Aaron Mark <64331623+amarkdotdev@users.noreply.github.com> Date: Mon, 15 Jun 2026 15:20:08 +0000 Subject: [PATCH 1/2] bake: reject targets inside target blocks Signed-off-by: Aaron Mark <64331623+amarkdotdev@users.noreply.github.com> --- bake/bake.go | 34 ++++++++++++++++++++++++++++++++++ bake/hcl_test.go | 21 +++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/bake/bake.go b/bake/bake.go index 66ef0a1d55b4..d14a24fcd5c2 100644 --- a/bake/bake.go +++ b/bake/bake.go @@ -413,6 +413,10 @@ func ParseFiles(files []File, defaults, vars map[string]string) (_ *Config, _ *h pm = *res } + if err := validateTargetGroups(hclFiles); err != nil { + return nil, nil, err + } + return &c, &pm, nil } @@ -442,6 +446,36 @@ func ParseFile(dt []byte, fn string) (*Config, error) { return c, err } +func validateTargetGroups(files []*hcl.File) error { + schema := &hcl.BodySchema{ + Blocks: []hcl.BlockHeaderSchema{ + {Type: "target", LabelNames: []string{"name"}}, + }, + } + for _, f := range files { + content, _, diags := f.Body.PartialContent(schema) + if diags.HasErrors() { + return diags + } + for _, block := range content.Blocks { + attrs, diags := block.Body.JustAttributes() + if diags.HasErrors() { + return diags + } + if attr, ok := attrs["targets"]; ok { + return hcl.Diagnostics{&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Unsupported argument", + Detail: "The \"targets\" argument is not valid inside a target block; use a group block instead.", + Subject: attr.NameRange.Ptr(), + Context: attr.Range.Ptr(), + }} + } + } + } + return nil +} + type Config struct { Groups []*Group `json:"group" hcl:"group,block" cty:"group"` Targets []*Target `json:"target" hcl:"target,block" cty:"target"` diff --git a/bake/hcl_test.go b/bake/hcl_test.go index c57ac78213b7..ec5633bb53ad 100644 --- a/bake/hcl_test.go +++ b/bake/hcl_test.go @@ -188,6 +188,27 @@ func TestHCLWithUserDefinedFunctions(t *testing.T) { require.Equal(t, ptrstr("124"), c.Targets[0].Args["buildno"]) } +func TestTargetDisallowsGroupTargetsAttribute(t *testing.T) { + dt := []byte(` + target "app" { + dockerfile = "app.Dockerfile" + } + + target "db" { + dockerfile = "db.Dockerfile" + } + + target "foo" { + targets = ["app", "db"] + } + `) + + _, err := ParseFile(dt, "docker-bake.hcl") + require.Error(t, err) + require.ErrorContains(t, err, "Unsupported argument") + require.ErrorContains(t, err, "targets") +} + func TestHCLWithVariables(t *testing.T) { dt := []byte(` variable "BUILD_NUMBER" { From 66aadfa01ffc21edb14a55b2dd3731b0fa54324c Mon Sep 17 00:00:00 2001 From: Aaron Mark <64331623+amarkdotdev@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:32:06 +0300 Subject: [PATCH 2/2] bake: expand tests for targets-in-target validation Document the targeted guard across HCL, JSON, and merged bake files. Signed-off-by: Aaron Mark <64331623+amarkdotdev@users.noreply.github.com> --- bake/hcl_test.go | 167 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 152 insertions(+), 15 deletions(-) diff --git a/bake/hcl_test.go b/bake/hcl_test.go index ec5633bb53ad..5eb650ea2789 100644 --- a/bake/hcl_test.go +++ b/bake/hcl_test.go @@ -189,24 +189,161 @@ func TestHCLWithUserDefinedFunctions(t *testing.T) { } func TestTargetDisallowsGroupTargetsAttribute(t *testing.T) { - dt := []byte(` - target "app" { - dockerfile = "app.Dockerfile" - } + t.Run("hcl", func(t *testing.T) { + dt := []byte(` + target "app" { + dockerfile = "app.Dockerfile" + } - target "db" { - dockerfile = "db.Dockerfile" - } + target "db" { + dockerfile = "db.Dockerfile" + } - target "foo" { - targets = ["app", "db"] - } - `) + target "foo" { + targets = ["app", "db"] + } + `) - _, err := ParseFile(dt, "docker-bake.hcl") - require.Error(t, err) - require.ErrorContains(t, err, "Unsupported argument") - require.ErrorContains(t, err, "targets") + _, err := ParseFile(dt, "docker-bake.hcl") + require.Error(t, err) + require.ErrorContains(t, err, "Unsupported argument") + require.ErrorContains(t, err, "targets") + require.ErrorContains(t, err, "docker-bake.hcl") + }) + + t.Run("json", func(t *testing.T) { + dt := []byte(`{ + "group": { + "default": { + "targets": ["foo"] + } + }, + "target": { + "app": { + "dockerfile": "app.Dockerfile" + }, + "db": { + "dockerfile": "db.Dockerfile" + }, + "foo": { + "targets": ["app", "db"] + } + } + }`) + + _, err := ParseFile(dt, "docker-bake.json") + require.Error(t, err) + require.ErrorContains(t, err, "Unsupported argument") + require.ErrorContains(t, err, "targets") + require.ErrorContains(t, err, "docker-bake.json") + }) + + t.Run("merged hcl files", func(t *testing.T) { + _, _, err := ParseFiles([]File{ + { + Name: "base.hcl", + Data: []byte(` + target "app" { + dockerfile = "app.Dockerfile" + } + + target "db" { + dockerfile = "db.Dockerfile" + } + `), + }, + { + Name: "group-as-target.hcl", + Data: []byte(` + target "foo" { + targets = ["app", "db"] + } + `), + }, + }, nil, nil) + require.Error(t, err) + require.ErrorContains(t, err, "Unsupported argument") + require.ErrorContains(t, err, "targets") + require.ErrorContains(t, err, "group-as-target.hcl") + }) + + t.Run("merged hcl and json", func(t *testing.T) { + _, _, err := ParseFiles([]File{ + { + Name: "docker-bake.hcl", + Data: []byte(` + group "default" { + targets = ["foo"] + } + + target "app" { + dockerfile = "app.Dockerfile" + } + `), + }, + { + Name: "extra.json", + Data: []byte(`{ + "target": { + "foo": { + "targets": ["app"] + } + } + }`), + }, + }, nil, nil) + require.Error(t, err) + require.ErrorContains(t, err, "Unsupported argument") + require.ErrorContains(t, err, "targets") + require.ErrorContains(t, err, "extra.json") + }) + + t.Run("group targets still valid", func(t *testing.T) { + dt := []byte(` + target "app" { + dockerfile = "app.Dockerfile" + } + + target "db" { + dockerfile = "db.Dockerfile" + } + + group "foo" { + targets = ["app", "db"] + } + `) + + c, err := ParseFile(dt, "docker-bake.hcl") + require.NoError(t, err) + require.Equal(t, 1, len(c.Groups)) + require.Equal(t, "foo", c.Groups[0].Name) + require.Equal(t, []string{"app", "db"}, c.Groups[0].Targets) + }) + + t.Run("merged valid files", func(t *testing.T) { + c, _, err := ParseFiles([]File{ + { + Name: "targets.hcl", + Data: []byte(` + target "app" { + dockerfile = "app.Dockerfile" + } + `), + }, + { + Name: "groups.hcl", + Data: []byte(` + group "foo" { + targets = ["app"] + } + `), + }, + }, nil, nil) + require.NoError(t, err) + require.Equal(t, 1, len(c.Groups)) + require.Equal(t, "foo", c.Groups[0].Name) + require.Equal(t, []string{"app"}, c.Groups[0].Targets) + }) } func TestHCLWithVariables(t *testing.T) {