diff --git a/daemon/config/builder.go b/daemon/config/builder.go index 07eb5ced20..08671159b9 100644 --- a/daemon/config/builder.go +++ b/daemon/config/builder.go @@ -2,7 +2,6 @@ package config import ( "encoding/json" - "fmt" "sort" "strings" @@ -28,7 +27,7 @@ func (x *BuilderGCFilter) MarshalJSON() ([]byte, error) { for _, k := range keys { values := f.Get(k) for _, v := range values { - arr = append(arr, fmt.Sprintf("%s=%s", k, v)) + arr = append(arr, k+"="+v) } } return json.Marshal(arr) @@ -45,9 +44,9 @@ func (x *BuilderGCFilter) UnmarshalJSON(data []byte) error { return err } for _, s := range arr { - fields := strings.SplitN(s, "=", 2) - name := strings.ToLower(strings.TrimSpace(fields[0])) - value := strings.TrimSpace(fields[1]) + name, value, _ := strings.Cut(s, "=") + name = strings.ToLower(strings.TrimSpace(name)) + value = strings.TrimSpace(value) f.Add(name, value) } *x = BuilderGCFilter(f) diff --git a/daemon/config/builder_test.go b/daemon/config/builder_test.go index 6b4576446b..0cb08619e1 100644 --- a/daemon/config/builder_test.go +++ b/daemon/config/builder_test.go @@ -1,6 +1,7 @@ package config import ( + "encoding/json" "testing" "github.com/docker/docker/api/types/filters" @@ -42,3 +43,16 @@ func TestBuilderGC(t *testing.T) { assert.Assert(t, filters.Args(cfg.Builder.GC.Policy[0].Filter).UniqueExactMatch("unused-for", "2200h")) assert.Assert(t, filters.Args(cfg.Builder.GC.Policy[1].Filter).UniqueExactMatch("unused-for", "3300h")) } + +// TestBuilderGCFilterUnmarshal is a regression test for https://github.com/moby/moby/issues/44361, +// where and incorrectly formatted gc filter option ("unused-for2200h", +// missing a "=" separator). resulted in a panic during unmarshal. +func TestBuilderGCFilterUnmarshal(t *testing.T) { + var cfg BuilderGCConfig + err := json.Unmarshal([]byte(`{"poliCy": [{"keepStorage": "10GB", "filter": ["unused-for2200h"]}]}`), &cfg) + assert.Check(t, err) + expectedPolicy := []BuilderGCRule{{ + KeepStorage: "10GB", Filter: BuilderGCFilter(filters.NewArgs(filters.Arg("unused-for2200h", ""))), + }} + assert.DeepEqual(t, cfg.Policy, expectedPolicy, cmp.AllowUnexported(BuilderGCFilter{})) +} diff --git a/daemon/config/config.go b/daemon/config/config.go index d1f02c330c..a80c1109c4 100644 --- a/daemon/config/config.go +++ b/daemon/config/config.go @@ -313,13 +313,13 @@ func New() (*Config, error) { func GetConflictFreeLabels(labels []string) ([]string, error) { labelMap := map[string]string{} for _, label := range labels { - stringSlice := strings.SplitN(label, "=", 2) - if len(stringSlice) > 1 { + key, val, ok := strings.Cut(label, "=") + if ok { // If there is a conflict we will return an error - if v, ok := labelMap[stringSlice[0]]; ok && v != stringSlice[1] { - return nil, errors.Errorf("conflict labels for %s=%s and %s=%s", stringSlice[0], stringSlice[1], stringSlice[0], v) + if v, ok := labelMap[key]; ok && v != val { + return nil, errors.Errorf("conflict labels for %s=%s and %s=%s", key, val, key, v) } - labelMap[stringSlice[0]] = stringSlice[1] + labelMap[key] = val } }