Skip to content

Commit 81c4790

Browse files
aledbfclaude
andcommitted
fix(docker): stop panicking when the docker context can't be read
FindDockerDriverBuilder read the stdout of `docker context inspect` without checking its error, and Run returns a nil result when the command does not start or the context is cancelled, so a Feature build on a docker-container builder could end in a nil pointer panic. A context that can't be read now counts as no current context, and the first docker-driver builder is still chosen, as when `buildx ls` names no builder for the current context. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent bf6c7d9 commit 81c4790

3 files changed

Lines changed: 18 additions & 3 deletions

File tree

‎internal/docker/argbuilders_test.go‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type cannedResponse struct {
2323
stdout []byte
2424
stderr []byte
2525
code int
26+
err error
2627
}
2728

2829
func (r *recordingRunner) Run(_ context.Context, stream io.Writer, name string, args ...string) ([]byte, []byte, int, error) {
@@ -34,7 +35,7 @@ func (r *recordingRunner) Run(_ context.Context, stream io.Writer, name string,
3435
_, _ = stream.Write(resp.stdout)
3536
_, _ = stream.Write(resp.stderr)
3637
}
37-
return resp.stdout, resp.stderr, resp.code, nil
38+
return resp.stdout, resp.stderr, resp.code, resp.err
3839
}
3940
return nil, nil, 0, nil
4041
}

‎internal/docker/builder_detect_held_test.go‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package docker
22

33
import (
4+
"errors"
45
"testing"
56

67
"github.com/devcontainers/cli/internal/log"
@@ -22,3 +23,14 @@ func TestBuilderDetectionIgnoresAFailedBuildx(t *testing.T) {
2223
t.Errorf("FindDockerDriverBuilder after a failed ls = %q, want empty", got)
2324
}
2425
}
26+
27+
func TestFindDockerDriverBuilderWhenTheContextCannotBeRead(t *testing.T) {
28+
rr := &recordingRunner{responses: []cannedResponse{
29+
{err: errors.New("exec docker: no such file")},
30+
{stdout: []byte("NAME DRIVER\nremote* docker-container running\ndefault docker running\n")},
31+
}}
32+
c := &Client{DockerPath: "docker", Log: log.Null, Runner: rr}
33+
if got := c.FindDockerDriverBuilder(t.Context()); got != "default" {
34+
t.Errorf("FindDockerDriverBuilder with no current context = %q, want the first docker-driver builder", got)
35+
}
36+
}

‎internal/docker/client.go‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,10 @@ func (c *Client) DetectActiveBuilder(ctx context.Context) *BuilderInfo {
218218
}
219219

220220
func (c *Client) FindDockerDriverBuilder(ctx context.Context) string {
221-
ctxRes, _ := c.Run(ctx, "context", "inspect", "--format", "{{.Name}}")
222-
currentContext := strings.TrimSpace(string(ctxRes.Stdout))
221+
currentContext := ""
222+
if ctxRes, err := c.Run(ctx, "context", "inspect", "--format", "{{.Name}}"); err == nil && ctxRes.ExitCode == 0 {
223+
currentContext = strings.TrimSpace(string(ctxRes.Stdout))
224+
}
223225

224226
res, err := c.Run(ctx, "buildx", "ls")
225227
if err != nil || res.ExitCode != 0 {

0 commit comments

Comments
 (0)