From f2b4dbf05f80228608cc95a8dab3906f913c976c Mon Sep 17 00:00:00 2001 From: Mirko Sekulic Date: Mon, 27 Apr 2026 15:26:31 +0000 Subject: [PATCH] run docker step in host mode (#857) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem In host executor mode, uses: docker:// step actions fail because act/runner/step_docker.go always attaches the step container to the job container's network namespace, which doesn't exist in host mode. ### Example Run following job in host runner ```yaml jobs: test: runs-on: ubuntu-latest-host steps: - uses: docker://alpine:3.20 with: args: echo hello ``` ``` Error: failed to start container: Error response from daemon: joining network namespace of container: No such container: xxxxxx ``` This pr allows the docker step in the host mode ## Testing I tested following steps on host runner and it worked ```yaml - name: Test azure cli action in host mode uses: azure/cli@v2 env: RUNNER_OS: Linux with: inlineScript: echo "hello from azure cli"   - uses: docker://alpine:3.20 with: args: echo hello ``` --------- Co-authored-by: Nicolas Reviewed-on: https://gitea.com/gitea/act_runner/pulls/857 Reviewed-by: Nicolas Co-authored-by: Mirko Sekulic Co-committed-by: Mirko Sekulic --- act/runner/step_docker.go | 6 ++- act/runner/step_docker_test.go | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/act/runner/step_docker.go b/act/runner/step_docker.go index 2f18fff0..97fc93ec 100644 --- a/act/runner/step_docker.go +++ b/act/runner/step_docker.go @@ -116,6 +116,10 @@ func (sd *stepDocker) newStepContainer(ctx context.Context, image string, cmd, e envList = append(envList, fmt.Sprintf("%s=%s", "RUNNER_TEMP", "/tmp")) binds, mounts := rc.GetBindsAndMounts() + networkMode := "container:" + rc.jobContainerName() + if rc.IsHostEnv(ctx) { + networkMode = "default" + } stepContainer := ContainerNewContainer(&container.NewContainerInput{ Cmd: cmd, Entrypoint: entrypoint, @@ -126,7 +130,7 @@ func (sd *stepDocker) newStepContainer(ctx context.Context, image string, cmd, e Name: createSimpleContainerName(rc.jobContainerName(), "STEP-"+step.ID), Env: envList, Mounts: mounts, - NetworkMode: "container:" + rc.jobContainerName(), + NetworkMode: networkMode, Binds: binds, Stdout: logWriter, Stderr: logWriter, diff --git a/act/runner/step_docker_test.go b/act/runner/step_docker_test.go index e1bf8998..59f8bad8 100644 --- a/act/runner/step_docker_test.go +++ b/act/runner/step_docker_test.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "io" + "strings" "testing" "gitea.com/gitea/act_runner/act/container" @@ -118,3 +119,81 @@ func TestStepDockerPrePost(t *testing.T) { err = sd.post()(ctx) assert.Nil(t, err) //nolint:testifylint // pre-existing issue from nektos/act } + +func TestStepDockerNewStepContainerNetworkMode(t *testing.T) { + cases := []struct { + name string + platform string + expectDefault bool + }{ + { + name: "docker mode attaches to job container network", + platform: "node:14", + expectDefault: false, + }, + { + name: "host mode uses default network", + platform: "-self-hosted", + expectDefault: true, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + cm := &containerMock{} + + var captured *container.NewContainerInput + origContainerNewContainer := ContainerNewContainer + ContainerNewContainer = func(input *container.NewContainerInput) container.ExecutionsEnvironment { + captured = input + return cm + } + defer func() { + ContainerNewContainer = origContainerNewContainer + }() + + ctx := context.Background() + + platform := tc.platform + sd := &stepDocker{ + RunContext: &RunContext{ + StepResults: map[string]*model.StepResult{}, + Config: &Config{ + PlatformPicker: func(_ []string) string { + return platform + }, + }, + Run: &model.Run{ + JobID: "1", + Workflow: &model.Workflow{ + Jobs: map[string]*model.Job{ + "1": {}, + }, + }, + }, + JobContainer: cm, + }, + Step: &model.Step{ + ID: "1", + Uses: "docker://alpine:3.20", + }, + } + sd.RunContext.ExprEval = sd.RunContext.NewExpressionEvaluator(ctx) + + assert.Equal(t, tc.expectDefault, sd.RunContext.IsHostEnv(ctx), + "IsHostEnv mismatch for platform %q", tc.platform) + + _ = sd.newStepContainer(ctx, "alpine:3.20", []string{"echo", "hello"}, nil) + + if tc.expectDefault { + assert.Equal(t, "default", captured.NetworkMode, + "host-mode step container must use 'default' network, got %q", + captured.NetworkMode) + } else { + assert.True(t, strings.HasPrefix(captured.NetworkMode, "container:"), + "docker-mode step container must attach to job container network, got %q", + captured.NetworkMode) + } + }) + } +}