mirror of
https://github.com/containers/buildah.git
synced 2026-10-23 06:48:59 +03:00
updating the incorrect resetting logic for multi-stage builds
fixes : https://github.com/podman-container-tools/podman/issues/29633 Signed-off-by: Himanshu Ravindra Iwanati <work.himanshu.r.v@gmail.com>
This commit is contained in:
@@ -1130,18 +1130,35 @@ func (s *stageExecutor) prepare(ctx context.Context, from string, initializeIBCo
|
||||
// In a multi-stage build where `FROM --platform=<>` was used then we must
|
||||
// reset context for new stages so that new stages don't inherit unexpected
|
||||
// `--platform` from prior stages.
|
||||
if stage.Builder.Platform != "" || (len(s.stages) > 1 && (s.systemContext.ArchitectureChoice == "" && s.systemContext.VariantChoice == "" && s.systemContext.OSChoice == "")) {
|
||||
imageOS, imageArch, imageVariant, err := parse.Platform(stage.Builder.Platform)
|
||||
effectivePlatform := stage.Builder.Platform
|
||||
if effectivePlatform == "" &&
|
||||
len(s.stages) > 1 &&
|
||||
s.systemContext.ArchitectureChoice == "" &&
|
||||
s.systemContext.VariantChoice == "" &&
|
||||
s.systemContext.OSChoice == "" {
|
||||
for _, prevStage := range s.stages[:s.index] {
|
||||
if prevStage.Builder.Platform != "" {
|
||||
if s.executor.systemContext.ArchitectureChoice != "" ||
|
||||
s.executor.systemContext.OSChoice != "" ||
|
||||
s.executor.systemContext.VariantChoice != "" {
|
||||
s.systemContext.ArchitectureChoice = s.executor.systemContext.ArchitectureChoice
|
||||
s.systemContext.VariantChoice = s.executor.systemContext.VariantChoice
|
||||
s.systemContext.OSChoice = s.executor.systemContext.OSChoice
|
||||
} else {
|
||||
effectivePlatform = "local"
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if effectivePlatform != "" {
|
||||
imageOS, imageArch, imageVariant, err := parse.Platform(effectivePlatform)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse platform %q: %w", stage.Builder.Platform, err)
|
||||
}
|
||||
if imageArch != "" || imageVariant != "" {
|
||||
s.systemContext.ArchitectureChoice = imageArch
|
||||
s.systemContext.VariantChoice = imageVariant
|
||||
}
|
||||
if imageOS != "" {
|
||||
s.systemContext.OSChoice = imageOS
|
||||
return nil, fmt.Errorf("unable to parse platform %q: %w", effectivePlatform, err)
|
||||
}
|
||||
s.systemContext.ArchitectureChoice = imageArch
|
||||
s.systemContext.VariantChoice = imageVariant
|
||||
s.systemContext.OSChoice = imageOS
|
||||
}
|
||||
|
||||
builderOptions := buildah.BuilderOptions{
|
||||
|
||||
@@ -11116,3 +11116,89 @@ EOF
|
||||
|
||||
run_buildah build --pull=false --no-cache --jobs=2 --skip-unused-stages=false $WITH_POLICY_JSON $contextdir
|
||||
}
|
||||
|
||||
@test "bud multi-stage build preserves architecture of local external images" {
|
||||
# This tests that stages without a --platform flag are NOT aggressively
|
||||
# reset to the host architecture. It ensures Buildah does not strict-match
|
||||
# and crash when trying to resolve local images of a foreign architecture.
|
||||
|
||||
run_buildah info --format '{{.host.arch}}'
|
||||
host_arch="$output"
|
||||
|
||||
# Select a foreign test architecture + variant
|
||||
test_arch="arm"
|
||||
test_variant="v7"
|
||||
if [[ "$host_arch" == "arm" ]]; then
|
||||
test_arch="arm64"
|
||||
test_variant="v8"
|
||||
fi
|
||||
|
||||
local contextdir="${TEST_SCRATCH_DIR}/multi-stage-variant"
|
||||
mkdir -p "$contextdir"
|
||||
|
||||
# 1. Build an external local image with a foreign architecture
|
||||
cat > "$contextdir/Dockerfile.base" << EOF
|
||||
FROM busybox
|
||||
ENV STAGE=base
|
||||
EOF
|
||||
run_buildah build $WITH_POLICY_JSON --platform=linux/${test_arch}/${test_variant} -t local-cross-builder -f "$contextdir/Dockerfile.base" "$contextdir"
|
||||
|
||||
# 2. Main Dockerfile
|
||||
cat > "$contextdir/Dockerfile" << EOF
|
||||
ARG BASE=local-cross-builder
|
||||
|
||||
# Stage 1: Exists purely to test multi-stage behavior with local
|
||||
FROM alpine AS stage1
|
||||
|
||||
# Stage 2: Uses the local foreign image without a --platform flag.
|
||||
# This should leave the context empty and successfully accept the local foreign image.
|
||||
FROM \${BASE} AS final
|
||||
ENV STAGE=final
|
||||
EOF
|
||||
|
||||
# 3. Build the multi-stage image.
|
||||
run_buildah build $WITH_POLICY_JSON --target final -t test-final "$contextdir"
|
||||
|
||||
# 4. Verify the final image successfully retained the exact foreign architecture and variant.
|
||||
run_buildah inspect --format '{{.OCIv1.Architecture}}' test-final
|
||||
expect_output "${test_arch}"
|
||||
}
|
||||
|
||||
@test "bud multi-stage build does not re-pull and overwrite local image" {
|
||||
_prefetch alpine
|
||||
start_registry
|
||||
local authfile="${TEST_SCRATCH_DIR}/test.auth"
|
||||
run_buildah login --tls-verify=false --authfile "$authfile" --username testuser --password testpassword "localhost:${REGISTRY_PORT}"
|
||||
|
||||
local registry="localhost:${REGISTRY_PORT}"
|
||||
local contextdir="${TEST_SCRATCH_DIR}/re-pull-local"
|
||||
mkdir -p "$contextdir"
|
||||
|
||||
# Build an image without the test file and push it to the registry
|
||||
cat > "$contextdir/Dockerfile.remote" << _EOF
|
||||
FROM alpine
|
||||
RUN echo "remote-version" > /version.txt
|
||||
_EOF
|
||||
run_buildah build $WITH_POLICY_JSON -t "${registry}/local-override:latest" -f "$contextdir/Dockerfile.remote" "$contextdir"
|
||||
run_buildah push --authfile "$authfile" --tls-verify=false "${registry}/local-override:latest" "docker://${registry}/local-override:latest"
|
||||
|
||||
# Modify and rebuild the image locally with a local-only file (do not push!)
|
||||
cat > "$contextdir/Dockerfile.local" << _EOF
|
||||
FROM alpine
|
||||
RUN echo "local-version" > /version.txt
|
||||
RUN echo "local-only" > /local-file.txt
|
||||
_EOF
|
||||
run_buildah build $WITH_POLICY_JSON -t "${registry}/local-override:latest" -f "$contextdir/Dockerfile.local" "$contextdir"
|
||||
|
||||
# Multi-stage build that references the local image in stage 1
|
||||
cat > "$contextdir/Dockerfile.multistage" << _EOF
|
||||
FROM ${registry}/local-override:latest AS stage1
|
||||
FROM alpine
|
||||
COPY --from=stage1 /local-file.txt /local-file.txt
|
||||
RUN cat /local-file.txt
|
||||
_EOF
|
||||
|
||||
# Build must succeed using the local image without re-pulling from the registry
|
||||
run_buildah build --authfile "$authfile" --tls-verify=false -f "$contextdir/Dockerfile.multistage" "$contextdir"
|
||||
expect_output --substring "local-only"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user