From cd84277d7bbb812082adf4f6b7379107bf89b029 Mon Sep 17 00:00:00 2001 From: Areeb Ahmed Date: Sun, 31 May 2026 21:34:30 +0300 Subject: [PATCH 1/5] add helper + tests for SyncDockerConfigToContainer Signed-off-by: Areeb Ahmed --- cmd/cli/commands/compose.go | 1 + cmd/cli/commands/pull.go | 1 + cmd/cli/commands/push.go | 1 + cmd/cli/commands/utils.go | 28 +++++++++++++ cmd/cli/pkg/standalone/containers.go | 9 ++--- cmd/cli/pkg/standalone/containers_test.go | 48 +++++++++++++++++++++++ 6 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 cmd/cli/pkg/standalone/containers_test.go diff --git a/cmd/cli/commands/compose.go b/cmd/cli/commands/compose.go index 7d10a6d27..552eb9ee1 100644 --- a/cmd/cli/commands/compose.go +++ b/cmd/cli/commands/compose.go @@ -63,6 +63,7 @@ func newUpCommand() *cobra.Command { return errors.New("unable to determine standalone runner endpoint") } + syncDockerConfigForRegistry(cmd.Context(), asPrinter(cmd)) if err := downloadModelsOnlyIfNotFound(desktopClient, models); err != nil { return err } diff --git a/cmd/cli/commands/pull.go b/cmd/cli/commands/pull.go index 6de1676ff..1a163fe69 100644 --- a/cmd/cli/commands/pull.go +++ b/cmd/cli/commands/pull.go @@ -22,6 +22,7 @@ func newPullCmd() *cobra.Command { func pullModel(cmd *cobra.Command, desktopClient *desktop.Client, model string) error { printer := asPrinter(cmd) + syncDockerConfigForRegistry(cmd.Context(), printer) response, _, err := desktopClient.Pull(model, printer) if err != nil { diff --git a/cmd/cli/commands/push.go b/cmd/cli/commands/push.go index ef9c0b91f..f13b2adea 100644 --- a/cmd/cli/commands/push.go +++ b/cmd/cli/commands/push.go @@ -21,6 +21,7 @@ func newPushCmd() *cobra.Command { func pushModel(cmd *cobra.Command, desktopClient *desktop.Client, model string) error { printer := asPrinter(cmd) + syncDockerConfigForRegistry(cmd.Context(), printer) response, _, err := desktopClient.Push(model, printer) if err != nil { diff --git a/cmd/cli/commands/utils.go b/cmd/cli/commands/utils.go index fbe1a932e..db1441ba2 100644 --- a/cmd/cli/commands/utils.go +++ b/cmd/cli/commands/utils.go @@ -2,6 +2,7 @@ package commands import ( "bytes" + "context" "errors" "fmt" "io" @@ -10,6 +11,7 @@ import ( "github.com/docker/model-runner/cmd/cli/desktop" "github.com/docker/model-runner/cmd/cli/pkg/standalone" + "github.com/docker/model-runner/cmd/cli/pkg/types" "github.com/docker/model-runner/pkg/distribution/distribution" "github.com/docker/model-runner/pkg/distribution/oci/reference" "github.com/docker/model-runner/pkg/inference/backends/vllm" @@ -247,6 +249,32 @@ func addRunnerFlags(cmd *cobra.Command, opts runnerFlagOptions) { } } +// syncDockerConfigForRegistry copies the host's Docker config into the running +// container. Only applicable for Moby engine setups; a no-op otherwise. +func syncDockerConfigForRegistry(ctx context.Context, printer standalone.StatusPrinter) { + if modelRunner == nil { + return + } + engineKind := modelRunner.EngineKind() + if engineKind != types.ModelRunnerEngineKindMoby { + return + } + dockerClient, err := desktop.DockerClientForContext(dockerCLI, dockerCLI.CurrentContext()) + if err != nil { + return // non-fatal: proceed with potentially stale credentials + } + defer dockerClient.Close() + + containerID, _, _, err := standalone.FindControllerContainer(ctx, dockerClient) + if err != nil || containerID == "" { + return // non-fatal: container may not be running yet + } + + if err := standalone.SyncDockerConfigToContainer(ctx, dockerClient, containerID, engineKind); err != nil { + printer.Printf("Warning: failed to sync Docker credentials to runner: %v\n", err) + } +} + // newTable creates a new table with Docker CLI-style formatting: // no borders, no column separators, no header line, left-aligned, and 2-space padding. func newTable(w io.Writer) *tablewriter.Table { diff --git a/cmd/cli/pkg/standalone/containers.go b/cmd/cli/pkg/standalone/containers.go index cc6df5eb0..f1c9dd23b 100644 --- a/cmd/cli/pkg/standalone/containers.go +++ b/cmd/cli/pkg/standalone/containers.go @@ -28,10 +28,9 @@ import ( // controllerContainerName is the name to use for the controller container. const controllerContainerName = "docker-model-runner" -// copyDockerConfigToContainer copies the Docker config file from the host to the container -// and sets up proper ownership and permissions for the modelrunner user. -// It does nothing for Desktop and Cloud engine kinds. -func copyDockerConfigToContainer(ctx context.Context, dockerClient *client.Client, containerID string, engineKind types.ModelRunnerEngineKind) error { +// SyncDockerConfigToContainer copies the host's ~/.docker/config.json into the +// running container. It is a no-op for Desktop and Cloud engine kinds. +func SyncDockerConfigToContainer(ctx context.Context, dockerClient *client.Client, containerID string, engineKind types.ModelRunnerEngineKind) error { // Do nothing for Desktop and Cloud engine kinds if engineKind == types.ModelRunnerEngineKindDesktop || engineKind == types.ModelRunnerEngineKindCloud || os.Getenv("_MODEL_RUNNER_TREAT_DESKTOP_AS_MOBY") == "1" { @@ -622,7 +621,7 @@ func CreateControllerContainer(ctx context.Context, dockerClient *client.Client, // Copy Docker config file if it exists and we're the container creator. if created && !vllmOnWSL { - if err := copyDockerConfigToContainer(ctx, dockerClient, resp.ID, engineKind); err != nil { + if err := SyncDockerConfigToContainer(ctx, dockerClient, resp.ID, engineKind); err != nil { // Log warning but continue - don't fail container creation printer.Printf("Warning: failed to copy Docker config: %v\n", err) } diff --git a/cmd/cli/pkg/standalone/containers_test.go b/cmd/cli/pkg/standalone/containers_test.go new file mode 100644 index 000000000..67821a41f --- /dev/null +++ b/cmd/cli/pkg/standalone/containers_test.go @@ -0,0 +1,48 @@ +package standalone + +import ( + "context" + "os" + "path/filepath" + "testing" + + "github.com/docker/model-runner/cmd/cli/pkg/types" +) + +// TestSyncDockerConfigToContainer_NoopForDesktopAndCloud verifies that +// SyncDockerConfigToContainer skips Desktop and Cloud engine kinds. +func TestSyncDockerConfigToContainer_NoopForDesktopAndCloud(t *testing.T) { + tmpDir := t.TempDir() + dockerDir := filepath.Join(tmpDir, ".docker") + if err := os.MkdirAll(dockerDir, 0o700); err != nil { + t.Fatalf("failed to create .docker dir: %v", err) + } + if err := os.WriteFile(filepath.Join(dockerDir, "config.json"), []byte(`{}`), 0o600); err != nil { + t.Fatalf("failed to write config.json: %v", err) + } + t.Setenv("HOME", tmpDir) + + for _, engineKind := range []types.ModelRunnerEngineKind{ + types.ModelRunnerEngineKindDesktop, + types.ModelRunnerEngineKindCloud, + } { + t.Run(engineKind.String(), func(t *testing.T) { + err := SyncDockerConfigToContainer(context.Background(), nil, "container-id", engineKind) + if err != nil { + t.Fatalf("SyncDockerConfigToContainer(%v) returned unexpected error: %v", engineKind, err) + } + }) + } +} + +// TestSyncDockerConfigToContainer_NoopWhenConfigMissing verifies that +// SyncDockerConfigToContainer skips when the host config file is absent. +func TestSyncDockerConfigToContainer_NoopWhenConfigMissing(t *testing.T) { + tmpDir := t.TempDir() + t.Setenv("HOME", tmpDir) + + err := SyncDockerConfigToContainer(context.Background(), nil, "container-id", types.ModelRunnerEngineKindMoby) + if err != nil { + t.Fatalf("SyncDockerConfigToContainer returned unexpected error for missing config: %v", err) + } +} From fa1478926d0d6217edb8fc3aa856a220e0e14ee5 Mon Sep 17 00:00:00 2001 From: Areeb Ahmed Date: Mon, 1 Jun 2026 00:59:55 +0300 Subject: [PATCH 2/5] fix config path Signed-off-by: Areeb Ahmed --- cmd/cli/pkg/standalone/containers.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/cli/pkg/standalone/containers.go b/cmd/cli/pkg/standalone/containers.go index f1c9dd23b..6890e1b6a 100644 --- a/cmd/cli/pkg/standalone/containers.go +++ b/cmd/cli/pkg/standalone/containers.go @@ -17,6 +17,7 @@ import ( "time" "github.com/containerd/errdefs" + dockercliconfig "github.com/docker/cli/cli/config" gpupkg "github.com/docker/model-runner/cmd/cli/pkg/gpu" "github.com/docker/model-runner/cmd/cli/pkg/types" "github.com/moby/moby/api/types/container" @@ -37,7 +38,7 @@ func SyncDockerConfigToContainer(ctx context.Context, dockerClient *client.Clien return nil } - dockerConfigPath := os.ExpandEnv("$HOME/.docker/config.json") + dockerConfigPath := filepath.Join(dockercliconfig.Dir(), "config.json") if s, err := os.Stat(dockerConfigPath); err != nil || s.Mode()&os.ModeType != 0 { return nil } From bcc0422d3bb2539b38e7eec64fb29510ed811187 Mon Sep 17 00:00:00 2001 From: Areeb Ahmed Date: Mon, 1 Jun 2026 13:59:02 +0300 Subject: [PATCH 3/5] add log Signed-off-by: Areeb Ahmed --- cmd/cli/commands/utils.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd/cli/commands/utils.go b/cmd/cli/commands/utils.go index db1441ba2..39bdf0d4e 100644 --- a/cmd/cli/commands/utils.go +++ b/cmd/cli/commands/utils.go @@ -261,13 +261,18 @@ func syncDockerConfigForRegistry(ctx context.Context, printer standalone.StatusP } dockerClient, err := desktop.DockerClientForContext(dockerCLI, dockerCLI.CurrentContext()) if err != nil { - return // non-fatal: proceed with potentially stale credentials + printer.Printf("Warning: failed to create Docker client for credential sync: %v\n", err) + return } defer dockerClient.Close() containerID, _, _, err := standalone.FindControllerContainer(ctx, dockerClient) - if err != nil || containerID == "" { - return // non-fatal: container may not be running yet + if err != nil { + printer.Printf("Warning: failed to find model runner container for credential sync: %v\n", err) + return + } + if containerID == "" { + return } if err := standalone.SyncDockerConfigToContainer(ctx, dockerClient, containerID, engineKind); err != nil { From e65118c2b7ed6464f8fbbe7a999626ec9ebc496f Mon Sep 17 00:00:00 2001 From: Areeb Ahmed Date: Mon, 1 Jun 2026 22:47:12 +0300 Subject: [PATCH 4/5] possible fix ci run Signed-off-by: Areeb Ahmed --- cmd/cli/pkg/standalone/containers_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/cli/pkg/standalone/containers_test.go b/cmd/cli/pkg/standalone/containers_test.go index 67821a41f..51ab047ea 100644 --- a/cmd/cli/pkg/standalone/containers_test.go +++ b/cmd/cli/pkg/standalone/containers_test.go @@ -1,7 +1,6 @@ package standalone import ( - "context" "os" "path/filepath" "testing" @@ -27,7 +26,7 @@ func TestSyncDockerConfigToContainer_NoopForDesktopAndCloud(t *testing.T) { types.ModelRunnerEngineKindCloud, } { t.Run(engineKind.String(), func(t *testing.T) { - err := SyncDockerConfigToContainer(context.Background(), nil, "container-id", engineKind) + err := SyncDockerConfigToContainer(t.Context(), nil, "container-id", engineKind) if err != nil { t.Fatalf("SyncDockerConfigToContainer(%v) returned unexpected error: %v", engineKind, err) } @@ -41,7 +40,7 @@ func TestSyncDockerConfigToContainer_NoopWhenConfigMissing(t *testing.T) { tmpDir := t.TempDir() t.Setenv("HOME", tmpDir) - err := SyncDockerConfigToContainer(context.Background(), nil, "container-id", types.ModelRunnerEngineKindMoby) + err := SyncDockerConfigToContainer(t.Context(), nil, "container-id", types.ModelRunnerEngineKindMoby) if err != nil { t.Fatalf("SyncDockerConfigToContainer returned unexpected error for missing config: %v", err) } From cf01a3c6265997efe0a507b787b0ee611a94e0bf Mon Sep 17 00:00:00 2001 From: Areeb Ahmed Date: Tue, 2 Jun 2026 14:46:12 +0300 Subject: [PATCH 5/5] switch for inline approach Signed-off-by: Areeb Ahmed --- cmd/cli/pkg/standalone/containers.go | 11 +++++++++-- cmd/cli/pkg/standalone/containers_test.go | 15 +-------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/cmd/cli/pkg/standalone/containers.go b/cmd/cli/pkg/standalone/containers.go index 6890e1b6a..e0ff912f9 100644 --- a/cmd/cli/pkg/standalone/containers.go +++ b/cmd/cli/pkg/standalone/containers.go @@ -17,7 +17,6 @@ import ( "time" "github.com/containerd/errdefs" - dockercliconfig "github.com/docker/cli/cli/config" gpupkg "github.com/docker/model-runner/cmd/cli/pkg/gpu" "github.com/docker/model-runner/cmd/cli/pkg/types" "github.com/moby/moby/api/types/container" @@ -38,7 +37,15 @@ func SyncDockerConfigToContainer(ctx context.Context, dockerClient *client.Clien return nil } - dockerConfigPath := filepath.Join(dockercliconfig.Dir(), "config.json") + dockerConfigDir := os.Getenv("DOCKER_CONFIG") + if dockerConfigDir == "" { + homeDir, err := os.UserHomeDir() + if err != nil { + return fmt.Errorf("failed to get home directory: %w", err) + } + dockerConfigDir = filepath.Join(homeDir, ".docker") + } + dockerConfigPath := filepath.Join(dockerConfigDir, "config.json") if s, err := os.Stat(dockerConfigPath); err != nil || s.Mode()&os.ModeType != 0 { return nil } diff --git a/cmd/cli/pkg/standalone/containers_test.go b/cmd/cli/pkg/standalone/containers_test.go index 51ab047ea..31df15e87 100644 --- a/cmd/cli/pkg/standalone/containers_test.go +++ b/cmd/cli/pkg/standalone/containers_test.go @@ -1,8 +1,6 @@ package standalone import ( - "os" - "path/filepath" "testing" "github.com/docker/model-runner/cmd/cli/pkg/types" @@ -11,16 +9,6 @@ import ( // TestSyncDockerConfigToContainer_NoopForDesktopAndCloud verifies that // SyncDockerConfigToContainer skips Desktop and Cloud engine kinds. func TestSyncDockerConfigToContainer_NoopForDesktopAndCloud(t *testing.T) { - tmpDir := t.TempDir() - dockerDir := filepath.Join(tmpDir, ".docker") - if err := os.MkdirAll(dockerDir, 0o700); err != nil { - t.Fatalf("failed to create .docker dir: %v", err) - } - if err := os.WriteFile(filepath.Join(dockerDir, "config.json"), []byte(`{}`), 0o600); err != nil { - t.Fatalf("failed to write config.json: %v", err) - } - t.Setenv("HOME", tmpDir) - for _, engineKind := range []types.ModelRunnerEngineKind{ types.ModelRunnerEngineKindDesktop, types.ModelRunnerEngineKindCloud, @@ -37,8 +25,7 @@ func TestSyncDockerConfigToContainer_NoopForDesktopAndCloud(t *testing.T) { // TestSyncDockerConfigToContainer_NoopWhenConfigMissing verifies that // SyncDockerConfigToContainer skips when the host config file is absent. func TestSyncDockerConfigToContainer_NoopWhenConfigMissing(t *testing.T) { - tmpDir := t.TempDir() - t.Setenv("HOME", tmpDir) + t.Setenv("DOCKER_CONFIG", t.TempDir()) err := SyncDockerConfigToContainer(t.Context(), nil, "container-id", types.ModelRunnerEngineKindMoby) if err != nil {