diff --git a/cdc-service/src/main/java/com/xtrmetl/cdc/spi/PostgresDebeziumCdcSource.java b/cdc-service/src/main/java/com/xtrmetl/cdc/spi/PostgresDebeziumCdcSource.java index dcc0e653..2009c738 100644 --- a/cdc-service/src/main/java/com/xtrmetl/cdc/spi/PostgresDebeziumCdcSource.java +++ b/cdc-service/src/main/java/com/xtrmetl/cdc/spi/PostgresDebeziumCdcSource.java @@ -11,6 +11,10 @@ /** * Adapter for the live Debezium PostgreSQL capture path owned by {@link CdcService}. * + *

The live service reads connection and Debezium settings from deployment configuration. Per-call + * SPI configuration is therefore intentionally unsupported: callers must pass an empty map so values + * such as credentials are never accepted and then silently ignored.

+ * *

{@link #start(Map)} / {@link #stop()} delegate to the service when available so the SPI * is a real control surface for the supported source type.

*/ @@ -67,13 +71,34 @@ public SourceCapabilities capabilities() { return new SourceCapabilities("debezium-embedded", Set.of("postgresql"), false); } + /** + * Validates the per-call configuration accepted by this adapter. + * + *

The live PostgreSQL capture service is configured by the deployment, not by this SPI call. + * An empty map is therefore the only valid value.

+ * + * @param config per-call settings; must be non-null and empty + * @throws IllegalArgumentException when {@code config} is null or contains any entry + */ @Override public void validate(Map config) { if (config == null) { throw new IllegalArgumentException("config must not be null"); } + if (!config.isEmpty()) { + throw new IllegalArgumentException( + "postgres-debezium uses deployment-owned configuration; per-call config must be empty" + ); + } } + /** + * Starts the deployment-configured PostgreSQL CDC service. + * + * @param config per-call settings; must be non-null and empty + * @throws IllegalArgumentException when {@code config} is null or contains any entry + * @throws IllegalStateException when the live {@link CdcService} is unavailable + */ @Override public void start(Map config) { validate(config); diff --git a/cdc-service/src/test/java/com/xtrmetl/cdc/spi/PostgresDebeziumCdcSourceConfigurationTest.java b/cdc-service/src/test/java/com/xtrmetl/cdc/spi/PostgresDebeziumCdcSourceConfigurationTest.java new file mode 100644 index 00000000..a65766fa --- /dev/null +++ b/cdc-service/src/test/java/com/xtrmetl/cdc/spi/PostgresDebeziumCdcSourceConfigurationTest.java @@ -0,0 +1,43 @@ +package com.xtrmetl.cdc.spi; + +import com.xtrmetl.cdc.service.CdcService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.ObjectProvider; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +/** + * Guards the PostgreSQL source SPI against silently ignored per-call configuration. + */ +class PostgresDebeziumCdcSourceConfigurationTest { + + @Test + void rejectsCallerConfigurationBeforeStartingDeploymentConfiguredService() { + CdcService service = mock(CdcService.class); + @SuppressWarnings("unchecked") + ObjectProvider provider = mock(ObjectProvider.class); + when(provider.getIfAvailable()).thenReturn(service); + PostgresDebeziumCdcSource source = new PostgresDebeziumCdcSource(provider); + String rejectedSecret = "buyer-secret-password-8472"; + + IllegalArgumentException failure = assertThrows( + IllegalArgumentException.class, + () -> source.start(Map.of("database.password", rejectedSecret)) + ); + + assertEquals( + "postgres-debezium uses deployment-owned configuration; per-call config must be empty", + failure.getMessage() + ); + assertFalse(failure.getMessage().contains(rejectedSecret)); + assertFalse(failure.getMessage().contains("database.password")); + verifyNoInteractions(service); + } +}