From 020f0d2861ef8415093278b7d32af410114607dd Mon Sep 17 00:00:00 2001 From: Drew Inglis Date: Mon, 5 Oct 2026 11:05:17 +0000 Subject: [PATCH] fix: extract copied directories at their destination in Kubernetes pods (#1286) The Kubernetes backend extracted CopyDir archives at "/" with entries like "var/run/act/actions//...". Ubuntu's patched tar refuses to extract through an absolute symlink, failing with "Invalid cross-device link" on images that link /var/run to /run, so actions never reached the job container. Extract at the destination with relative entries instead, like Copy already does. This is a similar issue to #1128, but for k8s instead of Docker. I built the image and deployed it to my k8s cluster to verify the fix. --------- Co-authored-by: bircni Co-authored-by: silverwind Reviewed-on: https://gitea.com/gitea/runner/pulls/1286 Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com> Co-authored-by: Drew Inglis --- Makefile | 2 +- act/container/kubernetes.go | 4 ++-- act/container/kubernetes_test.go | 10 ++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index be872504..08e972d2 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ XGO_VERSION := go-1.27.x GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.17 # renovate: datasource=go PODMAN_TEST_IMAGE ?= quay.io/containers/podman:v5.8.4-immutable@sha256:90405e3c6a86f33c5a6f8dbdfa8e02a98143a8ba4337b84bdaec5336d2ef008a # renovate: datasource=docker -E2E_JOB_IMAGE ?= node:24-bookworm@sha256:64af3819f9275802414d7cdc38c27e9d82bd564dec4d4da87d008255d36c63b4 # renovate: datasource=docker +E2E_JOB_IMAGE ?= docker.gitea.com/runner-images:ubuntu-latest@sha256:0e62e56b382ebf485bff1e51a05cbe27c708545a2e91425467fd31eb3e249521 # renovate: datasource=docker SERVICE_IMAGE ?= nginx:1.31.4-alpine@sha256:db35bfc6b2951e7f8a72db5db120288c127ffaeeb4a6d4b95a26fead017d5913 # renovate: datasource=docker E2E_GITEA_IMAGE ?= gitea/gitea:main-nightly E2E_K3S_IMAGE ?= rancher/k3s:v1.36.4-k3s1@sha256:edad48e12bf81c3a09ac1c05c0c0ffaaa22145980b989d6fae84543a76b83657 # renovate: datasource=docker diff --git a/act/container/kubernetes.go b/act/container/kubernetes.go index 247732a9..0e4bd545 100644 --- a/act/container/kubernetes.go +++ b/act/container/kubernetes.go @@ -433,8 +433,8 @@ func (c *kubernetesContainer) Copy(destPath string, files ...*FileEntry) common. func (c *kubernetesContainer) CopyDir(destPath, srcPath string, useGitIgnore, skipGitDir bool) common.Executor { return func(ctx context.Context) error { - return c.extract(ctx, "/", func(writer io.Writer) error { - return writeDirTar(ctx, writer, destPath, srcPath, useGitIgnore, skipGitDir, 0, 0) + return c.extract(ctx, destPath, func(writer io.Writer) error { + return writeDirTar(ctx, writer, "/", srcPath, useGitIgnore, skipGitDir, 0, 0) }) } } diff --git a/act/container/kubernetes_test.go b/act/container/kubernetes_test.go index 5ff668f3..36ada2e6 100644 --- a/act/container/kubernetes_test.go +++ b/act/container/kubernetes_test.go @@ -12,6 +12,7 @@ import ( "io" "net/http" "net/http/httptest" + "net/url" "os" "os/exec" "path/filepath" @@ -230,6 +231,15 @@ func TestKubernetesPodRunsJobThroughAPI(t *testing.T) { _, err = job.GetContainerArchive(ctx, workdir+"/missing") require.Error(t, err) + actionDir := filepath.Join(t.TempDir(), "action") + require.NoError(t, os.MkdirAll(actionDir, 0o755)) + require.NoError(t, os.WriteFile(filepath.Join(actionDir, "index.js"), []byte("main()"), 0o644)) + require.NoError(t, job.CopyDir(workdir+"/act/actions/sha/", actionDir+"/", false, false)(ctx)) + script, err := os.ReadFile(workdir + "/act/actions/sha/index.js") + require.NoError(t, err) + assert.Equal(t, "main()", string(script)) + assert.Contains(t, cluster.requests["exec"][len(cluster.requests["exec"])-1], "command="+url.QueryEscape(workdir+"/act/actions/sha/")) + pathEnv := map[string]string{} require.NoError(t, job.UpdateFromImageEnv(&pathEnv)(ctx)) assert.Equal(t, os.Getenv("PATH"), pathEnv["PATH"])