From b92996676eed2dc2d24ffaad4a1d95dc7cd44692 Mon Sep 17 00:00:00 2001 From: Martin Zihlmann Date: Fri, 3 Jul 2026 22:33:28 +0100 Subject: [PATCH 1/3] v1.29.0 dry-run: flip switch-on feature flags to default true (except RUN_VIA_TINI, blocked on RISC-V tini) --- pkg/executor/build.go | 14 +++++++------- pkg/util/fs_util.go | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/executor/build.go b/pkg/executor/build.go index e428535b4..ac3465951 100644 --- a/pkg/executor/build.go +++ b/pkg/executor/build.go @@ -240,7 +240,7 @@ func populateCompositeKey(command commands.DockerCommand, files []string, compos // Add the next command to the cache key. keyString := command.String() resolver, ok := command.(commands.CacheKeyResolver) - if ok && config.EnvBool("FF_KANIKO_RESOLVE_CACHE_KEY") { + if ok && config.EnvBoolDefault("FF_KANIKO_RESOLVE_CACHE_KEY", true) { resolved, err := resolver.CacheKey(replacementEnvs) if err != nil { return compositeKey, fmt.Errorf("resolving cache key: %w", err) @@ -336,7 +336,7 @@ func (s *stageBuilder) optimize(compositeKeyPtr *CompositeCache, cfg v1.Config, copyCmd, isCopy := commands.CastAbstractCopyCommand(command) if !hasContext && isCopy && copyCmd.From() != "" { inferred := false - if config.EnvBool("FF_KANIKO_INFER_CROSS_STAGE_CACHE_KEY") && opts.CacheCopyLayers { + if config.EnvBoolDefault("FF_KANIKO_INFER_CROSS_STAGE_CACHE_KEY", true) && opts.CacheCopyLayers { inferredKey, err := populateCompositeKey(command, nil, compositeKey, args, cfg.Env, fileContext, stageFinalCacheKeys, externalImageDigests) if err == nil { inferredCK, err := inferredKey.Hash() @@ -374,7 +374,7 @@ func (s *stageBuilder) optimize(compositeKeyPtr *CompositeCache, cfg v1.Config, } // mz334: assert the inferred key pointer resolves to the same content key. - if config.EnvBool("FF_KANIKO_INFER_CROSS_STAGE_CACHE_KEY") && opts.CacheCopyLayers { + if config.EnvBoolDefault("FF_KANIKO_INFER_CROSS_STAGE_CACHE_KEY", true) && opts.CacheCopyLayers { inferredKey, err := populateCompositeKey(command, nil, prevCompositeKey, args, cfg.Env, fileContext, stageFinalCacheKeys, externalImageDigests) if err == nil { inferredCK, err := inferredKey.Hash() @@ -531,7 +531,7 @@ func (s *stageBuilder) build(compositeKey CompositeCache, opts *config.KanikoOpt return err } // mz334: also compute the inferred key so we can push a pointer below. - if config.EnvBool("FF_KANIKO_INFER_CROSS_STAGE_CACHE_KEY") && opts.CacheCopyLayers { + if config.EnvBoolDefault("FF_KANIKO_INFER_CROSS_STAGE_CACHE_KEY", true) && opts.CacheCopyLayers { inferredKey, err := populateCompositeKey(command, nil, prevCompositeKey, s.args, s.cf.Config.Env, fileContext, stageFinalCacheKeys, externalImageDigests) if err == nil { inferredCacheKey, err = inferredKey.Hash() @@ -816,7 +816,7 @@ func convertLayerMediaType(layer v1.Layer, image v1.Image, opts *config.KanikoOp if targetMediaType != "" { srcCompression := layerCompression(layerMediaType) dstCompression := layerCompression(targetMediaType) - if config.EnvBool("FF_KANIKO_SKIP_RELABEL_RECOMPRESS") && srcCompression != "" && srcCompression == dstCompression { + if config.EnvBoolDefault("FF_KANIKO_SKIP_RELABEL_RECOMPRESS", true) && srcCompression != "" && srcCompression == dstCompression { relabeled, err := tarball.LayerFromOpener(layer.Compressed, layerOpts...) if err != nil { return nil, err @@ -974,7 +974,7 @@ func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts printf("UNPACK %s\n", s.BaseName) } for jdx, c := range s.Commands { - if opts.Cache && opts.CacheCopyLayers && config.EnvBool("FF_KANIKO_INFER_CROSS_STAGE_CACHE_KEY") && config.EnvBool("FF_KANIKO_CACHE_LOOKAHEAD") { + if opts.Cache && opts.CacheCopyLayers && config.EnvBoolDefault("FF_KANIKO_INFER_CROSS_STAGE_CACHE_KEY", true) && config.EnvBool("FF_KANIKO_CACHE_LOOKAHEAD") { if copyCmd, ok := c.(*instructions.CopyCommand); ok && copyCmd.From != "" { ci := cacheInfo[s.Index] if ck := ci.redirectKeys[jdx]; ck != "" { @@ -1296,7 +1296,7 @@ func DoBuild(opts *config.KanikoOptions) (image v1.Image, retErr error) { if err != nil { return nil, err } - if config.EnvBool("FF_KANIKO_REPRODUCIBLE_PRESERVE_BASE_LAYERS") { + if config.EnvBoolDefault("FF_KANIKO_REPRODUCIBLE_PRESERVE_BASE_LAYERS", true) { sourceImage, err = image_util.ReplaceBase(sourceImage, baseImage) if err != nil { return nil, err diff --git a/pkg/util/fs_util.go b/pkg/util/fs_util.go index 24a5d0446..8bf5b3cc9 100644 --- a/pkg/util/fs_util.go +++ b/pkg/util/fs_util.go @@ -236,7 +236,7 @@ func extractLayer(i int, l v1.Layer, root string, cfg *FSConfig) ([]string, erro } // mz774: whiteout deletion is already applied, the marker is not needed in the filesystem - if !cfg.includeWhiteout || config.EnvBool("FF_KANIKO_SKIP_WRITE_WHITEOUTS") { + if !cfg.includeWhiteout || config.EnvBoolDefault("FF_KANIKO_SKIP_WRITE_WHITEOUTS", true) { logrus.Trace("Not including whiteout files") continue } @@ -347,7 +347,7 @@ func UnTar(r io.Reader, dest string) ([]string, error) { return nil, err } cleanedName := filepath.Clean(hdr.Name) - if cleanedName == "." && config.EnvBool("FF_KANIKO_UNTAR_SKIP_ROOT") { + if cleanedName == "." && config.EnvBoolDefault("FF_KANIKO_UNTAR_SKIP_ROOT", true) { continue } if err := ExtractFile(dest, hdr, cleanedName, tr); err != nil { From 233753dfc41058adda2908a238b8ba0d94588c0e Mon Sep 17 00:00:00 2001 From: Martin Zihlmann Date: Mon, 29 Jun 2026 15:30:09 +0100 Subject: [PATCH 2/3] read FF_KANIKO_VOLUME_SKIP_MKDIR and FF_KANIKO_DEPRECATE_INTER_STAGE_RESTORE with their documented default --- cmd/executor/cmd/root.go | 2 +- pkg/executor/build.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/executor/cmd/root.go b/cmd/executor/cmd/root.go index 46b4696e2..d8b32d3de 100644 --- a/cmd/executor/cmd/root.go +++ b/cmd/executor/cmd/root.go @@ -403,7 +403,7 @@ func checkNoDeprecatedFlags() { logrus.Warn("Flag --skip-unused-stages is deprecated. This is the new default behaviour. If you want to build multiple independent stages pass them as --target instead") } - if !config.EnvBool("FF_KANIKO_DEPRECATE_INTER_STAGE_RESTORE") { + if !config.EnvBoolDefault("FF_KANIKO_DEPRECATE_INTER_STAGE_RESTORE", true) { if opts.PreserveContext && !opts.PreCleanup { logrus.Warn("--preserve-context without --pre-cleanup restores the original context between stages; this is deprecated and will be removed. Use --mount=type=secret for secrets. Set FF_KANIKO_DEPRECATE_INTER_STAGE_RESTORE=1 to opt into the new behaviour now.") } diff --git a/pkg/executor/build.go b/pkg/executor/build.go index ac3465951..679590380 100644 --- a/pkg/executor/build.go +++ b/pkg/executor/build.go @@ -600,7 +600,7 @@ func (s *stageBuilder) build(compositeKey CompositeCache, opts *config.KanikoOpt util.Assert("executor.build.metadata-only", command.MetadataOnly(), "build: non-MetadataOnly command %q ran without unpacked filesystem in stage %d", command.String(), s.index) } _, isVolume := command.(*commands.VolumeCommand) - volumeCreatesFiles := isVolume && !config.EnvBool("FF_KANIKO_VOLUME_SKIP_MKDIR") + volumeCreatesFiles := isVolume && !config.EnvBoolDefault("FF_KANIKO_VOLUME_SKIP_MKDIR", true) if command.MetadataOnly() && !opts.SingleSnapshot && !volumeCreatesFiles { // MetadataOnly commands must not change or even need the filesystem. util.Assert("executor.build.without-fs", snapshotted == 0, "build: MetadataOnly command %q snapshotted %d file(s)", command.String(), snapshotted) @@ -659,7 +659,7 @@ func takeSnapshot(files []string, shdDelete bool, opts *config.KanikoOptions, sn if files == nil || opts.SingleSnapshot { snapshot, snapshotted, err = snapshotter.TakeSnapshotFS() } else { - if !config.EnvBool("FF_KANIKO_VOLUME_SKIP_MKDIR") { + if !config.EnvBoolDefault("FF_KANIKO_VOLUME_SKIP_MKDIR", true) { // Volumes are very weird. They get snapshotted in the next command. files = append(files, util.Volumes()...) } From 8dc802fd8f03fdf8c39d94cefd7342179e8d6691 Mon Sep 17 00:00:00 2001 From: Martin Zihlmann Date: Fri, 3 Jul 2026 23:02:58 +0100 Subject: [PATCH 3/3] v1.29.0 dry-run: remove deprecated feature flags and their legacy code paths --- cmd/executor/cmd/root.go | 6 - .../dockerfiles/Dockerfile_test_issue_mz793 | 8 -- integration/images.go | 6 - pkg/cache/cache.go | 66 +--------- pkg/commands/env.go | 7 +- pkg/commands/run.go | 6 +- pkg/commands/volume.go | 14 -- pkg/dockerfile/buildargs.go | 10 +- pkg/executor/build.go | 33 +---- pkg/util/fs_util.go | 65 ++++------ pkg/warmer/lock.go | 2 +- pkg/warmer/warm.go | 120 +++--------------- 12 files changed, 54 insertions(+), 289 deletions(-) delete mode 100644 integration/dockerfiles/Dockerfile_test_issue_mz793 diff --git a/cmd/executor/cmd/root.go b/cmd/executor/cmd/root.go index d8b32d3de..8bb88fd85 100644 --- a/cmd/executor/cmd/root.go +++ b/cmd/executor/cmd/root.go @@ -402,12 +402,6 @@ func checkNoDeprecatedFlags() { if opts.SkipUnusedStagesDeprecated { logrus.Warn("Flag --skip-unused-stages is deprecated. This is the new default behaviour. If you want to build multiple independent stages pass them as --target instead") } - - if !config.EnvBoolDefault("FF_KANIKO_DEPRECATE_INTER_STAGE_RESTORE", true) { - if opts.PreserveContext && !opts.PreCleanup { - logrus.Warn("--preserve-context without --pre-cleanup restores the original context between stages; this is deprecated and will be removed. Use --mount=type=secret for secrets. Set FF_KANIKO_DEPRECATE_INTER_STAGE_RESTORE=1 to opt into the new behaviour now.") - } - } } // cacheFlagsValid makes sure the flags passed in related to caching are valid diff --git a/integration/dockerfiles/Dockerfile_test_issue_mz793 b/integration/dockerfiles/Dockerfile_test_issue_mz793 deleted file mode 100644 index 5dacbbbf5..000000000 --- a/integration/dockerfiles/Dockerfile_test_issue_mz793 +++ /dev/null @@ -1,8 +0,0 @@ -FROM busybox - -# mz793: VOLUME + --cache panics on assertion executor.build.without-fs since v1.27.4. -# With FF_KANIKO_VOLUME_SKIP_MKDIR off, VOLUME creates the volume directory and it gets -# snapshotted, but VolumeCommand reports MetadataOnly, so the without-fs assertion -# (metadata-only commands snapshot zero files) fires. The assertion only holds once the -# flag skips the mkdir, so it must be gated on the flag. -VOLUME /data diff --git a/integration/images.go b/integration/images.go index d562468ee..a5f326c5f 100644 --- a/integration/images.go +++ b/integration/images.go @@ -94,7 +94,6 @@ var envsMap = map[string][]string{ "Dockerfile_test_issue_cg188": {"SECRET=blubb"}, "Dockerfile_test_issue_mz774": {"FF_KANIKO_SKIP_WRITE_WHITEOUTS=1"}, "Dockerfile_test_issue_mz775": {"FF_KANIKO_CACHE_LOOKAHEAD=0", "FF_KANIKO_SKIP_RELABEL_RECOMPRESS=1"}, - "Dockerfile_test_issue_mz793": {"FF_KANIKO_VOLUME_SKIP_MKDIR=0"}, "Dockerfile_test_issue_mz473": {"KANIKO_DIR=/kaniko2"}, "Dockerfile_test_issue_mz661": {"KANIKO_DIR=/kaniko2"}, "Dockerfile_test_stopsignal": {"FF_KANIKO_OCI_SCRATCH_BASE=0"}, @@ -266,10 +265,6 @@ var diffArgsMap = map[string][]string{ // mz595: surprisingly the missing files are **not** picked up if we ignore layer-length-mismatch, // which we do by default in TestRun, we should move to disable that globally urgently. "TestRun/test_Dockerfile_test_issue_mz595": {"--extra-ignore-layer-length-mismatch=false"}, - // mz793: with FF_KANIKO_VOLUME_SKIP_MKDIR off, VOLUME creates the directory fresh on - // each build, so its mtime differs between the two cached builds. That divergence is the - // known volume non-determinism the flag fixes, here we only assert the build no longer panics. - "TestCache/test_cache_Dockerfile_test_issue_mz793": {"--extra-ignore-files=data/"}, } // output check to do when building with kaniko @@ -485,7 +480,6 @@ func NewDockerFileBuilder() *DockerFileBuilder { "Dockerfile_test_issue_mz774": {}, "Dockerfile_test_issue_mz775": {}, "Dockerfile_test_issue_mz782": {}, - "Dockerfile_test_issue_mz793": {}, } d.TestOCICacheDockerfiles = map[string]struct{}{ "Dockerfile_test_cache_oci": {}, diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 5030ae726..35ea03a17 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -21,7 +21,6 @@ import ( "fmt" "os" "path" - "path/filepath" "strings" "time" @@ -29,7 +28,6 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/layout" "github.com/google/go-containerregistry/pkg/v1/remote" - "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/osscontainertools/kaniko/pkg/config" "github.com/osscontainertools/kaniko/pkg/creds" "github.com/osscontainertools/kaniko/pkg/util" @@ -196,69 +194,7 @@ func LocalSource(opts *config.CacheOptions, cacheKey string) (v1.Image, error) { } logrus.Infof("Found %s in local cache", cacheKey) - if config.EnvBoolDefault("FF_KANIKO_OCI_WARMER", true) { - return ociCachedImageFromPath(path) - } else { - return cachedImageFromPath(path) - } -} - -// cachedImage represents a v1.Tarball that is cached locally in a CAS. -// Computing the digest for a v1.Tarball is very expensive. If the tarball -// is named with the digest we can store this and return it directly rather -// than recompute it. -type cachedImage struct { - digest string - v1.Image - mfst *v1.Manifest -} - -func (c *cachedImage) Digest() (v1.Hash, error) { - return v1.NewHash(c.digest) -} - -func (c *cachedImage) Manifest() (*v1.Manifest, error) { - if config.EnvBool("FF_KANIKO_IGNORE_CACHED_MANIFEST") || c.mfst == nil { - return c.Image.Manifest() - } - return c.mfst, nil -} - -func mfstFromPath(p string) (*v1.Manifest, error) { - f, err := util.FSys.Open(p) - if err != nil { - return nil, err - } - defer f.Close() - return v1.ParseManifest(f) -} - -func cachedImageFromPath(p string) (v1.Image, error) { - imgTar, err := tarball.ImageFromPath(p, nil) - if err != nil { - return nil, fmt.Errorf("getting image from path: %w", err) - } - - // Manifests may be present next to the tar, named with a ".json" suffix - mfstPath := p + ".json" - - var mfst *v1.Manifest - if _, err := os.Stat(mfstPath); err != nil { - logrus.Debugf("Manifest does not exist at file: %s", mfstPath) - } else { - mfst, err = mfstFromPath(mfstPath) - if err != nil { - logrus.Debugf("Error parsing manifest from file: %s", mfstPath) - } else { - logrus.Infof("Found manifest at %s", mfstPath) - } - } - - return &cachedImage{ - digest: filepath.Base(p), - Image: imgTar, - mfst: mfst, - }, nil + return ociCachedImageFromPath(path) } func ociCachedImageFromPath(tarPath string) (v1.Image, error) { diff --git a/pkg/commands/env.go b/pkg/commands/env.go index b3b14564b..a79dd98a5 100644 --- a/pkg/commands/env.go +++ b/pkg/commands/env.go @@ -19,7 +19,6 @@ package commands import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/moby/buildkit/frontend/dockerfile/instructions" - kConfig "github.com/osscontainertools/kaniko/pkg/config" "github.com/osscontainertools/kaniko/pkg/dockerfile" "github.com/osscontainertools/kaniko/pkg/util" ) @@ -37,10 +36,8 @@ func (e *EnvCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui return err } // 3344: An ENV declared after an ARG of the same name overrides it. - if kConfig.EnvBoolDefault("FF_KANIKO_BUILDKIT_ARG_ENV_PRECEDENCE", true) { - for _, keyVal := range newEnvs { - buildArgs.RemoveArg(keyVal.Key) - } + for _, keyVal := range newEnvs { + buildArgs.RemoveArg(keyVal.Key) } return nil } diff --git a/pkg/commands/run.go b/pkg/commands/run.go index bc2638e3e..f033b9d68 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -59,7 +59,6 @@ func (r *RunCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui } func runCommandWithFlags(config *v1.Config, buildArgs *dockerfile.BuildArgs, cmdRun *instructions.RunCommand, fileContext util.FileContext, secrets kConfig.SecretOptions) (reterr error) { - ff_bind := kConfig.EnvBoolDefault("FF_KANIKO_RUN_MOUNT_BIND", true) for _, f := range cmdRun.FlagsUsed { if f != "mount" { logrus.Warnf("#969 kaniko does not support '--%s' flags in RUN statements - relying on unsupported flags can lead to invalid builds", f) @@ -216,7 +215,7 @@ func runCommandWithFlags(config *v1.Config, buildArgs *dockerfile.BuildArgs, cmd } } // https://docs.docker.com/reference/dockerfile/#run---mounttypebind - case m.Type == instructions.MountTypeBind && ff_bind: + case m.Type == instructions.MountTypeBind: if m.From != "" && m.From != "context" { logrus.Warnf("Kaniko does not support cross-stage bind mounts (from=%s) - skipping", m.From) continue @@ -529,8 +528,7 @@ func runCmdFilesUsedFromContext( config *v1.Config, buildArgs *dockerfile.BuildArgs, cmd *instructions.RunCommand, fileContext util.FileContext, ) ([]string, error) { - ff_bind := kConfig.EnvBoolDefault("FF_KANIKO_RUN_MOUNT_BIND", true) - if !ff_bind || len(cmd.FlagsUsed) == 0 { + if len(cmd.FlagsUsed) == 0 { return []string{}, nil } diff --git a/pkg/commands/volume.go b/pkg/commands/volume.go index 4726f6dea..d73c5e39c 100644 --- a/pkg/commands/volume.go +++ b/pkg/commands/volume.go @@ -17,12 +17,8 @@ limitations under the License. package commands import ( - "fmt" - "os" - v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/moby/buildkit/frontend/dockerfile/instructions" - kconfig "github.com/osscontainertools/kaniko/pkg/config" "github.com/osscontainertools/kaniko/pkg/dockerfile" "github.com/osscontainertools/kaniko/pkg/util" "github.com/sirupsen/logrus" @@ -50,16 +46,6 @@ func (v *VolumeCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile. var x struct{} existingVolumes[volume] = x util.AddVolumePathToIgnoreList(volume) - - if !kconfig.EnvBoolDefault("FF_KANIKO_VOLUME_SKIP_MKDIR", true) { - // Only create and snapshot the dir if it didn't exist already - if _, err := os.Stat(volume); os.IsNotExist(err) { - logrus.Infof("Creating directory %s", volume) - if err := os.MkdirAll(volume, 0o755); err != nil { - return fmt.Errorf("could not create directory for volume %s: %w", volume, err) - } - } - } } config.Volumes = existingVolumes util.Assert("volume.count-monotone", len(config.Volumes) >= prevVolumeCount, "VOLUME must not remove volumes: count went from %d to %d", prevVolumeCount, len(config.Volumes)) diff --git a/pkg/dockerfile/buildargs.go b/pkg/dockerfile/buildargs.go index b73c7f8f4..f2fa1969e 100644 --- a/pkg/dockerfile/buildargs.go +++ b/pkg/dockerfile/buildargs.go @@ -23,7 +23,6 @@ import ( "github.com/containerd/platforms" "github.com/moby/buildkit/frontend/dockerfile/instructions" - "github.com/osscontainertools/kaniko/pkg/config" "github.com/osscontainertools/kaniko/pkg/util" ) @@ -93,13 +92,8 @@ func (b *BuildArgs) ReplacementEnvs(envs []string) []string { nenvs := len(merged) args := b.GetAllAllowed() for key, val := range args { - if config.EnvBoolDefault("FF_KANIKO_BUILDKIT_ARG_ENV_PRECEDENCE", true) { - // 3344: args always override envs - merged[key] = &val - } else if _, exists := merged[key]; !exists { - // 3344: legacy behaviour, envs always override args - merged[key] = &val - } + // 3344: args always override envs + merged[key] = &val } result := make([]string, 0, len(merged)) for key, val := range merged { diff --git a/pkg/executor/build.go b/pkg/executor/build.go index 679590380..e63a9c72c 100644 --- a/pkg/executor/build.go +++ b/pkg/executor/build.go @@ -599,9 +599,7 @@ func (s *stageBuilder) build(compositeKey CompositeCache, opts *config.KanikoOpt // So the only case where we don't need a filesystem is if all commands are MetadataOnly. util.Assert("executor.build.metadata-only", command.MetadataOnly(), "build: non-MetadataOnly command %q ran without unpacked filesystem in stage %d", command.String(), s.index) } - _, isVolume := command.(*commands.VolumeCommand) - volumeCreatesFiles := isVolume && !config.EnvBoolDefault("FF_KANIKO_VOLUME_SKIP_MKDIR", true) - if command.MetadataOnly() && !opts.SingleSnapshot && !volumeCreatesFiles { + if command.MetadataOnly() && !opts.SingleSnapshot { // MetadataOnly commands must not change or even need the filesystem. util.Assert("executor.build.without-fs", snapshotted == 0, "build: MetadataOnly command %q snapshotted %d file(s)", command.String(), snapshotted) } @@ -659,10 +657,6 @@ func takeSnapshot(files []string, shdDelete bool, opts *config.KanikoOptions, sn if files == nil || opts.SingleSnapshot { snapshot, snapshotted, err = snapshotter.TakeSnapshotFS() } else { - if !config.EnvBoolDefault("FF_KANIKO_VOLUME_SKIP_MKDIR", true) { - // Volumes are very weird. They get snapshotted in the next command. - files = append(files, util.Volumes()...) - } snapshot, snapshotted, err = snapshotter.TakeSnapshot(files, shdDelete) } timing.DefaultRun.Stop(t) @@ -1022,11 +1016,6 @@ func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts printf("SAVE FILES %v %s%d\n", filesToSave, config.KanikoInterStageDepsDir, s.Index) } printf("CLEAN\n\n") - if !config.EnvBoolDefault("FF_KANIKO_DEPRECATE_INTER_STAGE_RESTORE", true) { - if opts.PreserveContext && !opts.PreCleanup { - printf("RESTORE CONTEXT\n\n") - } - } } util.Unreachable("we should always have a final stage") return retErr @@ -1089,9 +1078,7 @@ func DoBuild(opts *config.KanikoOptions) (image v1.Image, retErr error) { return nil, fmt.Errorf("precompute: failed to get baseImage: %w", err) } } - if config.EnvBoolDefault("FF_KANIKO_NO_PROPAGATE_ANNOTATIONS", true) { - baseImage = image_util.WithoutAnnotations(baseImage) - } + baseImage = image_util.WithoutAnnotations(baseImage) args := baseArgs if stage.BaseImageStoredLocally { args = stageArgs[stage.BaseImageIndex] @@ -1195,9 +1182,7 @@ func DoBuild(opts *config.KanikoOptions) (image v1.Image, retErr error) { if err != nil { return nil, fmt.Errorf("failed to get baseImage: %w", err) } - if config.EnvBoolDefault("FF_KANIKO_NO_PROPAGATE_ANNOTATIONS", true) { - baseImage = image_util.WithoutAnnotations(baseImage) - } + baseImage = image_util.WithoutAnnotations(baseImage) args := baseArgs if stage.BaseImageStoredLocally { @@ -1341,18 +1326,6 @@ func DoBuild(opts *config.KanikoOptions) (image v1.Image, retErr error) { if err := util.DeleteFilesystem(); err != nil { return nil, fmt.Errorf("deleting file system after stage %d: %w", stage.Index, err) } - if !config.EnvBoolDefault("FF_KANIKO_DEPRECATE_INTER_STAGE_RESTORE", true) { - if opts.PreserveContext && !opts.PreCleanup { - if tarball == "" { - return nil, errors.New("context snapshot is missing") - } - _, err := util.UnpackLocalTarArchive(tarball, config.RootDir) - if err != nil { - return nil, fmt.Errorf("failed to unpack context snapshot: %w", err) - } - logrus.Info("Context restored") - } - } } util.Unreachable("we should always have a final stage") diff --git a/pkg/util/fs_util.go b/pkg/util/fs_util.go index 8bf5b3cc9..606646bae 100644 --- a/pkg/util/fs_util.go +++ b/pkg/util/fs_util.go @@ -88,8 +88,6 @@ var ignorelist = append([]IgnoreListEntry{}, defaultIgnoreList...) var volumes = []string{} -var secureExtraction = config.EnvBoolDefault("FF_KANIKO_SECUREJOIN_EXTRACTION", true) - type FileContext struct { Root string ExcludedFiles []string @@ -210,13 +208,11 @@ func extractLayer(i int, l v1.Layer, root string, cfg *FSConfig) ([]string, erro if strings.HasPrefix(base, archive.WhiteoutPrefix) { dir := filepath.Dir(path) - if secureExtraction { - securePath, err := securejoin.SecureJoin(root, cleanedName) - if err != nil { - return nil, fmt.Errorf("resolving whiteout path for %q: %w", hdr.Name, err) - } - dir = filepath.Dir(securePath) + securePath, err := securejoin.SecureJoin(root, cleanedName) + if err != nil { + return nil, fmt.Errorf("resolving whiteout path for %q: %w", hdr.Name, err) } + dir = filepath.Dir(securePath) name := strings.TrimPrefix(base, archive.WhiteoutPrefix) path := filepath.Join(dir, name) @@ -302,7 +298,7 @@ func childDirInIgnoreList(path string) bool { } func removeAllSkipIgnored(path string) (skip bool, err error) { - if !config.EnvBoolDefault("FF_KANIKO_PRESERVE_MOUNTED_PATHS", true) || !childDirInIgnoreList(path) { + if !childDirInIgnoreList(path) { return false, os.RemoveAll(path) } logrus.Debugf("Not removing %s, as it contains an ignored path", path) @@ -364,23 +360,19 @@ func ExtractFile(dest string, hdr *tar.Header, cleanedName string, tr io.Reader) } var path string - if secureExtraction { - // cg330: SecureJoin the parent only, then append the basename lexically. Joining - // the full name would resolve the final component when it is a symlink we - // mean to overwrite, writing through it and creating loops like - // bin/sh -> dash -> dash. - secureDir, err := securejoin.SecureJoin(dest, filepath.Dir(cleanedName)) - if err != nil { - if !errors.Is(err, syscall.ELOOP) { - return fmt.Errorf("resolving path for %q: %w", hdr.Name, err) - } - logrus.Warnf("Skipping %q: parent path cannot be securely resolved (symlink loop)", hdr.Name) - return nil + // cg330: SecureJoin the parent only, then append the basename lexically. Joining + // the full name would resolve the final component when it is a symlink we + // mean to overwrite, writing through it and creating loops like + // bin/sh -> dash -> dash. + secureDir, err := securejoin.SecureJoin(dest, filepath.Dir(cleanedName)) + if err != nil { + if !errors.Is(err, syscall.ELOOP) { + return fmt.Errorf("resolving path for %q: %w", hdr.Name, err) } - path = filepath.Join(secureDir, filepath.Base(cleanedName)) - } else { - path = filepath.Join(dest, cleanedName) + logrus.Warnf("Skipping %q: parent path cannot be securely resolved (symlink loop)", hdr.Name) + return nil } + path = filepath.Join(secureDir, filepath.Base(cleanedName)) base := filepath.Base(path) dir := filepath.Dir(path) mode := hdr.FileInfo().Mode() @@ -450,12 +442,10 @@ func ExtractFile(dest string, hdr *tar.Header, cleanedName string, tr io.Reader) } case tar.TypeDir: logrus.Tracef("Creating dir %s", path) - if secureExtraction { - fi, lerr := os.Lstat(path) - if lerr == nil && fi.Mode()&os.ModeSymlink != 0 { - if err := os.Remove(path); err != nil { - return fmt.Errorf("error removing symlink %s to make way for new directory: %w", path, err) - } + fi, lerr := os.Lstat(path) + if lerr == nil && fi.Mode()&os.ModeSymlink != 0 { + if err := os.Remove(path); err != nil { + return fmt.Errorf("error removing symlink %s to make way for new directory: %w", path, err) } } if err := MkdirAllWithPermissions(path, mode, int64(uid), int64(gid)); err != nil { @@ -497,15 +487,11 @@ func ExtractFile(dest string, hdr *tar.Header, cleanedName string, tr io.Reader) return fmt.Errorf("hardlink target %q is not allowed: references parent directory", hdr.Linkname) } var link string - if secureExtraction { - resolved, err := securejoin.SecureJoin(dest, hdr.Linkname) - if err != nil { - return fmt.Errorf("invalid hardlink target %q: %w", hdr.Linkname, err) - } - link = resolved - } else { - link = filepath.Clean(filepath.Join(dest, hdr.Linkname)) + resolved, err := securejoin.SecureJoin(dest, hdr.Linkname) + if err != nil { + return fmt.Errorf("invalid hardlink target %q: %w", hdr.Linkname, err) } + link = resolved if err := os.Link(link, path); err != nil { return err } @@ -775,7 +761,6 @@ func CopyDir(src, dest string, context FileContext, uid, gid int64, chmod mode.S var copiedFiles []string var updates []timestampUpdate hardlinksSeen := make(map[uint64]string) - preserveHardlinks := config.EnvBoolDefault("FF_KANIKO_PRESERVE_HARDLINKS", true) for _, file := range files { fullPath := filepath.Join(src, file) if context.ExcludesFile(fullPath) { @@ -829,7 +814,7 @@ func CopyDir(src, dest string, context FileContext, uid, gid int64, chmod mode.S if _, err := CopySymlink(fullPath, destPath, context); err != nil { return nil, err } - } else if linkDst, ok := checkCopyHardlink(fi, destPath, hardlinksSeen); ok && preserveHardlinks { + } else if linkDst, ok := checkCopyHardlink(fi, destPath, hardlinksSeen); ok { // #2594: inode already copied — create a hardlink instead of duplicating content. logrus.Tracef("Creating hardlink %s -> %s", destPath, linkDst) if err := os.Link(linkDst, destPath); err != nil { diff --git a/pkg/warmer/lock.go b/pkg/warmer/lock.go index 2fe459baa..bec57dda6 100644 --- a/pkg/warmer/lock.go +++ b/pkg/warmer/lock.go @@ -31,7 +31,7 @@ import ( const warmerLockDir = ".warmer-locks" // acquireCacheLock takes an exclusive flock on cacheDir/.warmer-locks/.lock -// and returns a cacheLock. It is used by warmToFile and ociWarmToFile to +// and returns a cacheLock. It is used by ociWarmToFile to // serialize the cache write for the same digest across processes sharing // the same cache volume. type cacheLock struct { diff --git a/pkg/warmer/warm.go b/pkg/warmer/warm.go index 243b8738b..14cab5dac 100644 --- a/pkg/warmer/warm.go +++ b/pkg/warmer/warm.go @@ -59,21 +59,11 @@ func WarmCache(opts *config.WarmerOptions) error { logrus.Debugf("%s\n", images) errs := 0 - if config.EnvBoolDefault("FF_KANIKO_OCI_WARMER", true) { - for _, img := range images { - err := ociWarmToFile(cacheDir, img, opts) - if err != nil { - logrus.Warnf("Error while trying to warm image: %v %v", img, err) - errs++ - } - } - } else { - for _, img := range images { - err := warmToFile(cacheDir, img, opts) - if err != nil { - logrus.Warnf("Error while trying to warm image: %v %v", img, err) - errs++ - } + for _, img := range images { + err := ociWarmToFile(cacheDir, img, opts) + if err != nil { + logrus.Warnf("Error while trying to warm image: %v %v", img, err) + errs++ } } @@ -84,78 +74,6 @@ func WarmCache(opts *config.WarmerOptions) error { return nil } -// Download image in temporary files then move files to final destination -func warmToFile(cacheDir, img string, opts *config.WarmerOptions) error { - f, err := os.CreateTemp(cacheDir, "warmingImage.*") - if err != nil { - return err - } - // defer called in reverse order - defer os.Remove(f.Name()) - defer f.Close() - - mtfsFile, err := os.CreateTemp(cacheDir, "warmingManifest.*") - if err != nil { - return err - } - defer os.Remove(mtfsFile.Name()) - defer mtfsFile.Close() - - cw := &Warmer{ - Remote: remote.RetrieveRemoteImage, - Local: cache.LocalSource, - TarWriter: f, - ManifestWriter: mtfsFile, - } - - cacheRef, image, digest, err := cw.Resolve(img, opts) - if err != nil { - if cache.IsAlreadyCached(err) { - logrus.Infof("Image already in cache: %v", img) - return nil - } - logrus.Warnf("Error while trying to warm image: %v %v", img, err) - return err - } - - finalCachePath := path.Join(cacheDir, digest.String()) - finalMfstPath := finalCachePath + ".json" - - if config.EnvBoolDefault("FF_KANIKO_WARMER_CACHE_LOCK", true) { - lock, err := acquireCacheLock(cacheDir, digest.String()) - if err != nil { - return fmt.Errorf("failed to acquire cache lock: %w", err) - } - defer lock.Release() - - _, lookupErr := cw.Local(&opts.CacheOptions, digest.String()) - if lookupErr == nil || cache.IsExpired(lookupErr) { - logrus.Infof("Image %v became available in cache while waiting for lock; keeping existing copy", img) - return nil - } - _ = os.RemoveAll(finalCachePath) - _ = os.Remove(finalMfstPath) - } - - if err := cw.Write(cacheRef, image); err != nil { - logrus.Warnf("Error while trying to warm image: %v %v", img, err) - return err - } - - err = os.Rename(f.Name(), finalCachePath) - if err != nil { - return err - } - - err = os.Rename(mtfsFile.Name(), finalMfstPath) - if err != nil { - return fmt.Errorf("failed to rename manifest file: %w", err) - } - - logrus.Debugf("Wrote %s to cache", img) - return nil -} - // Download image in temporary files then move files to final destination func ociWarmToFile(cacheDir, img string, opts *config.WarmerOptions) error { tmp, err := os.MkdirTemp(cacheDir, "") @@ -182,23 +100,21 @@ func ociWarmToFile(cacheDir, img string, opts *config.WarmerOptions) error { finalCachePath := path.Join(cacheDir, digest.String()) - if config.EnvBoolDefault("FF_KANIKO_WARMER_CACHE_LOCK", true) { - lock, err := acquireCacheLock(cacheDir, digest.String()) - if err != nil { - return fmt.Errorf("failed to acquire cache lock: %w", err) - } - defer lock.Release() + lock, err := acquireCacheLock(cacheDir, digest.String()) + if err != nil { + return fmt.Errorf("failed to acquire cache lock: %w", err) + } + defer lock.Release() - _, lookupErr := cw.Local(&opts.CacheOptions, digest.String()) - if lookupErr == nil || cache.IsExpired(lookupErr) { - logrus.Infof("Image %v became available in cache while waiting for lock; keeping existing copy", img) - return nil - } - _ = os.RemoveAll(finalCachePath) - // mz364: finalCachePath+".json" is the legacy tarball manifest sidecar. - // Drop this once the tarball cache format is removed (FF_KANIKO_OCI_WARMER deprecated) - _ = os.Remove(finalCachePath + ".json") + _, lookupErr := cw.Local(&opts.CacheOptions, digest.String()) + if lookupErr == nil || cache.IsExpired(lookupErr) { + logrus.Infof("Image %v became available in cache while waiting for lock; keeping existing copy", img) + return nil } + _ = os.RemoveAll(finalCachePath) + // mz364: finalCachePath+".json" is the legacy tarball manifest sidecar. + // Drop this once the tarball cache format is removed (FF_KANIKO_OCI_WARMER deprecated) + _ = os.Remove(finalCachePath + ".json") if err := cw.Write(cacheRef, image); err != nil { logrus.Warnf("Error while trying to warm image: %v %v", img, err)