diff --git a/kp_pre_commit_hooks/gitops_values_validation.py b/kp_pre_commit_hooks/gitops_values_validation.py index f4ef2b2..ca53725 100755 --- a/kp_pre_commit_hooks/gitops_values_validation.py +++ b/kp_pre_commit_hooks/gitops_values_validation.py @@ -41,10 +41,17 @@ re.MULTILINE ) -# Validate topic names follow pattern: (private.)?serviceName.topic(-version)?(.suffix)? +# Matches standard topic names to extract the serviceName for ownership checks. +# Format validation (e.g. enforcing -vN over -N) is the chart schema's responsibility; +# this regexp only needs to match what the schema accepts so the service name check fires correctly. TOPIC_NAME_REGEXP = re.compile( - r"^(private\.)?(?P[a-z][a-z0-9-]*)\.[a-z][a-z0-9-]*(-[0-9]+)?(\.[a-z0-9]+)?$" + r"^(private\.)?(?P[a-z][a-z0-9-]*)\.[a-z][a-z0-9-]*(-v[0-9]+)?(\.[a-z0-9-]+)?$" ) +# Kafka Streams internal topics: {applicationId}-{name}-(changelog|repartition) +KAFKA_STREAMS_INTERNAL_TOPIC_REGEXP = re.compile(r"^[a-z][a-z0-9-]*-(changelog|repartition)$") + +# Matches any Go template block {{ ... }} +TEMPLATE_BLOCK_REGEXP = re.compile(r"\{\{[^}]*\}\}") TWINGATE_DOC_URL = "https://kpler.atlassian.net/wiki/spaces/KSD/pages/243562083/Install+and+configure+the+Twingate+VPN+client" @@ -547,11 +554,53 @@ def validate_service_keys_match_service_folder(self, value, schema): f" Must be either '{folder_name}' or '{folder_name}-'" ) + def _resolve_topic_name_template(self, template: str) -> str: + """Replace known context variables with actual values, others with a placeholder. + + This allows validating the structure of a topicNameTemplate as if it were + a static topicName, by substituting the context variables the chart would + inject at render time. + """ + service_name = self._get_current_service_name() + instance = self.service_instance_config.instance + + replacements = { + "$.context.serviceInstanceName": f"{service_name}-{instance}", + "$.context.serviceName": service_name, + "$.context.instanceName": instance, + "$.context.env": self.service_instance_config.env, + } + + result = template + for var, val in replacements.items(): + result = result.replace(f"{{{{ {var} }}}}", val) + + # Replace remaining unknown template blocks with a generic placeholder + result = TEMPLATE_BLOCK_REGEXP.sub("x", result) + return result + def validate_topic_name_compliance(self, value, schema): + current_path = self._get_current_path() + is_template = current_path and current_path[-1] == "topicNameTemplate" + + topic_name = self._resolve_topic_name_template(str(value)) if is_template else str(value) + + # Kafka Streams internal topics (changelog, repartition) don't follow the serviceName.dataIdentifier convention + # but must start with {serviceName}-{instanceName}- to prevent copy-paste mistakes across instances + if KAFKA_STREAMS_INTERNAL_TOPIC_REGEXP.match(topic_name): + service_name = self._get_current_service_name() + instance = self.service_instance_config.instance + expected_prefix = f"{service_name}-{instance}-" + if not topic_name.startswith(expected_prefix): + yield ValidationError( + f"Internal topic '{topic_name}' is not compliant, " + f"it must start with '{expected_prefix}' (serviceName-instanceName)" + ) + return service_name = self._get_current_service_name() - match = TOPIC_NAME_REGEXP.match(str(value)) + match = TOPIC_NAME_REGEXP.match(topic_name) if match and match["serviceName"] not in (service_name, self.service_instance_config.service_group): - yield ValidationError(f"topicName '{value}' it not compliant, it should contain the service name '{service_name}'") + yield ValidationError(f"topicName '{topic_name}' it not compliant, it should contain the service name '{service_name}'") def validate_max_local_topic_bytes_compliance(self, value, schema): diff --git a/tests/test_data/gitops_data/app1/service1/Chart-dev.yaml b/tests/test_data/gitops_data/app1/service1/Chart-dev.yaml index c585dc8..61f7d10 100644 --- a/tests/test_data/gitops_data/app1/service1/Chart-dev.yaml +++ b/tests/test_data/gitops_data/app1/service1/Chart-dev.yaml @@ -1,3 +1,3 @@ dependencies: - name: platform-managed-chart - version: 0.1.159 + version: 0.1.225 diff --git a/tests/test_data/gitops_data/app1/service1/Chart.yaml b/tests/test_data/gitops_data/app1/service1/Chart.yaml index 11d0afa..c93ef7d 100644 --- a/tests/test_data/gitops_data/app1/service1/Chart.yaml +++ b/tests/test_data/gitops_data/app1/service1/Chart.yaml @@ -3,4 +3,4 @@ name: service1 version: 0.1.0 dependencies: - name: platform-managed-chart - version: 0.1.157-pr195 + version: 0.1.224 diff --git a/tests/test_data/gitops_data/app1/service1/values-dev-hyphenated-suffix.yaml b/tests/test_data/gitops_data/app1/service1/values-dev-hyphenated-suffix.yaml new file mode 100644 index 0000000..dba4134 --- /dev/null +++ b/tests/test_data/gitops_data/app1/service1/values-dev-hyphenated-suffix.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.225/schema-platform-managed-chart.json +# Test file: Standard topic with hyphenated suffix (valid per chart schema) +platform-managed-chart: + serviceName: service1 + teamOwner: team1 + env: dev + workloadType: stream + + stream: {} + + image: + repository: dev/my-repo + tag: my-tag + + managedResources: + mskTopics: + output: + topicName: service1.testtopic.sub-part diff --git a/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_authorized_max_local_topic_bytes.yaml b/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_authorized_max_local_topic_bytes.yaml index 6ead7e9..9442b89 100644 --- a/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_authorized_max_local_topic_bytes.yaml +++ b/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_authorized_max_local_topic_bytes.yaml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.157-pr195/schema-platform-managed-chart.json +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.225/schema-platform-managed-chart.json # Test file: Whitelisted topic with valid size platform-managed-chart: serviceName: service1 diff --git a/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_max_local_topic_bytes_above_authorized_value.yaml b/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_max_local_topic_bytes_above_authorized_value.yaml index ed60d51..85ad125 100644 --- a/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_max_local_topic_bytes_above_authorized_value.yaml +++ b/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_max_local_topic_bytes_above_authorized_value.yaml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.157-pr195/schema-platform-managed-chart.json +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.225/schema-platform-managed-chart.json # Test file: Whitelisted topic exceeding its specific limit platform-managed-chart: serviceName: service1 diff --git a/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_no_max_local_topic_bytes_set.yaml b/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_no_max_local_topic_bytes_set.yaml index a34b0cf..1c1a7e6 100644 --- a/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_no_max_local_topic_bytes_set.yaml +++ b/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_no_max_local_topic_bytes_set.yaml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.157-pr195/schema-platform-managed-chart.json +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.225/schema-platform-managed-chart.json # Test file: Whitelisted topic with valid size platform-managed-chart: serviceName: service1 diff --git a/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_unauthorized_max_local_topic_bytes.yaml b/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_unauthorized_max_local_topic_bytes.yaml index d897ac8..4d9bb56 100644 --- a/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_unauthorized_max_local_topic_bytes.yaml +++ b/tests/test_data/gitops_data/app1/service1/values-dev-topic_with_unauthorized_max_local_topic_bytes.yaml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.157-pr195/schema-platform-managed-chart.json +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.225/schema-platform-managed-chart.json platform-managed-chart: serviceName: service1 teamOwner: team1 diff --git a/tests/test_data/gitops_data/app1/service1/values-dev-versioned-topic.yaml b/tests/test_data/gitops_data/app1/service1/values-dev-versioned-topic.yaml new file mode 100644 index 0000000..32452cf --- /dev/null +++ b/tests/test_data/gitops_data/app1/service1/values-dev-versioned-topic.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.225/schema-platform-managed-chart.json +# Test file: Standard topic with -vN version suffix (valid per chart schema) +platform-managed-chart: + serviceName: service1 + teamOwner: team1 + env: dev + workloadType: stream + + stream: {} + + image: + repository: dev/my-repo + tag: my-tag + + managedResources: + mskTopics: + output: + topicName: service1.testtopic-v2 diff --git a/tests/test_data/gitops_data/app1/service1/values-prod-topic_with_authorized_max_local_topic_bytes_not_on_current_env.yaml b/tests/test_data/gitops_data/app1/service1/values-prod-topic_with_authorized_max_local_topic_bytes_not_on_current_env.yaml index 11bfe5d..b56cd02 100644 --- a/tests/test_data/gitops_data/app1/service1/values-prod-topic_with_authorized_max_local_topic_bytes_not_on_current_env.yaml +++ b/tests/test_data/gitops_data/app1/service1/values-prod-topic_with_authorized_max_local_topic_bytes_not_on_current_env.yaml @@ -1,4 +1,4 @@ -# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.157-pr195/schema-platform-managed-chart.json +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.224/schema-platform-managed-chart.json # Test file: Whitelisted topic with valid size platform-managed-chart: serviceName: service1 diff --git a/tests/test_data/gitops_data/app1/service2/Chart.yaml b/tests/test_data/gitops_data/app1/service2/Chart.yaml new file mode 100644 index 0000000..15ca3c7 --- /dev/null +++ b/tests/test_data/gitops_data/app1/service2/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: service2 +version: 0.1.0 +dependencies: + - name: platform-managed-chart + version: 0.1.223-pr313 diff --git a/tests/test_data/gitops_data/app1/service2/values-dev-topic_with_wrong_service_name.yaml b/tests/test_data/gitops_data/app1/service2/values-dev-topic_with_wrong_service_name.yaml new file mode 100644 index 0000000..3d1f7fe --- /dev/null +++ b/tests/test_data/gitops_data/app1/service2/values-dev-topic_with_wrong_service_name.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.223-pr313/schema-platform-managed-chart.json +# Test file: Topic with wrong service name +platform-managed-chart: + serviceName: service2 + teamOwner: team1 + env: dev + workloadType: stream + + stream: {} + + image: + repository: dev/my-repo + tag: my-tag + + managedResources: + mskTopics: + output: + topicName: other-service.testtopic diff --git a/tests/test_data/gitops_data/app1/service3/Chart.yaml b/tests/test_data/gitops_data/app1/service3/Chart.yaml new file mode 100644 index 0000000..467c1d4 --- /dev/null +++ b/tests/test_data/gitops_data/app1/service3/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: service3 +version: 0.1.0 +dependencies: + - name: platform-managed-chart + version: 0.1.223-pr313 diff --git a/tests/test_data/gitops_data/app1/service3/values-dev-changelog.yaml b/tests/test_data/gitops_data/app1/service3/values-dev-changelog.yaml new file mode 100644 index 0000000..5371630 --- /dev/null +++ b/tests/test_data/gitops_data/app1/service3/values-dev-changelog.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.223-pr313/schema-platform-managed-chart.json +# Test file: valid Kafka Streams changelog internal topic (correct serviceName-instanceName prefix) +platform-managed-chart: + serviceName: service3 + teamOwner: team1 + env: dev + workloadType: stream + + stream: {} + + image: + repository: dev/my-repo + tag: my-tag + + managedResources: + mskTopics: + output: + topicName: service3-changelog-mystore-changelog diff --git a/tests/test_data/gitops_data/app1/service3/values-dev-foreign-service.yaml b/tests/test_data/gitops_data/app1/service3/values-dev-foreign-service.yaml new file mode 100644 index 0000000..fca498a --- /dev/null +++ b/tests/test_data/gitops_data/app1/service3/values-dev-foreign-service.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.223-pr313/schema-platform-managed-chart.json +# Test file: Kafka Streams internal topic from a foreign service (wrong serviceName prefix) +platform-managed-chart: + serviceName: service3 + teamOwner: team1 + env: dev + workloadType: stream + + stream: {} + + image: + repository: dev/my-repo + tag: my-tag + + managedResources: + mskTopics: + output: + topicName: otherservice-foreign-service-mystore-changelog diff --git a/tests/test_data/gitops_data/app1/service3/values-dev-repartition.yaml b/tests/test_data/gitops_data/app1/service3/values-dev-repartition.yaml new file mode 100644 index 0000000..88043d8 --- /dev/null +++ b/tests/test_data/gitops_data/app1/service3/values-dev-repartition.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.223-pr313/schema-platform-managed-chart.json +# Test file: valid Kafka Streams repartition internal topic (correct serviceName-instanceName prefix) +platform-managed-chart: + serviceName: service3 + teamOwner: team1 + env: dev + workloadType: stream + + stream: {} + + image: + repository: dev/my-repo + tag: my-tag + + managedResources: + mskTopics: + output: + topicName: service3-repartition-mystate-repartition diff --git a/tests/test_data/gitops_data/app1/service3/values-dev-tpl-valid.yaml b/tests/test_data/gitops_data/app1/service3/values-dev-tpl-valid.yaml new file mode 100644 index 0000000..f202376 --- /dev/null +++ b/tests/test_data/gitops_data/app1/service3/values-dev-tpl-valid.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.223-pr313/schema-platform-managed-chart.json +# Test file: valid Kafka Streams changelog internal topic using topicNameTemplate +platform-managed-chart: + serviceName: service3 + teamOwner: team1 + env: dev + workloadType: stream + + stream: {} + + image: + repository: dev/my-repo + tag: my-tag + + managedResources: + mskTopics: + output: + topicNameTemplate: "{{ $.context.serviceName }}-{{ $.context.instanceName }}-mystore-changelog" diff --git a/tests/test_data/gitops_data/app1/service3/values-dev-tpl-wrong.yaml b/tests/test_data/gitops_data/app1/service3/values-dev-tpl-wrong.yaml new file mode 100644 index 0000000..5bac727 --- /dev/null +++ b/tests/test_data/gitops_data/app1/service3/values-dev-tpl-wrong.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.223-pr313/schema-platform-managed-chart.json +# Test file: invalid Kafka Streams changelog topic template with wrong instance name +platform-managed-chart: + serviceName: service3 + teamOwner: team1 + env: dev + workloadType: stream + + stream: {} + + image: + repository: dev/my-repo + tag: my-tag + + managedResources: + mskTopics: + output: + topicNameTemplate: "{{ $.context.serviceName }}-other-instance-mystore-changelog" diff --git a/tests/test_data/gitops_data/app1/service3/values-dev-wrong-prefix.yaml b/tests/test_data/gitops_data/app1/service3/values-dev-wrong-prefix.yaml new file mode 100644 index 0000000..93e1c6e --- /dev/null +++ b/tests/test_data/gitops_data/app1/service3/values-dev-wrong-prefix.yaml @@ -0,0 +1,18 @@ +# yaml-language-server: $schema=https://kp-helmchart-stable-shared-main.s3.eu-west-1.amazonaws.com/schema/platform-managed-chart/v0.1.223-pr313/schema-platform-managed-chart.json +# Test file: Kafka Streams internal topic with wrong serviceName-instanceName prefix +platform-managed-chart: + serviceName: service3 + teamOwner: team1 + env: dev + workloadType: stream + + stream: {} + + image: + repository: dev/my-repo + tag: my-tag + + managedResources: + mskTopics: + output: + topicName: service3-other-instance-store-changelog diff --git a/tests/test_gitops_values_validation.py b/tests/test_gitops_values_validation.py index 4630d50..bc44df9 100644 --- a/tests/test_gitops_values_validation.py +++ b/tests/test_gitops_values_validation.py @@ -82,8 +82,8 @@ def test_env_specific_chart_version_is_used_for_validation( # WHEN - We check the chart version used for validation chart_version_dev = validator_dev.service_instance_config.helm_chart.platform_managed_chart_version - # THEN - Should use the dev-specific version from Chart-dev.yaml (same as base for now) - assert chart_version_dev == "0.1.157-pr195", f"Expected dev chart version '0.1.157-pr195', got '{chart_version_dev}'" + # THEN - Should use the dev-specific version from Chart-dev.yaml + assert chart_version_dev == "0.1.225", f"Expected dev chart version '0.1.225', got '{chart_version_dev}'" # GIVEN - A prod environment configuration validator_prod = create_validator_for_test_file("app1/service1/values-prod-topic_with_authorized_max_local_topic_bytes_not_on_current_env.yaml") @@ -92,4 +92,127 @@ def test_env_specific_chart_version_is_used_for_validation( chart_version_prod = validator_prod.service_instance_config.helm_chart.platform_managed_chart_version # THEN - Should use the base version from Chart.yaml (no Chart-prod.yaml exists) - assert chart_version_prod == "0.1.157-pr195", f"Expected prod chart version '0.1.157-pr195', got '{chart_version_prod}'" + assert chart_version_prod == "0.1.224", f"Expected prod chart version '0.1.224', got '{chart_version_prod}'" + + +def test_kafka_streams_changelog_topic_is_accepted( + create_validator_for_test_file: Callable[[str], ServiceInstanceConfigValidator], +) -> None: + # GIVEN + validator = create_validator_for_test_file("app1/service3/values-dev-changelog.yaml") + + # WHEN + errors = validator.validate_configuration() + + # THEN + assert len(errors) == 0, f"Kafka Streams changelog topics should be accepted, got: {errors}" + + +def test_kafka_streams_repartition_topic_is_accepted( + create_validator_for_test_file: Callable[[str], ServiceInstanceConfigValidator], +) -> None: + # GIVEN + validator = create_validator_for_test_file("app1/service3/values-dev-repartition.yaml") + + # WHEN + errors = validator.validate_configuration() + + # THEN + assert len(errors) == 0, f"Kafka Streams repartition topics should be accepted, got: {errors}" + + +def test_kafka_streams_internal_topic_with_wrong_prefix_is_rejected( + create_validator_for_test_file: Callable[[str], ServiceInstanceConfigValidator], +) -> None: + # GIVEN + validator = create_validator_for_test_file("app1/service3/values-dev-wrong-prefix.yaml") + + # WHEN + errors = validator.validate_configuration() + + # THEN + assert any("must start with 'service3-wrong-prefix-'" in e.message for e in errors), ( + f"Expected internal topic prefix error, got: {errors}" + ) + + +def test_topic_with_wrong_service_name_is_rejected( + create_validator_for_test_file: Callable[[str], ServiceInstanceConfigValidator], +) -> None: + # GIVEN + validator = create_validator_for_test_file("app1/service2/values-dev-topic_with_wrong_service_name.yaml") + + # WHEN + errors = validator.validate_configuration() + + # THEN + assert any("it not compliant" in e.message for e in errors), f"Expected topic name compliance error, got: {errors}" + + +def test_kafka_streams_internal_topic_from_foreign_service_is_rejected( + create_validator_for_test_file: Callable[[str], ServiceInstanceConfigValidator], +) -> None: + # GIVEN + validator = create_validator_for_test_file("app1/service3/values-dev-foreign-service.yaml") + + # WHEN + errors = validator.validate_configuration() + + # THEN + assert any("must start with 'service3-foreign-service-'" in e.message for e in errors), ( + f"Expected internal topic prefix error for foreign service topic, got: {errors}" + ) + + +def test_versioned_topic_with_v_prefix_is_accepted( + create_validator_for_test_file: Callable[[str], ServiceInstanceConfigValidator], +) -> None: + # GIVEN + validator = create_validator_for_test_file("app1/service1/values-dev-versioned-topic.yaml") + + # WHEN + errors = validator.validate_configuration() + + # THEN + assert len(errors) == 0, f"Topic with -vN version suffix should be accepted, got: {errors}" + + +def test_topic_with_hyphenated_suffix_is_accepted( + create_validator_for_test_file: Callable[[str], ServiceInstanceConfigValidator], +) -> None: + # GIVEN + validator = create_validator_for_test_file("app1/service1/values-dev-hyphenated-suffix.yaml") + + # WHEN + errors = validator.validate_configuration() + + # THEN + assert len(errors) == 0, f"Topic with hyphenated suffix should be accepted, got: {errors}" + + +def test_kafka_streams_changelog_topic_template_is_accepted( + create_validator_for_test_file: Callable[[str], ServiceInstanceConfigValidator], +) -> None: + # GIVEN + validator = create_validator_for_test_file("app1/service3/values-dev-tpl-valid.yaml") + + # WHEN + errors = validator.validate_configuration() + + # THEN + assert len(errors) == 0, f"Kafka Streams changelog topic template should be accepted, got: {errors}" + + +def test_kafka_streams_changelog_topic_template_with_wrong_prefix_is_rejected( + create_validator_for_test_file: Callable[[str], ServiceInstanceConfigValidator], +) -> None: + # GIVEN + validator = create_validator_for_test_file("app1/service3/values-dev-tpl-wrong.yaml") + + # WHEN + errors = validator.validate_configuration() + + # THEN + assert any("must start with 'service3-tpl-wrong-'" in e.message for e in errors), ( + f"Expected internal topic prefix error for template with wrong instance, got: {errors}" + )