From 1ff8c57dd7ef3bd669163800eb815b18401360d3 Mon Sep 17 00:00:00 2001 From: afonso pinto Date: Thu, 15 Oct 2026 20:05:08 +0100 Subject: [PATCH 1/2] CH-297 Handle missing registry Secrets in generated workflows --- .../cloudharness/utils/config.py | 5 ++- .../cloudharness/workflows/operations.py | 5 ++- .../tests/test_workflow.py | 40 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/libraries/cloudharness-common/cloudharness/utils/config.py b/libraries/cloudharness-common/cloudharness/utils/config.py index 4fdc83249..c6d120994 100644 --- a/libraries/cloudharness-common/cloudharness/utils/config.py +++ b/libraries/cloudharness-common/cloudharness/utils/config.py @@ -70,7 +70,10 @@ def get_registry_name(cls): @classmethod def get_registry_secret(cls): - return cls.get_configuration()['registry'].get('secret', {}).get('name', '') + secret = cls.get_configuration()['registry'].get('secret') or {} + if not isinstance(secret, dict): + return '' + return secret.get('name') or '' @classmethod def is_secured(cls): diff --git a/libraries/cloudharness-common/cloudharness/workflows/operations.py b/libraries/cloudharness-common/cloudharness/workflows/operations.py index dbc3886e9..1d9ce709e 100644 --- a/libraries/cloudharness-common/cloudharness/workflows/operations.py +++ b/libraries/cloudharness-common/cloudharness/workflows/operations.py @@ -120,13 +120,13 @@ def to_workflow(self, **arguments): } def spec(self): + registry_secret = config.CloudharnessConfig.get_registry_secret() spec = { 'entrypoint': self.entrypoint, 'ttlStrategy': self.ttl_strategy, 'templates': [self.modify_template(template) for template in self.templates], 'tolerations': [V1Toleration(key='cloudharness/temporary-job', operator='Equal', value='true').to_dict()], 'serviceAccountName': SERVICE_ACCOUNT, - 'imagePullSecrets': [{'name': config.CloudharnessConfig.get_registry_secret()}], 'podGC': self.pod_gc or { 'strategy': 'OnWorkflowSuccess', 'deleteDelayDuration': self.ttl_strategy['secondsAfterSuccess'] if self.ttl_strategy else "600s", @@ -140,6 +140,9 @@ def spec(self): }] } + if registry_secret: + spec['imagePullSecrets'] = [{'name': registry_secret}] + if is_accounts_present(): spec['volumes'].append({ 'name': 'cloudharness-kc-accounts', diff --git a/libraries/cloudharness-common/tests/test_workflow.py b/libraries/cloudharness-common/tests/test_workflow.py index 83eddb8e8..37fa27d92 100644 --- a/libraries/cloudharness-common/tests/test_workflow.py +++ b/libraries/cloudharness-common/tests/test_workflow.py @@ -1,4 +1,8 @@ """Notice, this test needs a fully operating kubernetes with argo environment in the container running the test""" +from unittest.mock import patch + +import pytest + from cloudharness.utils.config import CloudharnessConfig from cloudharness.workflows import argo_service from cloudharness import set_debug @@ -26,6 +30,42 @@ def check_wf(wf): assert "spec" in wf +@pytest.mark.parametrize('secret', [None, {}, {'name': ''}, {'name': None}, '']) +def test_unconfigured_registry_secret(secret): + with patch.object( + CloudharnessConfig, 'get_configuration', + return_value={'registry': {'secret': secret}}, + ): + assert CloudharnessConfig.get_registry_secret() == '' + + +def test_missing_registry_secret(): + with patch.object(CloudharnessConfig, 'get_configuration', return_value={'registry': {}}): + assert CloudharnessConfig.get_registry_secret() == '' + + +def test_configured_registry_secret(): + with patch.object( + CloudharnessConfig, 'get_configuration', + return_value={'registry': {'secret': {'name': 'private-registry'}}}, + ): + assert CloudharnessConfig.get_registry_secret() == 'private-registry' + + +@pytest.mark.parametrize('registry_secret', ['', 'private-registry']) +def test_workflow_optional_image_pull_secret(registry_secret): + task = tasks.CustomTask('registry-task', 'busybox') + operation = operations.SingleTaskOperation('registry-operation-', task) + + with patch.object(CloudharnessConfig, 'get_registry_secret', return_value=registry_secret): + workflow = operation.to_workflow() + + if registry_secret: + assert workflow['spec']['imagePullSecrets'] == [{'name': registry_secret}] + else: + assert 'imagePullSecrets' not in workflow['spec'] + + def test_volume_affinity_check(): assert not utils.volume_requires_affinity("a") assert utils.volume_requires_affinity("a:b") From 64ae2cac425a3d36d393cd2b5e38abae24ccebcb Mon Sep 17 00:00:00 2001 From: afonso pinto Date: Thu, 15 Oct 2026 23:33:29 +0100 Subject: [PATCH 2/2] CH-297 Fix spacing between deployment CLI tests --- tools/deployment-cli-tools/tests/test_helm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/deployment-cli-tools/tests/test_helm.py b/tools/deployment-cli-tools/tests/test_helm.py index 3b28c3959..7ed243704 100644 --- a/tools/deployment-cli-tools/tests/test_helm.py +++ b/tools/deployment-cli-tools/tests/test_helm.py @@ -1704,6 +1704,8 @@ def test_find_chart_images_resolves_empty_tag_from_app_version(): assert find_chart_images({'image': {'repository': 'a/b', 'tag': ''}}) == [ ChartImageRef(path=('image',), value={'repository': 'a/b'}), ] + + def test_instances_expand_into_applications(tmp_path): """An instance is deployed as an application of its own, inheriting the parent's configuration.""" out_folder = tmp_path / 'test_instances_expand_into_applications'