diff --git a/imagebuildah/executor.go b/imagebuildah/executor.go index f479eea7398..a3cbc1c3400 100644 --- a/imagebuildah/executor.go +++ b/imagebuildah/executor.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "os" + "regexp" "slices" "strconv" "strings" @@ -519,6 +520,12 @@ func (b *Executor) getImageTypeAndHistoryAndDiffIDs(ctx context.Context, imageID return oci.OS, oci.Architecture, manifestFormat, oci.History, oci.RootFS.DiffIDs, nil } +// Checks if is word is using any variable in the form of `$VAR`, `${VAR}` etc +func containsVariable(arg string) bool { + re := regexp.MustCompile(`\$\{?[a-zA-Z_][a-zA-Z0-9_]*\}?`) + return re.MatchString(arg) +} + func (b *Executor) buildStage(ctx context.Context, cleanupStages map[int]*StageExecutor, stages imagebuilder.Stages, stageIndex int) (imageID string, ref reference.Canonical, onlyBaseImage bool, err error) { stage := stages[stageIndex] ib := stage.Builder @@ -600,7 +607,26 @@ func (b *Executor) buildStage(ctx context.Context, cleanupStages map[int]*StageE prefix += ": " } suffix := "\n" - fmt.Fprintf(stageExecutor.executor.out, prefix+format+suffix, args...) + builtinArgs := argsMapToSlice(stage.Builder.BuiltinArgDefaults) + headingArgs := argsMapToSlice(stage.Builder.HeadingArgs) + userArgs := argsMapToSlice(stage.Builder.Args) + userArgs = append(builtinArgs, append(userArgs, headingArgs...)...) + processedArgs := make([]any, 0, len(args)) + for i := range args { + if arg, ok := args[i].(string); ok { + if containsVariable(arg) { + processedArg, err := imagebuilder.ProcessWord(arg, userArgs) + if err != nil { + processedArg = arg + fmt.Fprintf(stageExecutor.executor.err, "while replacing arg variables with values for format in logging %q: %v\n", arg, err) + } + processedArgs = append(processedArgs, processedArg) + } else { + processedArgs = append(processedArgs, arg) + } + } + } + fmt.Fprintf(stageExecutor.executor.out, prefix+format+suffix, processedArgs...) } } b.stagesLock.Unlock() diff --git a/tests/bud.bats b/tests/bud.bats index d0c10e79687..fa749fa1a18 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -5425,10 +5425,11 @@ EOM ${OCI} --version _prefetch alpine busybox - - run_buildah build --build-arg base=alpine --build-arg toolchainname=busybox --build-arg destinationpath=/tmp --pull=false $WITH_POLICY_JSON -f $BUDFILES/from-with-arg/Containerfile . + toolchainname=busybox + destinationpath=/tmp + run_buildah build --build-arg base=alpine --build-arg toolchainname=$toolchainname --build-arg destinationpath=$destinationpath --pull=false $WITH_POLICY_JSON -f $BUDFILES/from-with-arg/Containerfile . expect_output --substring "FROM alpine" - expect_output --substring 'STEP 4/4: COPY --from=\$\{toolchainname\} \/ \$\{destinationpath\}' + expect_output --substring "STEP 4/4: COPY --from=$toolchainname \/ $destinationpath" run_buildah rm -a } @@ -6186,7 +6187,7 @@ _EOF # must push cache twice i.e for first step and second step run printf "STEP 2/3: ARG VAR=hello\n--> Pushing cache" step1=$output - run printf "STEP 3/3: RUN echo \"Hello \$VAR\"" + run printf "STEP 3/3: RUN echo \"Hello hello\"" step2=$output run printf "Hello hello" step3=$output @@ -8874,3 +8875,42 @@ _EOF run_buildah --root=${TEST_SCRATCH_DIR}/newroot --storage-opt=imagestore=${TEST_SCRATCH_DIR}/root build --pull=never ${contextdir} run_buildah --root=${TEST_SCRATCH_DIR}/newroot --storage-opt=imagestore=${TEST_SCRATCH_DIR}/root build --pull=never --squash ${contextdir} } + +@test "bud build argument expansion in log" { + _prefetch alpine + target=build-arg-expand-log + + # Test basic build argument expansion + run_buildah build $WITH_POLICY_JSON -t ${target} --build-arg foo=foovalue -f $BUDFILES/build-arg/Dockerfile $BUDFILES/build-arg + expect_output --substring "RUN echo foovalue" + + # Test with a more complex build argument + run_buildah build $WITH_POLICY_JSON -t ${target}-complex --build-arg foo="/usr/local/bin" -f $BUDFILES/build-arg/Dockerfile $BUDFILES/build-arg + expect_output --substring "RUN echo /usr/local/bin" + + # Test with multiple build arguments + contextdir=${TEST_SCRATCH_DIR}/build-arg-expansion + mkdir -p $contextdir + + cat > $contextdir/Containerfile << _EOF +FROM alpine +ARG NEWROOT +ARG PREFIX +RUN mkdir \$NEWROOT +RUN echo \$PREFIX/bin +_EOF + + run_buildah build $WITH_POLICY_JSON -t ${target}-multi --build-arg NEWROOT=/new-root-fs --build-arg PREFIX=/usr $contextdir + expect_output --substring "RUN mkdir /new-root-fs" + expect_output --substring "RUN echo /usr/bin" + + # Test that unexpanded variables show as empty when no build-arg is provided + cat > $contextdir/Containerfile2 << _EOF +FROM alpine +ARG UNDEFINEDVAR +RUN echo \$UNDEFINEDVAR hello +_EOF + + run_buildah build $WITH_POLICY_JSON -t ${target}-undefined -f $contextdir/Containerfile2 $contextdir + expect_output --substring "RUN echo hello" +}