This is an automated email from the ASF dual-hosted git repository. vatsrahul1001 pushed a commit to branch v3-4-test in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 1547f1f131b91db9c3d29a7b3e53fcc5c7383602 Author: Shahar Epstein <[email protected]> AuthorDate: Sat Nov 7 17:13:21 2026 +0200 [v3-4-test] Explain a BASE_IMAGE without Python in hardened image builds (#76645) (#76659) Passing a plain Debian BASE_IMAGE to the default hardened flavor stops the build with "python3: command not found", which does not say what to change. dev/breeze/tests/test_os_deps_images.py does not exist on this branch, and the rest of it on main tests code that was not backported, so it holds only the new test here. The script reaches the check using bash builtins alone, so the tool stubs the test has on main are not needed. (cherry picked from commit 2adbce7e7b2609c1d0c28b9363b50558ae3f7d80) Claude-Session: https://claude.ai/code/session_01BVx6g8K9pmgvCdYRrKCGPk Co-authored-by: Jarek Potiuk <[email protected]> --- Dockerfile | 7 ++++++ Dockerfile.ci | 7 ++++++ dev/breeze/tests/test_os_deps_images.py | 39 +++++++++++++++++++++++++++++++ docker-stack-docs/build-arg-ref.rst | 3 +++ scripts/docker/install_os_dependencies.sh | 7 ++++++ 5 files changed, 63 insertions(+) diff --git a/Dockerfile b/Dockerfile index 40d7146d847..6388c95857f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -135,6 +135,13 @@ AIRFLOW_IMAGE_FLAVOR=${AIRFLOW_IMAGE_FLAVOR:-hardened} AIRFLOW_PYTHON_VERSION=${AIRFLOW_PYTHON_VERSION:-} COSIGN_VERSION=${COSIGN_VERSION:-3.0.5} if [[ "${AIRFLOW_IMAGE_FLAVOR}" == "hardened" ]]; then + if ! command -v python3 >/dev/null; then + echo + echo "ERROR! The hardened flavor takes Python from BASE_IMAGE, but this base image has no python3." + echo "Pick a BASE_IMAGE with Python, or set AIRFLOW_IMAGE_FLAVOR to 'legacy' to build on a plain Debian image." + echo + exit 1 + fi # The Debian 12 hardened images ship Python under /opt/python, the Debian 13 ones install it as # Debian packages under /usr - so ask the base image's Python where it lives. PYTHON_HOME=${PYTHON_HOME:-$(python3 -c 'import sys; print(sys.base_prefix)')} diff --git a/Dockerfile.ci b/Dockerfile.ci index 283d9c5d7de..01ca2e3ed84 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -66,6 +66,13 @@ AIRFLOW_IMAGE_FLAVOR=${AIRFLOW_IMAGE_FLAVOR:-hardened} AIRFLOW_PYTHON_VERSION=${AIRFLOW_PYTHON_VERSION:-} COSIGN_VERSION=${COSIGN_VERSION:-3.0.5} if [[ "${AIRFLOW_IMAGE_FLAVOR}" == "hardened" ]]; then + if ! command -v python3 >/dev/null; then + echo + echo "ERROR! The hardened flavor takes Python from BASE_IMAGE, but this base image has no python3." + echo "Pick a BASE_IMAGE with Python, or set AIRFLOW_IMAGE_FLAVOR to 'legacy' to build on a plain Debian image." + echo + exit 1 + fi # The Debian 12 hardened images ship Python under /opt/python, the Debian 13 ones install it as # Debian packages under /usr - so ask the base image's Python where it lives. PYTHON_HOME=${PYTHON_HOME:-$(python3 -c 'import sys; print(sys.base_prefix)')} diff --git a/dev/breeze/tests/test_os_deps_images.py b/dev/breeze/tests/test_os_deps_images.py new file mode 100644 index 00000000000..7e41ef8b8d0 --- /dev/null +++ b/dev/breeze/tests/test_os_deps_images.py @@ -0,0 +1,39 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import shutil +import subprocess + +from airflow_breeze.utils.path_utils import AIRFLOW_ROOT_PATH + + +def test_hardened_flavor_explains_a_base_image_without_python(tmp_path): + result = subprocess.run( + [ + shutil.which("bash"), + AIRFLOW_ROOT_PATH / "scripts" / "docker" / "install_os_dependencies.sh", + "dev", + ], + env={"PATH": str(tmp_path)}, + capture_output=True, + text=True, + check=False, + ) + + assert result.returncode == 1 + assert "AIRFLOW_IMAGE_FLAVOR to 'legacy'" in result.stdout diff --git a/docker-stack-docs/build-arg-ref.rst b/docker-stack-docs/build-arg-ref.rst index 4bb92541a58..5b86b87a000 100644 --- a/docker-stack-docs/build-arg-ref.rst +++ b/docker-stack-docs/build-arg-ref.rst @@ -106,6 +106,9 @@ Python - for Airflow |airflow-version| that is ``ghcr.io/apache/airflow/base/pyt pinned to the digest the Airflow CI last passed on (see :ref:`the hardened base images <image-hardened-base>`). Pulling the mirror needs no credentials; pulling ``dhi.io`` directly requires a ``docker login dhi.io``. +In the default ``hardened`` flavor ``BASE_IMAGE`` has to provide Python, so the build fails on a plain Debian +image such as ``debian:trixie-slim``. Use the ``legacy`` flavor below to build on one. + For the 3.4.x line Airflow also publishes ``legacy`` images, built the way all images were built before 3.4.0: Python is downloaded from python.org, its signature verified and compiled on a ``debian:bookworm-slim`` base. They are deprecated and will be removed in Airflow 3.5.0. To build one yourself, set these arguments: diff --git a/scripts/docker/install_os_dependencies.sh b/scripts/docker/install_os_dependencies.sh index 880b4f208ba..696572137ed 100644 --- a/scripts/docker/install_os_dependencies.sh +++ b/scripts/docker/install_os_dependencies.sh @@ -41,6 +41,13 @@ AIRFLOW_IMAGE_FLAVOR=${AIRFLOW_IMAGE_FLAVOR:-hardened} AIRFLOW_PYTHON_VERSION=${AIRFLOW_PYTHON_VERSION:-} COSIGN_VERSION=${COSIGN_VERSION:-3.0.5} if [[ "${AIRFLOW_IMAGE_FLAVOR}" == "hardened" ]]; then + if ! command -v python3 >/dev/null; then + echo + echo "ERROR! The hardened flavor takes Python from BASE_IMAGE, but this base image has no python3." + echo "Pick a BASE_IMAGE with Python, or set AIRFLOW_IMAGE_FLAVOR to 'legacy' to build on a plain Debian image." + echo + exit 1 + fi # The Debian 12 hardened images ship Python under /opt/python, the Debian 13 ones install it as # Debian packages under /usr - so ask the base image's Python where it lives. PYTHON_HOME=${PYTHON_HOME:-$(python3 -c 'import sys; print(sys.base_prefix)')}
