Skip to content

Commit

Permalink
dockerfile: add support for non-octal COPY --chmod in labs
Browse files Browse the repository at this point in the history
Signed-off-by: Tonis Tiigi <[email protected]>
  • Loading branch information
tonistiigi committed Oct 3, 2024
1 parent c7db68a commit e42889d
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 5 deletions.
17 changes: 13 additions & 4 deletions frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -1363,12 +1363,21 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error {

var mode *llb.ChmodOpt
if cfg.chmod != "" {
mode = &llb.ChmodOpt{}
p, err := strconv.ParseUint(cfg.chmod, 8, 32)
if err != nil || p > 0o7777 {
return errors.Errorf("invalid chmod parameter: '%v'. it should be octal string and between 0 and 07777", cfg.chmod)
nonOctalErr := errors.Errorf("invalid chmod parameter: '%v'. it should be octal string and between 0 and 07777", cfg.chmod)
if err == nil {
if p > 0o7777 {
return nonOctalErr
}
mode.Mode = os.FileMode(p)
} else {
if featureCopyChmodNonOctalEnabled {
mode.ModeStr = cfg.chmod
} else {
return nonOctalErr
}
}
perm := os.FileMode(p)
mode = &llb.ChmodOpt{Mode: perm}
}

if cfg.checksum != "" {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build !dfcopychmodnonoctal
// +build !dfcopychmodnonoctal

package dockerfile2llb

var featureCopyChmodNonOctalEnabled = false
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build dfcopychmodnonoctal
// +build dfcopychmodnonoctal

package dockerfile2llb

var featureCopyChmodNonOctalEnabled = true
121 changes: 121 additions & 0 deletions frontend/dockerfile/dockerfile_chmod_non_octal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//go:build dfcopychmodnonoctal
// +build dfcopychmodnonoctal

package dockerfile

import (
"fmt"
"testing"

"github.com/containerd/continuity/fs/fstest"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/frontend/dockerui"
"github.com/moby/buildkit/util/testutil/integration"
"github.com/stretchr/testify/require"
"github.com/tonistiigi/fsutil"
)

func init() {
allTests = append(allTests, integration.TestFuncs(testChmodNonOctal)...)
}

func testChmodNonOctal(t *testing.T, sb integration.Sandbox) {
integration.SkipOnPlatform(t, "windows")
f := getFrontend(t, sb)

tcases := []struct {
src string
dst string
mode string
isDir bool
}{
{
src: "file",
dst: "f1",
mode: "go-w",
},
{
src: "file",
dst: "f2",
mode: "u=rw,g=r,o=r",
}, {
src: "file",
dst: "f3",
mode: "a+X",
},
{
src: "dir",
dst: "d1",
mode: "go-w",
isDir: true,
},
{
src: "dir",
dst: "d2",
mode: "u+rw,g+r,o-x,o+w",
isDir: true,
},
{
src: "dir",
dst: "d3",
mode: "a+X",
isDir: true,
},
}

expectedCommands := ""
copyCommands := ""
verifyCommands := ""

for _, tc := range tcases {
if tc.isDir {
// create nested input dir because COPY copies directory contents
expectedCommands += "RUN mkdir -p /input/dirs/" + tc.dst + " && cp -a /input/" + tc.src + " /input/dirs/" + tc.dst + "/" + tc.dst + "\n"
expectedCommands += "RUN cp -a /input/dirs/" + tc.dst + "/. /expected/ && chmod " + tc.mode + " /expected/" + tc.dst + "\n"
copyCommands += "COPY --from=base --chmod=" + tc.mode + " /input/dirs/" + tc.dst + " /\n"
} else {
expectedCommands += "RUN cp -a /input/" + tc.src + " /expected/" + tc.dst + " && chmod " + tc.mode + " /expected/" + tc.dst + "\n"
copyCommands += "COPY --from=base --chmod=" + tc.mode + " /input/" + tc.src + " /" + tc.dst + "\n"
}
verifyCommands += "RUN [ \"$(stat -c %A /actual/" + tc.dst + ")\" = \"$(stat -c %A /expected/" + tc.dst + ")\" ]\n"
}

dockerfile := []byte(fmt.Sprintf(`
FROM alpine as base
RUN <<eot
set -ex
mkdir /input
touch /input/file
chmod 666 /input/file
mkdir /input/dir
chmod 124 /input/dir
mkdir /expected
eot
%s
FROM scratch as result
%s
FROM base
COPY --from=result / /actual/
%s
`, expectedCommands, copyCommands, verifyCommands))

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

c, err := client.New(sb.Context(), sb.Address())
require.NoError(t, err)
defer c.Close()

_, err = f.Solve(sb.Context(), c, client.SolveOpt{
LocalMounts: map[string]fsutil.FS{
dockerui.DefaultLocalNameDockerfile: dir,
dockerui.DefaultLocalNameContext: dir,
},
}, nil)
require.NoError(t, err)
}
2 changes: 1 addition & 1 deletion frontend/dockerfile/release/labs/tags
Original file line number Diff line number Diff line change
@@ -1 +1 @@
dfrunsecurity dfparents dfexcludepatterns
dfrunsecurity dfparents dfexcludepatterns dfchmodnonoctal

0 comments on commit e42889d

Please sign in to comment.