mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-08-06 00:44:22 +02:00
fix: strip leading slash from mkdir tarball in CopyTarStream (#1129)
`CopyTarStream` creates the destination directory by extracting a one-entry tarball with `DestinationPath: "/"`, but named that entry with the absolute `destPath`. Docker Engine 29.5+ tightened path validation on the copy API and rejects absolute entry names against a `/` destination with `statat var/run/act/actions/<sha>: path escapes from parent`, so the action directory never reached the job container and `actions/checkout` failed during "Set up job". Stripping the leading slash makes the entry relative, matching what the sibling `copyDir` already does and the upstream fix in nektos/act v0.2.89. Adds a regression test asserting the mkdir tarball entry is relative. Fixes #1128 Reviewed-on: https://gitea.com/gitea/runner/pulls/1129 Reviewed-by: Zettat123 <39446+zettat123@noreply.gitea.com>
This commit is contained in:
@@ -868,11 +868,12 @@ func (cr *containerReference) CopyTarStream(ctx context.Context, destPath string
|
|||||||
if cr.id == "" {
|
if cr.id == "" {
|
||||||
return cr.missingContainerError("copy to %s", destPath)
|
return cr.missingContainerError("copy to %s", destPath)
|
||||||
}
|
}
|
||||||
// Mkdir
|
// Mkdir, with a path relative to the DestinationPath ("/") below. Docker 29.5+
|
||||||
|
// rejects absolute tar entry names with "path escapes from parent".
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
tw := tar.NewWriter(buf)
|
tw := tar.NewWriter(buf)
|
||||||
_ = tw.WriteHeader(&tar.Header{
|
_ = tw.WriteHeader(&tar.Header{
|
||||||
Name: destPath,
|
Name: strings.TrimPrefix(destPath, "/"),
|
||||||
Mode: 0o777,
|
Mode: 0o777,
|
||||||
Typeflag: tar.TypeDir,
|
Typeflag: tar.TypeDir,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/tar"
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
@@ -358,6 +359,44 @@ func TestDockerCopyTarStream(t *testing.T) {
|
|||||||
client.AssertExpectations(t)
|
client.AssertExpectations(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Docker 29.5+ rejects absolute names in the mkdir tarball with
|
||||||
|
// "path escapes from parent", since it is extracted relative to "/".
|
||||||
|
func TestDockerCopyTarStreamMkdirEntryIsRelative(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
var mkdirNames []string
|
||||||
|
client := &mockDockerClient{}
|
||||||
|
client.On("CopyToContainer", ctx, "123", mock.MatchedBy(func(opts mobyclient.CopyToContainerOptions) bool {
|
||||||
|
if opts.DestinationPath != "/" || opts.Content == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
tr := tar.NewReader(opts.Content)
|
||||||
|
for {
|
||||||
|
hdr, err := tr.Next()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mkdirNames = append(mkdirNames, hdr.Name)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})).Return(mobyclient.CopyToContainerResult{}, nil)
|
||||||
|
client.On("CopyToContainer", ctx, "123", mock.MatchedBy(func(opts mobyclient.CopyToContainerOptions) bool {
|
||||||
|
return opts.DestinationPath == "/var/run/act" && opts.Content != nil
|
||||||
|
})).Return(mobyclient.CopyToContainerResult{}, nil)
|
||||||
|
cr := &containerReference{
|
||||||
|
id: "123",
|
||||||
|
cli: client,
|
||||||
|
input: &NewContainerInput{
|
||||||
|
Image: "image",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, cr.CopyTarStream(ctx, "/var/run/act", &bytes.Buffer{}))
|
||||||
|
assert.Equal(t, []string{"var/run/act"}, mkdirNames)
|
||||||
|
|
||||||
|
client.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
func TestDockerCopyTarStreamErrorInCopyFiles(t *testing.T) {
|
func TestDockerCopyTarStreamErrorInCopyFiles(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user