From 574b61152dd4bb8a6904fec3cdfa36e7cd9c382f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 10 Aug 2026 08:53:30 +0900 Subject: [PATCH 1/4] test(cdc): reject stop exception diagnostics in response --- .../com/xtrmetl/cdc/controller/CdcControllerTest.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cdc-service/src/test/java/com/xtrmetl/cdc/controller/CdcControllerTest.java b/cdc-service/src/test/java/com/xtrmetl/cdc/controller/CdcControllerTest.java index 08cf2f5d..16cbda8b 100644 --- a/cdc-service/src/test/java/com/xtrmetl/cdc/controller/CdcControllerTest.java +++ b/cdc-service/src/test/java/com/xtrmetl/cdc/controller/CdcControllerTest.java @@ -79,13 +79,17 @@ void testStopCdc() throws IOException { } @Test - void testStopCdcWithException() throws IOException { - doThrow(new IOException("Error stopping CDC")).when(cdcService).stop(); + void testStopCdcWithExceptionDoesNotExposeInternalDiagnostics() throws IOException { + String sensitiveDiagnostic = + "Error closing offset store at jdbc:postgresql://db.internal/prod?password=driver-secret"; + doThrow(new IOException(sensitiveDiagnostic)).when(cdcService).stop(); ResponseEntity response = cdcController.stopCdc(); assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); - assertEquals("Error stopping CDC process: Error stopping CDC", response.getBody()); + assertEquals("CDC process could not be stopped", response.getBody()); + assertFalse(response.getBody().contains("driver-secret")); + assertFalse(response.getBody().contains("jdbc:postgresql://")); verify(cdcService, times(1)).stop(); } From b00077e9afdd857566cd6c60e1f433117aa147fe Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 10 Aug 2026 09:00:03 +0900 Subject: [PATCH 2/4] fix(cdc): keep stop diagnostics out of API response --- .../src/main/java/com/xtrmetl/cdc/controller/CdcController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cdc-service/src/main/java/com/xtrmetl/cdc/controller/CdcController.java b/cdc-service/src/main/java/com/xtrmetl/cdc/controller/CdcController.java index 621af2df..b1aad0f9 100644 --- a/cdc-service/src/main/java/com/xtrmetl/cdc/controller/CdcController.java +++ b/cdc-service/src/main/java/com/xtrmetl/cdc/controller/CdcController.java @@ -122,7 +122,7 @@ public ResponseEntity stopCdc() { cdcService.stop(); return ResponseEntity.ok("CDC process stopped"); } catch (IOException e) { - return ResponseEntity.internalServerError().body("Error stopping CDC process: " + e.getMessage()); + return ResponseEntity.internalServerError().body("CDC process could not be stopped"); } } } From 3a872c9eba23efc38bbbeb5ce3814d83788e0a2f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 10 Aug 2026 11:34:03 +0900 Subject: [PATCH 3/4] test(cdc): keep start failure diagnostics out of API responses --- .../xtrmetl/cdc/controller/CdcControllerTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/cdc-service/src/test/java/com/xtrmetl/cdc/controller/CdcControllerTest.java b/cdc-service/src/test/java/com/xtrmetl/cdc/controller/CdcControllerTest.java index 16cbda8b..3a4eca0d 100644 --- a/cdc-service/src/test/java/com/xtrmetl/cdc/controller/CdcControllerTest.java +++ b/cdc-service/src/test/java/com/xtrmetl/cdc/controller/CdcControllerTest.java @@ -69,6 +69,21 @@ void testStartCdc() { verify(cdcService, times(1)).start(); } + @Test + void testStartCdcWithExceptionDoesNotExposeInternalDiagnostics() { + String sensitiveDiagnostic = + "Failed to initialize jdbc:postgresql://db.internal/prod?user=cdc&password=driver-secret"; + doThrow(new IllegalStateException(sensitiveDiagnostic)).when(cdcService).start(); + + ResponseEntity response = cdcController.startCdc(); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); + assertEquals("CDC process could not be started", response.getBody()); + assertFalse(response.getBody().contains("driver-secret")); + assertFalse(response.getBody().contains("jdbc:postgresql://")); + verify(cdcService, times(1)).start(); + } + @Test void testStopCdc() throws IOException { ResponseEntity response = cdcController.stopCdc(); From 69dcccfe0a608e79ec1fea4098747943ab5aa86c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 10 Aug 2026 11:37:59 +0900 Subject: [PATCH 4/4] fix(cdc): bound start failure API diagnostics --- .../xtrmetl/cdc/controller/CdcController.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/cdc-service/src/main/java/com/xtrmetl/cdc/controller/CdcController.java b/cdc-service/src/main/java/com/xtrmetl/cdc/controller/CdcController.java index b1aad0f9..b40ddf80 100644 --- a/cdc-service/src/main/java/com/xtrmetl/cdc/controller/CdcController.java +++ b/cdc-service/src/main/java/com/xtrmetl/cdc/controller/CdcController.java @@ -108,13 +108,27 @@ private Map sourceEntry(com.xtrmetl.cdc.spi.CdcSourceConnector s return entry; } + /** + * Requests CDC engine startup and exposes only a stable public failure contract. + * + * @return {@code 200} when startup is accepted, or {@code 500} without internal startup diagnostics + */ @PostMapping("/start") @Observed(name = "cdc.start", contextualName = "cdc-start") public ResponseEntity startCdc() { - cdcService.start(); - return ResponseEntity.ok("CDC process started"); + try { + cdcService.start(); + return ResponseEntity.ok("CDC process started"); + } catch (RuntimeException e) { + return ResponseEntity.internalServerError().body("CDC process could not be started"); + } } + /** + * Requests CDC engine shutdown and exposes only a stable public failure contract. + * + * @return {@code 200} when shutdown succeeds, or {@code 500} without internal shutdown diagnostics + */ @PostMapping("/stop") @Observed(name = "cdc.stop", contextualName = "cdc-stop") public ResponseEntity stopCdc() {