diff --git a/modules/cybercore-app/pom.xml b/modules/cybercore-app/pom.xml index d83b40d..6e09980 100644 --- a/modules/cybercore-app/pom.xml +++ b/modules/cybercore-app/pom.xml @@ -108,6 +108,23 @@ + + + src/main/resources + true + + build-info.properties + + + + src/main/resources + false + + build-info.properties + + + + org.openjfx @@ -138,6 +155,7 @@ CyberCore Signer ${project.version} CyberCore + ${cybercore.build.flavor} diff --git a/modules/cybercore-app/src/main/java/br/com/cybercore/signer/app/CyberCoreSignerApplication.java b/modules/cybercore-app/src/main/java/br/com/cybercore/signer/app/CyberCoreSignerApplication.java index 9524324..862a6a1 100644 --- a/modules/cybercore-app/src/main/java/br/com/cybercore/signer/app/CyberCoreSignerApplication.java +++ b/modules/cybercore-app/src/main/java/br/com/cybercore/signer/app/CyberCoreSignerApplication.java @@ -19,12 +19,39 @@ public class CyberCoreSignerApplication { private static final Logger logger = LoggerFactory.getLogger(CyberCoreSignerApplication.class); + private static final String BUILD_INFO_RESOURCE = "/build-info.properties"; + private static String buildFlavor = "production"; private static boolean developmentMode = false; private static boolean headlessMode = false; private static boolean noWaitMode = false; private static int configuredPort = CcspServer.DEFAULT_PORT; private static volatile CcspServer runningServer = null; + static { + loadBuildInfo(); + } + + private static void loadBuildInfo() { + try (var is = CyberCoreSignerApplication.class.getResourceAsStream(BUILD_INFO_RESOURCE)) { + if (is != null) { + var props = new java.util.Properties(); + props.load(is); + String flavor = props.getProperty("build.flavor"); + if (flavor != null && !flavor.isBlank()) { + buildFlavor = flavor.trim().toLowerCase(); + } + } + } catch (Exception ignored) {} + } + + public static String getBuildFlavor() { + return buildFlavor; + } + + public static void setBuildFlavorForTesting(String flavor) { + buildFlavor = flavor; + } + public static CcspServer getRunningServer() { return runningServer; } @@ -147,6 +174,10 @@ public class CyberCoreSignerApplication { for (int i = 0; i < args.length; i++) { String arg = args[i]; if ("--dev".equalsIgnoreCase(arg) || "-dev".equalsIgnoreCase(arg)) { + if ("production".equalsIgnoreCase(buildFlavor)) { + logger.error("ALERTA DE SEGURANÇA: Modo de desenvolvimento (--dev) não é permitido em compilações de produção (flavor: production)."); + throw new SecurityException("Modo de desenvolvimento (--dev) bloqueado em compilações de produção."); + } developmentMode = true; } else if ("--headless".equalsIgnoreCase(arg) || "-headless".equalsIgnoreCase(arg) || "--cli".equalsIgnoreCase(arg)) { diff --git a/modules/cybercore-app/src/main/resources/build-info.properties b/modules/cybercore-app/src/main/resources/build-info.properties new file mode 100644 index 0000000..c1e7285 --- /dev/null +++ b/modules/cybercore-app/src/main/resources/build-info.properties @@ -0,0 +1,2 @@ +build.version=${project.version} +build.flavor=${cybercore.build.flavor} diff --git a/modules/cybercore-app/src/test/java/br/com/cybercore/signer/app/CyberCoreSignerApplicationTest.java b/modules/cybercore-app/src/test/java/br/com/cybercore/signer/app/CyberCoreSignerApplicationTest.java index f601ed6..45fc5b2 100644 --- a/modules/cybercore-app/src/test/java/br/com/cybercore/signer/app/CyberCoreSignerApplicationTest.java +++ b/modules/cybercore-app/src/test/java/br/com/cybercore/signer/app/CyberCoreSignerApplicationTest.java @@ -8,16 +8,36 @@ import static org.assertj.core.api.Assertions.assertThatCode; class CyberCoreSignerApplicationTest { @Test - @DisplayName("Deve inicializar a aplicação com argumentos sem erros") + @DisplayName("Deve inicializar a aplicação com argumentos sem erros em compilação normal") void shouldBootstrapWithoutErrors() { try { - assertThatCode(() -> CyberCoreSignerApplication.main(new String[]{"--dev", "--headless", "--no-wait", "--port", "29999"})) + assertThatCode(() -> CyberCoreSignerApplication.main(new String[]{"--headless", "--no-wait", "--port", "29999"})) .doesNotThrowAnyException(); } finally { CyberCoreSignerApplication.stopServer(); } } + @Test + @DisplayName("Deve bloquear o modo dev em compilações de produção") + void shouldBlockDevModeInProductionFlavor() { + CyberCoreSignerApplication.setBuildFlavorForTesting("production"); + org.assertj.core.api.Assertions.assertThatThrownBy(() -> + CyberCoreSignerApplication.parseArguments(new String[]{"--dev"}) + ).isInstanceOf(SecurityException.class) + .hasMessageContaining("bloqueado em compilações de produção"); + } + + @Test + @DisplayName("Deve permitir o modo dev quando o flavor for development") + void shouldAllowDevModeInDevelopmentFlavor() { + CyberCoreSignerApplication.setBuildFlavorForTesting("development"); + org.assertj.core.api.Assertions.assertThatCode(() -> + CyberCoreSignerApplication.parseArguments(new String[]{"--dev"}) + ).doesNotThrowAnyException(); + org.assertj.core.api.Assertions.assertThat(CyberCoreSignerApplication.isDevelopmentMode()).isTrue(); + } + @Test @DisplayName("Deve realizar o parse correto do argumento --port") void shouldParsePortArgument() {