From 05bd06e405d34b53eed1c0812d846d28038bb14a Mon Sep 17 00:00:00 2001 From: "xinjun.jiang" Date: Tue, 22 Sep 2026 15:57:24 +0800 Subject: [PATCH] fix: handle null Docker runtimes A JSON null runtimes entry decodes to a nil interface. Adding, removing, or looking up a runtime currently asserts that value to a map and panics. Treat a null runtimes entry like an absent entry before the assertion. Cover all three operations using a configuration loaded from a file and verify unrelated settings survive saving the updated configuration. Signed-off-by: xinjun.jiang --- pkg/config/engine/docker/docker.go | 6 ++--- pkg/config/engine/docker/docker_test.go | 33 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/pkg/config/engine/docker/docker.go b/pkg/config/engine/docker/docker.go index fb6f502f5..696a3ae9f 100644 --- a/pkg/config/engine/docker/docker.go +++ b/pkg/config/engine/docker/docker.go @@ -74,7 +74,7 @@ func (c *Config) AddRuntime(name string, path string, setAsDefault bool) error { // Read the existing runtimes runtimes := make(map[string]any) - if _, exists := config["runtimes"]; exists { + if config["runtimes"] != nil { runtimes = config["runtimes"].(map[string]any) } @@ -135,7 +135,7 @@ func (c *Config) RemoveRuntime(name string) error { } } - if _, exists := config["runtimes"]; exists { + if config["runtimes"] != nil { runtimes := config["runtimes"].(map[string]any) delete(runtimes, name) @@ -203,7 +203,7 @@ func (c *Config) GetRuntimeConfig(name string) (engine.RuntimeConfig, error) { cfg := *c var runtimes map[string]any - if _, ok := cfg["runtimes"]; ok { + if cfg["runtimes"] != nil { runtimes = cfg["runtimes"].(map[string]any) if r, ok := runtimes[name]; ok { dr := dockerRuntime(r.(map[string]any)) diff --git a/pkg/config/engine/docker/docker_test.go b/pkg/config/engine/docker/docker_test.go index b5ea75c03..ce9dc1497 100644 --- a/pkg/config/engine/docker/docker_test.go +++ b/pkg/config/engine/docker/docker_test.go @@ -250,6 +250,39 @@ func TestGetRuntimeConfig(t *testing.T) { } } +func TestNullRuntimesFromFile(t *testing.T) { + for _, action := range []string{"add", "remove", "get"} { + t.Run(action, func(t *testing.T) { + configPath := filepath.Join(t.TempDir(), "daemon.json") + require.NoError(t, os.WriteFile(configPath, []byte(`{"runtimes":null,"log-driver":"json-file"}`), 0600)) + config, err := New(WithPath(configPath)) + require.NoError(t, err) + + switch action { + case "add": + require.NoError(t, config.AddRuntime("nvidia", "/usr/bin/nvidia-container-runtime", false)) + runtime, err := config.GetRuntimeConfig("nvidia") + require.NoError(t, err) + require.Equal(t, "/usr/bin/nvidia-container-runtime", runtime.GetBinaryPath()) + case "remove": + require.NoError(t, config.RemoveRuntime("nvidia")) + case "get": + runtime, err := config.GetRuntimeConfig("nvidia") + require.NoError(t, err) + require.Empty(t, runtime.GetBinaryPath()) + } + + _, err = config.Save(configPath) + require.NoError(t, err) + contents, err := os.ReadFile(configPath) + require.NoError(t, err) + var saved map[string]any + require.NoError(t, json.Unmarshal(contents, &saved)) + require.Equal(t, "json-file", saved["log-driver"]) + }) + } +} + func TestEnableCDIPreservesFeaturesFromFile(t *testing.T) { tests := []struct { name string