From 45d9a5ac09c791ab4ac87ec24e659e86547b0815 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 10 Aug 2026 06:34:30 +0900 Subject: [PATCH 1/5] test(supply-chain): reject unsafe Replit Zipkin bootstraps --- .../RepositoryRuntimeSupplyChainTest.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java diff --git a/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java b/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java new file mode 100644 index 00000000..6ca22c0a --- /dev/null +++ b/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java @@ -0,0 +1,58 @@ +package com.xtrmetl.etl.security; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.assertFalse; + +/** + * Guards repository-owned developer launch configuration against executing opaque bundled + * observability binaries or mutable remote shell bootstrap content. + */ +class RepositoryRuntimeSupplyChainTest { + + private static final Path PROJECT_ROOT = projectRoot(); + private static final Pattern REMOTE_SHELL_PIPE = Pattern.compile( + "(?im)\\bcurl\\b[^\\r\\n|]*\\|\\s*(?:bash|sh)\\b" + ); + + @Test + void replitDoesNotExecuteTrackedZipkinJar() throws IOException { + String replit = readReplit(); + assertFalse( + replit.contains("java -jar zipkin.jar"), + "Replit launch configuration must not execute the repository-tracked opaque Zipkin JAR" + ); + } + + @Test + void replitDoesNotPipeMutableRemoteContentIntoAShell() throws IOException { + String replit = readReplit(); + assertFalse( + REMOTE_SHELL_PIPE.matcher(replit).find(), + "Replit launch configuration must not pipe mutable remote content directly into a shell" + ); + } + + private static String readReplit() throws IOException { + return Files.readString(PROJECT_ROOT.resolve(".replit"), StandardCharsets.UTF_8); + } + + private static Path projectRoot() { + Path current = Paths.get(System.getProperty("user.dir")).toAbsolutePath(); + while (current != null) { + if (Files.isRegularFile(current.resolve("pom.xml")) + && Files.isRegularFile(current.resolve(".replit"))) { + return current; + } + current = current.getParent(); + } + throw new IllegalStateException("Could not locate mightyETL repository root"); + } +} From 9c62b78853b847a9590503718e016decfe02d0c1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 10 Aug 2026 06:36:17 +0900 Subject: [PATCH 2/5] fix(supply-chain): retire unsafe Replit Zipkin execution --- .replit | 48 +++++------------------------------------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/.replit b/.replit index d50c78fd..13d25e94 100644 --- a/.replit +++ b/.replit @@ -3,6 +3,8 @@ modules = ["java", "java-17"] [nix] channel = "stable-24_05" +# Zipkin is intentionally not bootstrapped by Replit. Use the repository's Docker Compose +# topology for the supported, reviewable observability runtime. [workflows] runButton = "Project" @@ -23,14 +25,6 @@ args = "Java Version Check" task = "workflow.run" args = "Build Project" -[[workflows.workflow.tasks]] -task = "workflow.run" -args = "Run Zipkin Server" - -[[workflows.workflow.tasks]] -task = "workflow.run" -args = "Run Zipkin" - [[workflows.workflow.tasks]] task = "workflow.run" args = "Run Eureka Server" @@ -56,8 +50,8 @@ agentRequireRestartOnSave = false [[workflows.workflow.tasks]] task = "shell.exec" -args = "mvn clean install && java -jar eureka-server/target/eureka-server-1.0-SNAPSHOT.jar & sleep 30 && java -jar config-server/target/config-server-1.0-SNAPSHOT.jar & sleep 30 && java -jar zipkin.jar & sleep 30 && java -jar etl-service/target/etl-service-1.0-SNAPSHOT.jar & java -jar cdc-service/target/cdc-service-1.0-SNAPSHOT.jar & java -jar zuul-gateway/target/zuul-gateway-1.0-SNAPSHOT.jar" -waitForPort = 9411 +args = "mvn clean install && java -jar eureka-server/target/eureka-server-1.0-SNAPSHOT.jar & sleep 30 && java -jar config-server/target/config-server-1.0-SNAPSHOT.jar & sleep 30 && java -jar etl-service/target/etl-service-1.0-SNAPSHOT.jar & java -jar cdc-service/target/cdc-service-1.0-SNAPSHOT.jar & java -jar zuul-gateway/target/zuul-gateway-1.0-SNAPSHOT.jar" +waitForPort = 8761 [[workflows.workflow]] name = "Java Version Check" @@ -81,30 +75,6 @@ agentRequireRestartOnSave = false task = "shell.exec" args = "mvn clean install" -[[workflows.workflow]] -name = "Run Zipkin Server" -author = "agent" - -[workflows.workflow.metadata] -agentRequireRestartOnSave = false - -[[workflows.workflow.tasks]] -task = "shell.exec" -args = "curl -sSL https://zipkin.io/quickstart.sh | bash -s && java -jar zipkin.jar" -waitForPort = 9411 - -[[workflows.workflow]] -name = "Run Zipkin" -author = "agent" - -[workflows.workflow.metadata] -agentRequireRestartOnSave = false - -[[workflows.workflow.tasks]] -task = "shell.exec" -args = "java -jar zipkin.jar --server.port=9412" -waitForPort = 9412 - [[workflows.workflow]] name = "Run Eureka Server" author = "agent" @@ -152,16 +122,8 @@ args = "mvn clean install && java -jar eureka-server/target/eureka-server-1.0-SN waitForPort = 8761 [deployment] -run = ["sh", "-c", "mvn clean install && java -jar eureka-server/target/eureka-server-1.0-SNAPSHOT.jar & sleep 30 && java -jar config-server/target/config-server-1.0-SNAPSHOT.jar & sleep 30 && java -jar zipkin.jar & sleep 30 && java -jar etl-service/target/etl-service-1.0-SNAPSHOT.jar & java -jar cdc-service/target/cdc-service-1.0-SNAPSHOT.jar & java -jar zuul-gateway/target/zuul-gateway-1.0-SNAPSHOT.jar"] +run = ["sh", "-c", "mvn clean install && java -jar eureka-server/target/eureka-server-1.0-SNAPSHOT.jar & sleep 30 && java -jar config-server/target/config-server-1.0-SNAPSHOT.jar & sleep 30 && java -jar etl-service/target/etl-service-1.0-SNAPSHOT.jar & java -jar cdc-service/target/cdc-service-1.0-SNAPSHOT.jar & java -jar zuul-gateway/target/zuul-gateway-1.0-SNAPSHOT.jar"] [[ports]] localPort = 8761 externalPort = 3001 - -[[ports]] -localPort = 9411 -externalPort = 80 - -[[ports]] -localPort = 9412 -externalPort = 3000 From 5333bbb12a21746a480cc89a86ffbdabe4b85064 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 10 Aug 2026 06:41:28 +0900 Subject: [PATCH 3/5] test(ops): reject overlapping Replit service launches --- .../RepositoryRuntimeSupplyChainTest.java | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java b/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java index 6ca22c0a..bf301796 100644 --- a/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java +++ b/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java @@ -9,11 +9,13 @@ import java.nio.file.Paths; import java.util.regex.Pattern; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** - * Guards repository-owned developer launch configuration against executing opaque bundled - * observability binaries or mutable remote shell bootstrap content. + * Guards repository-owned developer launch configuration against unsafe or conflicting + * developer-runtime authority paths. */ class RepositoryRuntimeSupplyChainTest { @@ -40,10 +42,48 @@ void replitDoesNotPipeMutableRemoteContentIntoAShell() throws IOException { ); } + @Test + void projectRunButtonDelegatesToOneMicroserviceTopology() throws IOException { + String projectWorkflow = workflowBlock(readReplit(), "Project"); + int serviceTopologyDelegates = countOccurrences(projectWorkflow, "args = \"Run Microservices\"") + + countOccurrences(projectWorkflow, "args = \"Run Eureka Server\"") + + countOccurrences(projectWorkflow, "args = \"Build and Run Microservices\""); + + assertEquals( + 1, + serviceTopologyDelegates, + "The Replit run button must not launch overlapping copies of the same microservice topology" + ); + assertTrue( + projectWorkflow.contains("args = \"Run Microservices\""), + "The Replit run button must delegate service startup to the canonical Run Microservices workflow" + ); + } + private static String readReplit() throws IOException { return Files.readString(PROJECT_ROOT.resolve(".replit"), StandardCharsets.UTF_8); } + private static String workflowBlock(String replit, String workflowName) { + String marker = "[[workflows.workflow]]\nname = \"" + workflowName + "\""; + int start = replit.indexOf(marker); + if (start < 0) { + throw new AssertionError("Missing Replit workflow: " + workflowName); + } + int end = replit.indexOf("[[workflows.workflow]]", start + marker.length()); + return end < 0 ? replit.substring(start) : replit.substring(start, end); + } + + private static int countOccurrences(String text, String needle) { + int count = 0; + int cursor = 0; + while ((cursor = text.indexOf(needle, cursor)) >= 0) { + count++; + cursor += needle.length(); + } + return count; + } + private static Path projectRoot() { Path current = Paths.get(System.getProperty("user.dir")).toAbsolutePath(); while (current != null) { From 71c3ea4813075905b796b59f73ee0cf46cf8513d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 10 Aug 2026 06:44:27 +0900 Subject: [PATCH 4/5] fix(ops): avoid duplicate Replit service topologies --- .replit | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.replit b/.replit index 13d25e94..12fbdc2c 100644 --- a/.replit +++ b/.replit @@ -25,10 +25,6 @@ args = "Java Version Check" task = "workflow.run" args = "Build Project" -[[workflows.workflow.tasks]] -task = "workflow.run" -args = "Run Eureka Server" - [[workflows.workflow.tasks]] task = "workflow.run" args = "Run All Tests" @@ -37,10 +33,6 @@ args = "Run All Tests" task = "workflow.run" args = "Check Test Status" -[[workflows.workflow.tasks]] -task = "workflow.run" -args = "Build and Run Microservices" - [[workflows.workflow]] name = "Run Microservices" author = "agent" From 50426b24de3c51a112f608fbdb8c3a86f4fc4a8d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 10 Aug 2026 06:50:42 +0900 Subject: [PATCH 5/5] test(ops): normalize Replit line endings --- .../etl/security/RepositoryRuntimeSupplyChainTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java b/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java index bf301796..5cad7938 100644 --- a/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java +++ b/etl-service/src/test/java/com/xtrmetl/etl/security/RepositoryRuntimeSupplyChainTest.java @@ -65,13 +65,14 @@ private static String readReplit() throws IOException { } private static String workflowBlock(String replit, String workflowName) { + String normalizedReplit = replit.replace("\r\n", "\n").replace('\r', '\n'); String marker = "[[workflows.workflow]]\nname = \"" + workflowName + "\""; - int start = replit.indexOf(marker); + int start = normalizedReplit.indexOf(marker); if (start < 0) { throw new AssertionError("Missing Replit workflow: " + workflowName); } - int end = replit.indexOf("[[workflows.workflow]]", start + marker.length()); - return end < 0 ? replit.substring(start) : replit.substring(start, end); + int end = normalizedReplit.indexOf("[[workflows.workflow]]", start + marker.length()); + return end < 0 ? normalizedReplit.substring(start) : normalizedReplit.substring(start, end); } private static int countOccurrences(String text, String needle) {