Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions frontend/dockerfile/dockerfile_add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,159 @@ ADD %s /newname.tar.gz
require.Equal(t, buf2.Bytes(), dt)
}

// https://github.com/moby/moby/issues/53257
func testDockerfileAddArchiveWithImpliedParentDir(t *testing.T, sb integration.Sandbox) {
f := getFrontend(t, sb)
f.RequiresBuildctl(t)

buf := bytes.NewBuffer(nil)
tw := tar.NewWriter(buf)
err := tw.WriteHeader(&tar.Header{
Name: "etc/dnf/",
Typeflag: tar.TypeDir,
Mode: 0755,
})
require.NoError(t, err)
expectedContent := []byte("content0")
err = tw.WriteHeader(&tar.Header{
Name: "etc/dnf/dnf.conf",
Typeflag: tar.TypeReg,
Size: int64(len(expectedContent)),
Mode: 0644,
})
require.NoError(t, err)
_, err = tw.Write(expectedContent)
require.NoError(t, err)
err = tw.Close()
require.NoError(t, err)

gzBuf := bytes.NewBuffer(nil)
gz := gzip.NewWriter(gzBuf)
_, err = gz.Write(buf.Bytes())
require.NoError(t, err)
err = gz.Close()
require.NoError(t, err)

baseImage := integration.UnixOrWindows("scratch", "nanoserver")

dockerfile := fmt.Appendf(nil, `
FROM %s
ADD t.tar.gz /
`, baseImage)

dir := integration.Tmpdir(
t,
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("t.tar.gz", gzBuf.Bytes(), 0600),
)

args, trace := f.DFCmdArgs(dir.Name, dir.Name)
defer os.RemoveAll(trace)

destDir := t.TempDir()

cmd := sb.Cmd(args + fmt.Sprintf(" --output type=local,dest=%s", destDir))
require.NoError(t, cmd.Run())

dt, err := os.ReadFile(filepath.Join(destDir, "etc/dnf/dnf.conf"))
require.NoError(t, err)
require.Equal(t, expectedContent, dt)
}

// https://github.com/moby/moby/issues/53258
func testDockerfileAddArchiveThroughAbsoluteSymlink(t *testing.T, sb integration.Sandbox) {
integration.SkipOnPlatform(t, "windows", "absolute /run symlink traversal is a Unix-specific archive extraction case")
f := getFrontend(t, sb)
f.RequiresBuildctl(t)

writeDir := func(tw *tar.Writer, name string) {
err := tw.WriteHeader(&tar.Header{
Name: name,
Typeflag: tar.TypeDir,
Mode: 0755,
})
require.NoError(t, err)
}

rootfs := bytes.NewBuffer(nil)
tw := tar.NewWriter(rootfs)
writeDir(tw, "run/")
writeDir(tw, "var/")
err := tw.WriteHeader(&tar.Header{
Name: "var/run",
Typeflag: tar.TypeSymlink,
Linkname: "/run",
Mode: 0777,
})
require.NoError(t, err)
err = tw.Close()
require.NoError(t, err)

payload := bytes.NewBuffer(nil)
tw = tar.NewWriter(payload)
// Keep parent directories explicit so this isolates extraction through the
// absolute symlink from implied parent directory handling.
writeDir(tw, "var/run/act/")
writeDir(tw, "var/run/act/actions/")
writeDir(tw, "var/run/act/actions/broad/")
writeDir(tw, "var/run/act/actions/broad/.git/")
expectedContent := []byte("ref: refs/heads/main\n")
err = tw.WriteHeader(&tar.Header{
Name: "var/run/act/actions/broad/.git/HEAD",
Typeflag: tar.TypeReg,
Size: int64(len(expectedContent)),
Mode: 0644,
})
require.NoError(t, err)
_, err = tw.Write(expectedContent)
require.NoError(t, err)
err = tw.WriteHeader(&tar.Header{
Name: "var/run/act/actions/broad/.git/HEAD.link",
Typeflag: tar.TypeLink,
Linkname: "var/run/act/actions/broad/.git/HEAD",
Mode: 0644,
})
require.NoError(t, err)
err = tw.Close()
require.NoError(t, err)

dockerfile := []byte(`
FROM scratch
ADD rootfs.tar /
ADD payload.tar /
`)

dir := integration.Tmpdir(
t,
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("rootfs.tar", rootfs.Bytes(), 0600),
fstest.CreateFile("payload.tar", payload.Bytes(), 0600),
)

args, trace := f.DFCmdArgs(dir.Name, dir.Name)
defer os.RemoveAll(trace)

destDir := t.TempDir()

cmd := sb.Cmd(args + fmt.Sprintf(" --output type=local,dest=%s", destDir))
require.NoError(t, cmd.Run())

dt, err := os.ReadFile(filepath.Join(destDir, "run/act/actions/broad/.git/HEAD"))
require.NoError(t, err)
require.Equal(t, expectedContent, dt)

linkPath := filepath.Join(destDir, "run/act/actions/broad/.git/HEAD.link")
dt, err = os.ReadFile(linkPath)
require.NoError(t, err)
require.Equal(t, expectedContent, dt)

fileInfo, err := os.Stat(filepath.Join(destDir, "run/act/actions/broad/.git/HEAD"))
require.NoError(t, err)
linkInfo, err := os.Stat(linkPath)
require.NoError(t, err)
require.True(t, os.SameFile(fileInfo, linkInfo))
}

func testDockerfileAddChownArchive(t *testing.T, sb integration.Sandbox) {
integration.SkipOnPlatform(t, "windows", "ADD --chown tests Unix UID/GID ownership which is not applicable to Windows file permissions")
f := getFrontend(t, sb)
Expand Down
2 changes: 2 additions & 0 deletions frontend/dockerfile/dockerfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ var allTests = integration.TestFuncs(
// dockerfile_add_test.go
testDockerfileADDFromURL,
testDockerfileAddArchive,
testDockerfileAddArchiveWithImpliedParentDir,
testDockerfileAddArchiveThroughAbsoluteSymlink,
testDockerfileAddChownArchive,
testDockerfileAddArchiveWildcard,
testDockerfileAddChownExpand,
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ require (
github.com/in-toto/in-toto-golang v0.11.0
github.com/klauspost/compress v1.19.1
github.com/moby/docker-image-spec v1.3.1
github.com/moby/go-archive v0.2.1
github.com/moby/go-archive v0.2.0
github.com/moby/locker v1.0.1
github.com/moby/patternmatcher v0.6.1
github.com/moby/policy-helpers v0.0.0-20260722051018-856be88baec4
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.2.1 h1:fAa0wUS/ikZKyx7o/1fhUYmhZ7RgpthdeoDhJvunTLc=
github.com/moby/go-archive v0.2.1/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE=
github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
Expand Down
12 changes: 0 additions & 12 deletions vendor/github.com/moby/go-archive/.golangci.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading