From 7f45b51946272fca41bd91f520e264c0c798280a Mon Sep 17 00:00:00 2001 From: Siddharth Sharma Date: Tue, 9 Jun 2026 14:28:06 -0400 Subject: [PATCH] fix: add --base-image-release CLI override and disable it for open network mode Base image release requires hermetic builds, so when update_golang runs with --network-mode open, the build would fail at the base image release step. This adds a --base-image-release/--no-base-image-release flag to doozer's beta:images:konflux:build command and wires update_golang to pass --no-base-image-release when network_mode is open. Co-Authored-By: Claude Opus 4.6 rh-pre-commit.version: 2.4.0 rh-pre-commit.check-secrets: ENABLED --- doozer/doozerlib/cli/images_konflux.py | 8 +++++++ doozer/doozerlib/image.py | 5 ++++ doozer/doozerlib/runtime.py | 1 + doozer/tests/test_image.py | 28 ++++++++++++++++++++++ pyartcd/pyartcd/pipelines/update_golang.py | 3 +++ 5 files changed, 45 insertions(+) diff --git a/doozer/doozerlib/cli/images_konflux.py b/doozer/doozerlib/cli/images_konflux.py index ef90a2ec9f..7037a232e5 100644 --- a/doozer/doozerlib/cli/images_konflux.py +++ b/doozer/doozerlib/cli/images_konflux.py @@ -412,6 +412,11 @@ async def run(self): is_flag=True, help='Skip enterprise-contract verification after builds.', ) +@click.option( + '--base-image-release/--no-base-image-release', + default=None, + help='Override base image release trigger. Takes precedence over image and group config settings.', +) @pass_runtime @click_coroutine async def images_konflux_build( @@ -427,9 +432,12 @@ async def images_konflux_build( build_priority: Optional[str], network_mode: Optional[str], skip_ec_verify: bool, + base_image_release: Optional[bool], ): if network_mode: runtime.network_mode_override = network_mode + if base_image_release is not None: + runtime.base_image_release_override = base_image_release cli = KonfluxBuildCli( runtime=runtime, diff --git a/doozer/doozerlib/image.py b/doozer/doozerlib/image.py index 5fd3e75f0b..08688168d7 100644 --- a/doozer/doozerlib/image.py +++ b/doozer/doozerlib/image.py @@ -1412,6 +1412,11 @@ def should_trigger_base_image_release(self) -> bool: if self.runtime.variant is BuildVariant.OKD: return False + base_image_release_override = getattr(self.runtime, "base_image_release_override", None) + if base_image_release_override is not None: + self.logger.info(f"Base image release override from CLI: {base_image_release_override}") + return base_image_release_override + base_image_release_force_override = self.config.base_image_release.force if base_image_release_force_override not in [Missing, None] and bool(base_image_release_force_override): self.logger.info("Base image release force enabled from metadata config True") diff --git a/doozer/doozerlib/runtime.py b/doozer/doozerlib/runtime.py index 861b7ed436..daee4e3775 100644 --- a/doozer/doozerlib/runtime.py +++ b/doozer/doozerlib/runtime.py @@ -161,6 +161,7 @@ def __init__(self, **kwargs): self.variant = BuildVariant(self.variant.lower()) self.network_mode_override = None + self.base_image_release_override = None if self.latest_parent_version: self.ignore_missing_base = True diff --git a/doozer/tests/test_image.py b/doozer/tests/test_image.py index 832ce2a6b7..4bfd876d1b 100644 --- a/doozer/tests/test_image.py +++ b/doozer/tests/test_image.py @@ -1784,6 +1784,7 @@ def test_should_trigger_base_image_release(self): runtime.assembly = 'stream' runtime.product = 'ocp' runtime.group_config = Model({}) + runtime.base_image_release_override = None # Test base image - should trigger workflow base_image = Model({'name': 'test-base', 'base_only': True}) @@ -1804,6 +1805,7 @@ def test_should_trigger_base_image_release(self): test_assembly_runtime.assembly = 'test' test_assembly_runtime.product = 'ocp' test_assembly_runtime.group_config = Model({}) + test_assembly_runtime.base_image_release_override = None self.assertFalse(ImageMetadata(test_assembly_runtime, base_data).should_trigger_base_image_release()) self.assertFalse(ImageMetadata(test_assembly_runtime, golang_data).should_trigger_base_image_release()) @@ -1814,6 +1816,7 @@ def test_should_trigger_base_image_release(self): named_runtime.assembly = '4.17.1' named_runtime.product = 'ocp' named_runtime.group_config = Model({}) + named_runtime.base_image_release_override = None self.assertTrue(ImageMetadata(named_runtime, base_data).should_trigger_base_image_release()) self.assertTrue(ImageMetadata(named_runtime, golang_data).should_trigger_base_image_release()) @@ -1870,6 +1873,7 @@ def test_should_trigger_base_image_release(self): runtime_group_off.assembly = 'stream' runtime_group_off.product = 'ocp' runtime_group_off.group_config = Model({'base_image_release': Model({'enabled': False})}) + runtime_group_off.base_image_release_override = None group_off_base = Model({'name': 'g-off-base', 'base_only': True}) group_off_data = Model({'key': 'g-off-base', 'data': group_off_base, 'filename': 'g-off-base.yaml'}) group_off_metadata = ImageMetadata(runtime_group_off, group_off_data) @@ -1882,6 +1886,7 @@ def test_should_trigger_base_image_release(self): runtime_both.assembly = 'stream' runtime_both.product = 'ocp' runtime_both.group_config = Model({'base_image_release': Model({'enabled': False})}) + runtime_both.base_image_release_override = None base_override = Model( { 'name': 'override-base', @@ -1900,6 +1905,7 @@ def test_should_trigger_base_image_release(self): layered_runtime.assembly = 'stream' layered_runtime.product = 'rhmtc' layered_runtime.group_config = Model({}) + layered_runtime.base_image_release_override = None self.assertTrue(ImageMetadata(layered_runtime, base_data).should_trigger_base_image_release()) self.assertTrue(ImageMetadata(layered_runtime, golang_data).should_trigger_base_image_release()) @@ -1929,6 +1935,7 @@ def test_should_trigger_base_image_release(self): test_assembly_forced_runtime.assembly = 'test' test_assembly_forced_runtime.product = 'ocp' test_assembly_forced_runtime.group_config = Model({}) + test_assembly_forced_runtime.base_image_release_override = None test_assembly_forced = Model({'name': 'test-regular', 'base_image_release': Model({'force': True})}) test_assembly_forced_metadata = ImageMetadata( test_assembly_forced_runtime, @@ -1936,6 +1943,27 @@ def test_should_trigger_base_image_release(self): ) self.assertTrue(test_assembly_forced_metadata.should_trigger_base_image_release()) + # CLI override: base_image_release_override=False disables for base images + override_off_runtime = MagicMock() + override_off_runtime.logger = logging.getLogger('test_runtime') + override_off_runtime.variant = BuildVariant.OCP + override_off_runtime.assembly = 'stream' + override_off_runtime.product = 'ocp' + override_off_runtime.group_config = Model({}) + override_off_runtime.base_image_release_override = False + self.assertFalse(ImageMetadata(override_off_runtime, base_data).should_trigger_base_image_release()) + self.assertFalse(ImageMetadata(override_off_runtime, golang_data).should_trigger_base_image_release()) + + # CLI override: base_image_release_override=True enables even when group config disables + override_on_runtime = MagicMock() + override_on_runtime.logger = logging.getLogger('test_runtime') + override_on_runtime.variant = BuildVariant.OCP + override_on_runtime.assembly = 'stream' + override_on_runtime.product = 'ocp' + override_on_runtime.group_config = Model({'base_image_release': Model({'enabled': False})}) + override_on_runtime.base_image_release_override = True + self.assertTrue(ImageMetadata(override_on_runtime, base_data).should_trigger_base_image_release()) + def test_base_image_release_quay_fallback_image_overrides_group(self): from artcommonlib.model import Model diff --git a/pyartcd/pyartcd/pipelines/update_golang.py b/pyartcd/pyartcd/pipelines/update_golang.py index bd1021217f..683b45618d 100644 --- a/pyartcd/pyartcd/pipelines/update_golang.py +++ b/pyartcd/pyartcd/pipelines/update_golang.py @@ -932,6 +932,9 @@ async def _build_konflux(self, el_v, go_version): cmd.extend(['--konflux-kubeconfig', self.kubeconfig]) if self.network_mode: cmd.extend(["--network-mode", self.network_mode]) + if self.network_mode == "open": + # Base image release currently requires hermetic builds; this may change in the future + cmd.append("--no-base-image-release") if self.dry_run: cmd.append("--dry-run") await exectools.cmd_assert_async(cmd, env=self._doozer_env_vars, log_stdout=True)