diff --git a/pkg/dockerfile/buildargs.go b/pkg/dockerfile/buildargs.go index fbd2ad8401..bbb5cebdd2 100644 --- a/pkg/dockerfile/buildargs.go +++ b/pkg/dockerfile/buildargs.go @@ -51,8 +51,11 @@ func (b *BuildArgs) Clone() *BuildArgs { // ReplacementEnvs returns a list of filtered environment variables func (b *BuildArgs) ReplacementEnvs(envs []string) []string { + // Ensure that we operate on a new array and do not modify the underlying array + resultEnv := make([]string, len(envs)) + copy(resultEnv, envs) filtered := b.FilterAllowed(envs) - return append(envs, filtered...) + return append(resultEnv, filtered...) } // AddMetaArgs adds the supplied args map to b's allowedMetaArgs diff --git a/pkg/executor/build.go b/pkg/executor/build.go index 995c67376a..8284393866 100644 --- a/pkg/executor/build.go +++ b/pkg/executor/build.go @@ -21,6 +21,7 @@ import ( "os" "path/filepath" "runtime" + "sort" "strconv" "strings" "time" @@ -181,6 +182,9 @@ func initConfig(img partial.WithConfigFile, opts *config.KanikoOptions) (*v1.Con func (s *stageBuilder) populateCompositeKey(command fmt.Stringer, files []string, compositeKey CompositeCache, args *dockerfile.BuildArgs, env []string) (CompositeCache, error) { // First replace all the environment variables or args in the command replacementEnvs := args.ReplacementEnvs(env) + // The sort order of `replacementEnvs` is basically undefined, sort it + // so we can ensure a stable cache key. + sort.Strings(replacementEnvs) resolvedCmd, err := util.ResolveEnvironmentReplacement(command.String(), replacementEnvs, false) if err != nil { return compositeKey, err @@ -227,6 +231,11 @@ func (s *stageBuilder) optimize(compositeKey CompositeCache, cfg v1.Config) erro if !s.opts.Cache { return nil } + var buildArgs = s.args.Clone() + // Restore build args back to their original values + defer func() { + s.args = buildArgs + }() stopCache := false // Possibly replace commands with their cached implementations.