Skip to content
This repository was archived by the owner on Jun 3, 2025. It is now read-only.

Commit b205a1d

Browse files
committed
feat: Added --chmod for ADD and COPY command. Fixes #2850
1 parent 87e646a commit b205a1d

10 files changed

Lines changed: 227 additions & 95 deletions

File tree

cmd/executor/cmd/root.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package cmd
1818

1919
import (
2020
"fmt"
21+
"io/fs"
2122
"os"
2223
"os/exec"
2324
"path/filepath"
@@ -300,7 +301,7 @@ func checkKanikoDir(dir string) error {
300301
if dir != constants.DefaultKanikoPath {
301302

302303
// The destination directory may be across a different partition, so we cannot simply rename/move the directory in this case.
303-
if _, err := util.CopyDir(constants.DefaultKanikoPath, dir, util.FileContext{}, util.DoNotChangeUID, util.DoNotChangeGID); err != nil {
304+
if _, err := util.CopyDir(constants.DefaultKanikoPath, dir, util.FileContext{}, util.DoNotChangeUID, util.DoNotChangeGID, fs.FileMode(0o600), true); err != nil {
304305
return err
305306
}
306307

@@ -321,7 +322,6 @@ func checkContained() bool {
321322

322323
// checkNoDeprecatedFlags return an error if deprecated flags are used.
323324
func checkNoDeprecatedFlags() {
324-
325325
// In version >=2.0.0 make it fail (`Warn` -> `Fatal`)
326326
if opts.CustomPlatformDeprecated != "" {
327327
logrus.Warn("Flag --customPlatform is deprecated. Use: --custom-platform")
@@ -391,12 +391,12 @@ func resolveEnvironmentBuildArgs(arguments []string, resolver func(string) strin
391391
// copy Dockerfile to /kaniko/Dockerfile so that if it's specified in the .dockerignore
392392
// it won't be copied into the image
393393
func copyDockerfile() error {
394-
if _, err := util.CopyFile(opts.DockerfilePath, config.DockerfilePath, util.FileContext{}, util.DoNotChangeUID, util.DoNotChangeGID); err != nil {
394+
if _, err := util.CopyFile(opts.DockerfilePath, config.DockerfilePath, util.FileContext{}, util.DoNotChangeUID, util.DoNotChangeGID, fs.FileMode(0o600), true); err != nil {
395395
return errors.Wrap(err, "copying dockerfile")
396396
}
397397
dockerignorePath := opts.DockerfilePath + ".dockerignore"
398398
if util.FilepathExists(dockerignorePath) {
399-
if _, err := util.CopyFile(dockerignorePath, config.DockerfilePath+".dockerignore", util.FileContext{}, util.DoNotChangeUID, util.DoNotChangeGID); err != nil {
399+
if _, err := util.CopyFile(dockerignorePath, config.DockerfilePath+".dockerignore", util.FileContext{}, util.DoNotChangeUID, util.DoNotChangeGID, fs.FileMode(0o600), true); err != nil {
400400
return errors.Wrap(err, "copying Dockerfile.dockerignore")
401401
}
402402
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM alpine@sha256:5ce5f501c457015c4b91f91a15ac69157d9b06f1a75cf9107bf2b62e0843983a
2+
3+
ADD --chmod=0666 context/foo /file666
4+
ADD --chmod=777 context/qux /dir777
5+
6+
# ADD tests
7+
# simple file
8+
RUN test "$(stat -c "%a" /file666)" = "666"
9+
10+
# recurive dir
11+
RUN test "$(stat -c "%a" /dir777/qup)" = "777"
12+
RUN test "$(stat -c "%a" /dir777/quw/que)" = "777"
13+
14+
# COPY tests
15+
16+
COPY --chmod=0755 context/foo /copyfile755
17+
COPY --chmod=755 context/qux /copydir755
18+
19+
RUN test "$(stat -c "%a" /copyfile755)" = "755"
20+
21+
RUN test "$(stat -c "%a" /copydir755/qup)" = "755"
22+
RUN test "$(stat -c "%a" /copydir755/quw/que)" = "755"

integration/images.go

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import (
3939
const (
4040
// ExecutorImage is the name of the kaniko executor image
4141
ExecutorImage = "executor-image"
42-
//WarmerImage is the name of the kaniko cache warmer image
42+
// WarmerImage is the name of the kaniko cache warmer image
4343
WarmerImage = "warmer-image"
4444

4545
dockerPrefix = "docker-"
@@ -69,7 +69,8 @@ var argsMap = map[string][]string{
6969

7070
// Environment to build Dockerfiles with, used for both docker and kaniko builds
7171
var envsMap = map[string][]string{
72-
"Dockerfile_test_arg_secret": {"SSH_PRIVATE_KEY=ThEPriv4t3Key"},
72+
"Dockerfile_test_arg_secret": {"SSH_PRIVATE_KEY=ThEPriv4t3Key"},
73+
"Dockerfile_test_copyadd_chmod": {"DOCKER_BUILDKIT=1"},
7374
}
7475

7576
// Arguments to build Dockerfiles with when building with docker
@@ -138,8 +139,10 @@ func checkArgsNotPrinted(dockerfile string, out []byte) error {
138139
return nil
139140
}
140141

141-
var bucketContextTests = []string{"Dockerfile_test_copy_bucket"}
142-
var reproducibleTests = []string{"Dockerfile_test_reproducible"}
142+
var (
143+
bucketContextTests = []string{"Dockerfile_test_copy_bucket"}
144+
reproducibleTests = []string{"Dockerfile_test_reproducible"}
145+
)
143146

144147
// GetDockerImage constructs the name of the docker image that would be built with
145148
// dockerfile if it was tagged with imageRepo.
@@ -347,13 +350,15 @@ func populateVolumeCache() error {
347350
_, ex, _, _ := runtime.Caller(0)
348351
cwd := filepath.Dir(ex)
349352
warmerCmd := exec.Command("docker",
350-
append([]string{"run", "--net=host",
353+
append([]string{
354+
"run", "--net=host",
351355
"-d",
352356
"-v", os.Getenv("HOME") + "/.config/gcloud:/root/.config/gcloud",
353357
"-v", cwd + ":/workspace",
354358
WarmerImage,
355359
"-c", cacheDir,
356-
"-i", baseImageToCache},
360+
"-i", baseImageToCache,
361+
},
357362
)...,
358363
)
359364

@@ -374,14 +379,16 @@ func (d *DockerFileBuilder) buildCachedImage(config *integrationTestConfig, cach
374379

375380
benchmarkEnv := "BENCHMARK_FILE=false"
376381
if b, err := strconv.ParseBool(os.Getenv("BENCHMARK")); err == nil && b {
377-
os.Mkdir("benchmarks", 0755)
382+
os.Mkdir("benchmarks", 0o755)
378383
benchmarkEnv = "BENCHMARK_FILE=/workspace/benchmarks/" + dockerfile
379384
}
380385
kanikoImage := GetVersionedKanikoImage(imageRepo, dockerfile, version)
381386

382-
dockerRunFlags := []string{"run", "--net=host",
387+
dockerRunFlags := []string{
388+
"run", "--net=host",
383389
"-v", cwd + ":/workspace",
384-
"-e", benchmarkEnv}
390+
"-e", benchmarkEnv,
391+
}
385392
dockerRunFlags = addServiceAccountFlags(dockerRunFlags, serviceAccount)
386393
dockerRunFlags = append(dockerRunFlags, ExecutorImage,
387394
"-f", path.Join(buildContextPath, dockerfilesPath, dockerfile),
@@ -411,10 +418,12 @@ func (d *DockerFileBuilder) buildRelativePathsImage(imageRepo, dockerfile, servi
411418
kanikoImage := GetKanikoImage(imageRepo, "test_relative_"+dockerfile)
412419

413420
dockerCmd := exec.Command("docker",
414-
append([]string{"build",
421+
append([]string{
422+
"build",
415423
"-t", dockerImage,
416424
"-f", dockerfile,
417-
"./context"},
425+
"./context",
426+
},
418427
)...,
419428
)
420429

@@ -483,7 +492,8 @@ func buildKanikoImage(
483492
additionalFlags := append(buildArgs, kanikoArgs...)
484493
logf("Going to build image with kaniko: %s, flags: %s \n", kanikoImage, additionalFlags)
485494

486-
dockerRunFlags := []string{"run", "--net=host",
495+
dockerRunFlags := []string{
496+
"run", "--net=host",
487497
"-e", benchmarkEnv,
488498
"-v", contextDir + ":/workspace",
489499
"-v", benchmarkDir + ":/kaniko/benchmarks",

integration/integration_test.go

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ import (
4646
"github.com/GoogleContainerTools/kaniko/testutil"
4747
)
4848

49-
var config *integrationTestConfig
50-
var imageBuilder *DockerFileBuilder
51-
var allDockerfiles []string
49+
var (
50+
config *integrationTestConfig
51+
imageBuilder *DockerFileBuilder
52+
allDockerfiles []string
53+
)
5254

5355
const (
5456
daemonPrefix = "daemon://"
@@ -148,7 +150,6 @@ func TestMain(m *testing.M) {
148150
fmt.Println(err)
149151
}
150152
os.Exit(exitCode)
151-
152153
}
153154

154155
func buildRequiredImages() error {
@@ -207,7 +208,6 @@ func TestRun(t *testing.T) {
207208

208209
expected := fmt.Sprintf(emptyContainerDiff, dockerImage, kanikoImage, dockerImage, kanikoImage)
209210
checkContainerDiffOutput(t, diff, expected)
210-
211211
})
212212
}
213213

@@ -253,10 +253,12 @@ func testGitBuildcontextHelper(t *testing.T, repo string) {
253253
// Build with docker
254254
dockerImage := GetDockerImage(config.imageRepo, "Dockerfile_test_git")
255255
dockerCmd := exec.Command("docker",
256-
append([]string{"build",
256+
append([]string{
257+
"build",
257258
"-t", dockerImage,
258259
"-f", dockerfile,
259-
repo})...)
260+
repo,
261+
})...)
260262
out, err := RunCommandWithoutTest(dockerCmd)
261263
if err != nil {
262264
t.Errorf("Failed to build image %s with docker command %q: %s %s", dockerImage, dockerCmd.Args, err, string(out))
@@ -363,10 +365,12 @@ func TestBuildViaRegistryMirrors(t *testing.T) {
363365
// Build with docker
364366
dockerImage := GetDockerImage(config.imageRepo, "Dockerfile_registry_mirror")
365367
dockerCmd := exec.Command("docker",
366-
append([]string{"build",
368+
append([]string{
369+
"build",
367370
"-t", dockerImage,
368371
"-f", dockerfile,
369-
repo})...)
372+
repo,
373+
})...)
370374
out, err := RunCommandWithoutTest(dockerCmd)
371375
if err != nil {
372376
t.Errorf("Failed to build image %s with docker command %q: %s %s", dockerImage, dockerCmd.Args, err, string(out))
@@ -403,10 +407,12 @@ func TestBuildViaRegistryMap(t *testing.T) {
403407
// Build with docker
404408
dockerImage := GetDockerImage(config.imageRepo, "Dockerfile_registry_mirror")
405409
dockerCmd := exec.Command("docker",
406-
append([]string{"build",
410+
append([]string{
411+
"build",
407412
"-t", dockerImage,
408413
"-f", dockerfile,
409-
repo})...)
414+
repo,
415+
})...)
410416
out, err := RunCommandWithoutTest(dockerCmd)
411417
if err != nil {
412418
t.Errorf("Failed to build image %s with docker command %q: %s %s", dockerImage, dockerCmd.Args, err, string(out))
@@ -467,10 +473,12 @@ func TestKanikoDir(t *testing.T) {
467473
// Build with docker
468474
dockerImage := GetDockerImage(config.imageRepo, "Dockerfile_registry_mirror")
469475
dockerCmd := exec.Command("docker",
470-
append([]string{"build",
476+
append([]string{
477+
"build",
471478
"-t", dockerImage,
472479
"-f", dockerfile,
473-
repo})...)
480+
repo,
481+
})...)
474482
out, err := RunCommandWithoutTest(dockerCmd)
475483
if err != nil {
476484
t.Errorf("Failed to build image %s with docker command %q: %s %s", dockerImage, dockerCmd.Args, err, string(out))
@@ -508,11 +516,13 @@ func TestBuildWithLabels(t *testing.T) {
508516
// Build with docker
509517
dockerImage := GetDockerImage(config.imageRepo, "Dockerfile_test_label:mylabel")
510518
dockerCmd := exec.Command("docker",
511-
append([]string{"build",
519+
append([]string{
520+
"build",
512521
"-t", dockerImage,
513522
"-f", dockerfile,
514523
"--label", testLabel,
515-
repo})...)
524+
repo,
525+
})...)
516526
out, err := RunCommandWithoutTest(dockerCmd)
517527
if err != nil {
518528
t.Errorf("Failed to build image %s with docker command %q: %s %s", dockerImage, dockerCmd.Args, err, string(out))
@@ -549,10 +559,12 @@ func TestBuildWithHTTPError(t *testing.T) {
549559
// Build with docker
550560
dockerImage := GetDockerImage(config.imageRepo, "Dockerfile_test_add_404")
551561
dockerCmd := exec.Command("docker",
552-
append([]string{"build",
562+
append([]string{
563+
"build",
553564
"-t", dockerImage,
554565
"-f", dockerfile,
555-
repo})...)
566+
repo,
567+
})...)
556568
out, err := RunCommandWithoutTest(dockerCmd)
557569
if err == nil {
558570
t.Errorf("an error was expected, got %s", string(out))
@@ -588,6 +600,7 @@ func TestLayers(t *testing.T) {
588600
// produces a different amount of layers (?).
589601
offset["Dockerfile_test_copy_same_file_many_times"] = 47
590602
offset["Dockerfile_test_meta_arg"] = 1
603+
offset["Dockerfile_test_copyadd_chmod"] = 6
591604
}
592605

593606
for _, dockerfile := range allDockerfiles {
@@ -732,7 +745,6 @@ func verifyBuildWith(t *testing.T, cache, dockerfile string) {
732745
}
733746

734747
func TestRelativePaths(t *testing.T) {
735-
736748
dockerfile := "Dockerfile_relative_copy"
737749

738750
t.Run("test_relative_"+dockerfile, func(t *testing.T) {
@@ -763,7 +775,6 @@ func TestRelativePaths(t *testing.T) {
763775
}
764776

765777
func TestExitCodePropagation(t *testing.T) {
766-
767778
currentDir, err := os.Getwd()
768779
if err != nil {
769780
t.Fatal("Could not get working dir")
@@ -778,7 +789,8 @@ func TestExitCodePropagation(t *testing.T) {
778789
dockerFlags := []string{
779790
"build",
780791
"-t", dockerImage,
781-
"-f", dockerfile}
792+
"-f", dockerfile,
793+
}
782794
dockerCmd := exec.Command("docker", append(dockerFlags, context)...)
783795

784796
out, kanikoErr := RunCommandWithoutTest(dockerCmd)
@@ -798,7 +810,7 @@ func TestExitCodePropagation(t *testing.T) {
798810
t.Fatalf("did not produce the expected error:\n%s", out)
799811
}
800812

801-
//try to build the same image with kaniko the error code should match with the one from the plain docker build
813+
// try to build the same image with kaniko the error code should match with the one from the plain docker build
802814
contextVolume := fmt.Sprintf("%s:/workspace", context)
803815

804816
dockerFlags = []string{

pkg/commands/add.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package commands
1818

1919
import (
20+
"io/fs"
2021
"path/filepath"
2122

2223
v1 "github.com/google/go-containerregistry/pkg/v1"
@@ -47,6 +48,14 @@ type AddCommand struct {
4748
func (a *AddCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
4849
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
4950

51+
chmod, useDefaultChmod, err := util.GetChmod(a.cmd.Chmod, replacementEnvs)
52+
if err != nil {
53+
return errors.Wrap(err, "getting permissions from chmod")
54+
}
55+
if useDefaultChmod {
56+
chmod = fs.FileMode(0o600)
57+
}
58+
5059
uid, gid, err := util.GetUserGroup(a.cmd.Chown, replacementEnvs)
5160
if err != nil {
5261
return errors.Wrap(err, "getting user group from chown")
@@ -71,7 +80,7 @@ func (a *AddCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui
7180
return err
7281
}
7382
logrus.Infof("Adding remote URL %s to %s", src, urlDest)
74-
if err := util.DownloadFileToDest(src, urlDest, uid, gid); err != nil {
83+
if err := util.DownloadFileToDest(src, urlDest, uid, gid, chmod); err != nil {
7584
return errors.Wrap(err, "downloading remote source file")
7685
}
7786
a.snapshotFiles = append(a.snapshotFiles, urlDest)
@@ -100,6 +109,7 @@ func (a *AddCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui
100109
cmd: &instructions.CopyCommand{
101110
SourcesAndDest: instructions.SourcesAndDest{SourcePaths: unresolvedSrcs, DestPath: dest},
102111
Chown: a.cmd.Chown,
112+
Chmod: a.cmd.Chmod,
103113
},
104114
fileContext: a.fileContext,
105115
}

pkg/commands/copy.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bu
6464
return errors.Wrap(err, "resolving src")
6565
}
6666

67+
chmod, useDefaultChmod, err := util.GetChmod(c.cmd.Chmod, replacementEnvs)
68+
if err != nil {
69+
return errors.Wrap(err, "getting permissions from chmod")
70+
}
71+
6772
// For each source, iterate through and copy it over
6873
for _, src := range srcs {
6974
fullPath := filepath.Join(c.fileContext.Root, src)
@@ -93,7 +98,7 @@ func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bu
9398
}
9499

95100
if fi.IsDir() {
96-
copiedFiles, err := util.CopyDir(fullPath, destPath, c.fileContext, uid, gid)
101+
copiedFiles, err := util.CopyDir(fullPath, destPath, c.fileContext, uid, gid, chmod, useDefaultChmod)
97102
if err != nil {
98103
return errors.Wrap(err, "copying dir")
99104
}
@@ -110,7 +115,7 @@ func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bu
110115
c.snapshotFiles = append(c.snapshotFiles, destPath)
111116
} else {
112117
// ... Else, we want to copy over a file
113-
exclude, err := util.CopyFile(fullPath, destPath, c.fileContext, uid, gid)
118+
exclude, err := util.CopyFile(fullPath, destPath, c.fileContext, uid, gid, chmod, useDefaultChmod)
114119
if err != nil {
115120
return errors.Wrap(err, "copying file")
116121
}

0 commit comments

Comments
 (0)