diff --git a/Dockerfile b/Dockerfile index bafdeebb5..1c7a4e14b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,28 +1,20 @@ -FROM eclipse-temurin:21 AS builder - -ARG MAVEN_VERSION=3.9.6 -ARG USER_HOME_DIR="/root" -ARG SHA=706f01b20dec0305a822ab614d51f32b07ee11d0218175e55450242e49d2156386483b506b3a4e8a03ac8611bae96395fd5eec15f50d3013d5deed6d1ee18224 -ARG BASE_URL=https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries - -RUN mkdir -p /usr/share/maven /usr/share/maven/ref \ - && for i in 1 2 3; do \ - echo "Attempt $i to download Maven..." && \ - curl -fsSL --connect-timeout 300 --max-time 600 -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz && break || \ - (echo "Download failed, attempt $i of 3" && sleep 10); \ - done \ - && echo "${SHA} /tmp/apache-maven.tar.gz" | sha512sum -c - \ - && tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 \ - && rm -f /tmp/apache-maven.tar.gz \ - && ln -s /usr/share/maven/bin/mvn /usr/bin/mvn - -ENV MAVEN_HOME /usr/share/maven -ENV MAVEN_CONFIG "$USER_HOME_DIR/.m2" - -COPY mvn-entrypoint.sh /usr/local/bin/mvn-entrypoint.sh -COPY settings-docker.xml /usr/share/maven/ref/ - -# Copy src files needed for build +# ----------------------------- +# Builder stage +# ----------------------------- +# Uses the official Maven image with Eclipse Temurin Java 21 on Alpine. +# This stage is only used to compile/package the application. +# Maven and build tools stay in this stage and are not included in the final runtime image. +FROM maven:3.9.15-eclipse-temurin-21-alpine AS builder + +# Set the application source directory inside the container. +WORKDIR /usr/src/app + +# Copy custom Maven settings. +# This is useful if the build depends on internal repositories, mirrors, credentials, or proxy config. +COPY settings-docker.xml /usr/share/maven/ref/settings-docker.xml + +# Copy only the source files/modules needed for the Maven build. +# Keeping this explicit avoids copying unnecessary files into the build context. COPY pom.xml /usr/src/app/ COPY commons/ /usr/src/app/commons/ COPY test-commons/ /usr/src/app/test-commons/ @@ -32,18 +24,54 @@ COPY rest-api/ /usr/src/app/rest-api/ COPY generate/ /usr/src/app/generate/ COPY test-coverage/ /usr/src/app/test-coverage/ COPY tools/docker/docker-artifacts/ /usr/src/app/tools/docker/docker-artifacts/ -WORKDIR /usr/src/app/ -RUN /usr/local/bin/mvn-entrypoint.sh mvn install -Dmaven.test.skip -Djacoco.skip=true -Dskip.generate=true > /dev/null +# Build the application. +# -B runs Maven in batch mode for CI/CD. +# -ntp disables Maven transfer progress logs. +# -s uses the custom Maven settings file copied above. +# Tests, JaCoCo, and generate steps are skipped because this Docker build only packages the runtime artifact. +RUN mvn -B -ntp \ + -s /usr/share/maven/ref/settings-docker.xml \ + clean install \ + -Dmaven.test.skip=true \ + -Djacoco.skip=true \ + -Dskip.generate=true > /dev/null -# Final stage -FROM eclipse-temurin:21-jre -RUN mkdir -p /usr/src/run/ -COPY --from=builder /usr/src/app/tools/docker/docker-artifacts /usr/src/run/ -COPY --from=builder /usr/src/app/rest-api/target/rest-api.jar /usr/src/run/ +# ----------------------------- +# Final runtime stage +# ----------------------------- +# Uses a pinned Alpine-based Java 21 JRE image. +# This avoids the Ubuntu-based OS package vulnerabilities reported by Snyk +# while keeping the runtime image smaller and more reproducible. +FROM eclipse-temurin:21.0.10_7-jre-alpine-3.23 +# Set the directory where the application will run. WORKDIR /usr/src/run/ +# Copy only the runtime artifacts from the builder stage. +# This keeps Maven, source code, and build dependencies out of the final image. +COPY --from=builder /usr/src/app/tools/docker/docker-artifacts /usr/src/run/ +COPY --from=builder /usr/src/app/rest-api/target/rest-api.jar /usr/src/run/rest-api.jar + +# Prepare the startup script for the Alpine runtime. +# 1. Remove Windows CRLF line endings if present. +# 2. Replace a bash shebang with sh because Alpine includes /bin/sh by default, +# but does not include /bin/bash unless bash is installed separately. +# 3. Make the script executable. +# 4. Validate that the required runtime files exist during image build. +# +# We intentionally do not run "apk upgrade" here. +# The runtime image is pinned, so OS package versions come from the selected base image. +# This keeps builds more reproducible and avoids transient failures from Alpine package repos. +RUN sed -i 's/\r$//' /usr/src/run/qppConverter.sh \ + && sed -i '1s|^#!/bin/bash|#!/bin/sh|' /usr/src/run/qppConverter.sh \ + && chmod +x /usr/src/run/qppConverter.sh \ + && test -f /usr/src/run/rest-api.jar \ + && test -f /usr/src/run/qppConverter.sh + +# Application listens on 8443. EXPOSE 8443 -CMD ["/usr/src/run/qppConverter.sh"] + +# Start the application using the existing startup script. +CMD ["/usr/src/run/qppConverter.sh"] \ No newline at end of file diff --git a/DockerfileTest b/DockerfileTest index 9f11d33bc..28b446748 100644 --- a/DockerfileTest +++ b/DockerfileTest @@ -1,21 +1,56 @@ -FROM maven:3.9.6-eclipse-temurin-21 AS builder +# ----------------------------- +# Builder stage +# ----------------------------- +# Uses Maven with Eclipse Temurin Java 21 on Alpine. +# This stage builds the application jar only. +FROM maven:3.9.15-eclipse-temurin-21-alpine AS builder +# Copy the full project into the build container. COPY ./ /usr/src/app/ -WORKDIR /usr/src/app/ -RUN mvn install -Dmaven.test.skip -Djacoco.skip=true > /dev/null +# Set project directory. +WORKDIR /usr/src/app/ -# Final stage -FROM eclipse-temurin:21-jre +# Build the project and create the application jar. +# -B = batch mode, useful for CI +# -ntp = no transfer progress, cleaner logs +# Tests and JaCoCo are skipped because this image only needs the built runtime jar. +RUN mvn -B -ntp install \ + -Dmaven.test.skip=true \ + -Djacoco.skip=true \ + -Dskip.generate=true > /dev/null -RUN apt-get update && apt-get install -y dos2unix && rm -rf /var/lib/apt/lists/* -RUN mkdir -p /usr/src/run/ -COPY --from=builder /usr/src/app/rest-api/target/rest-api.jar /usr/src/run/ -COPY --from=builder /usr/src/app/tools/docker/docker-test-artifacts/* /usr/src/run/ -RUN dos2unix /usr/src/run/qppConverterTest.sh +# ----------------------------- +# Final runtime stage +# ----------------------------- +# Uses a smaller Alpine-based Eclipse Temurin Java 21 JRE image. +# This avoids the Ubuntu-based OS package vulnerabilities reported by Snyk. +FROM eclipse-temurin:21.0.10_7-jre-alpine-3.23 +# Set the runtime directory. WORKDIR /usr/src/run/ +# Copy only the built jar from the builder stage. +# This keeps Maven, source code, and build dependencies out of the final image. +COPY --from=builder /usr/src/app/rest-api/target/rest-api.jar /usr/src/run/rest-api.jar + +# Copy test runtime artifacts, including qppConverterTest.sh. +COPY --from=builder /usr/src/app/tools/docker/docker-test-artifacts/ /usr/src/run/ + +# Fix the startup script for Alpine runtime: +# 1. Remove Windows CRLF line endings if present. +# 2. Replace #!/bin/bash with #!/bin/sh because Alpine does not include bash by default. +# 3. Make the script executable. +# 4. Validate that the jar and startup script exist during image build. +RUN sed -i 's/\r$//' /usr/src/run/qppConverterTest.sh \ + && sed -i '1s|^#!/bin/bash|#!/bin/sh|' /usr/src/run/qppConverterTest.sh \ + && chmod +x /usr/src/run/qppConverterTest.sh \ + && test -f /usr/src/run/rest-api.jar \ + && test -f /usr/src/run/qppConverterTest.sh + +# Application test container listens on 8080. EXPOSE 8080 -ENTRYPOINT ["/usr/src/run/qppConverterTest.sh"] + +# Start the test application using the startup script. +ENTRYPOINT ["/usr/src/run/qppConverterTest.sh"] \ No newline at end of file diff --git a/acceptance-tests/pom.xml b/acceptance-tests/pom.xml index 954308451..f3891dbf6 100644 --- a/acceptance-tests/pom.xml +++ b/acceptance-tests/pom.xml @@ -3,7 +3,7 @@ 4.0.0 acceptance-tests gov.cms.qpp.conversion - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE conversion-tests jar @@ -13,6 +13,12 @@ + + com.fasterxml.jackson.core + jackson-core + 2.21.2 + + io.cucumber cucumber-java @@ -30,7 +36,7 @@ org.seleniumhq.selenium selenium-java - 4.14.0 + 4.14.1 @@ -43,7 +49,7 @@ org.springframework spring-web - 6.1.21 + 6.2.18 diff --git a/commandline/pom.xml b/commandline/pom.xml index c2bd030b2..bec511301 100644 --- a/commandline/pom.xml +++ b/commandline/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE ../pom.xml @@ -68,6 +68,12 @@ + + com.fasterxml.jackson.core + jackson-core + 2.21.2 + + ch.qos.logback logback-classic diff --git a/commons/pom.xml b/commons/pom.xml index 2c4a758b0..846d1b263 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE ../pom.xml diff --git a/converter/pom.xml b/converter/pom.xml index f77422b48..be87ebdc4 100644 --- a/converter/pom.xml +++ b/converter/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE ../pom.xml @@ -69,6 +69,12 @@ + + com.fasterxml.jackson.core + jackson-core + 2.21.2 + + com.google.code.findbugs annotations diff --git a/converter/src/test/java/gov/cms/qpp/conversion/encode/QualityMeasureIdEncoderTest.java b/converter/src/test/java/gov/cms/qpp/conversion/encode/QualityMeasureIdEncoderTest.java index eb74b5a6c..9e6242940 100644 --- a/converter/src/test/java/gov/cms/qpp/conversion/encode/QualityMeasureIdEncoderTest.java +++ b/converter/src/test/java/gov/cms/qpp/conversion/encode/QualityMeasureIdEncoderTest.java @@ -3,6 +3,7 @@ import static com.google.common.truth.Truth.assertThat; import com.jayway.jsonpath.TypeRef; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -69,6 +70,11 @@ void setUp() { MeasureConfigs.initMeasureConfigs(MeasureConfigs.TEST_MEASURE_DATA); } + @AfterEach + void tearDown() { + MeasureConfigs.initMeasureConfigs(MeasureConfigs.DEFAULT_MEASURE_DATA_FILE_NAME); + } + @Test void testMeasureIdIsEncoded() { executeInternalEncode(); diff --git a/generate-race-cpcplus/pom.xml b/generate-race-cpcplus/pom.xml index cebc0a23b..c3788db96 100644 --- a/generate-race-cpcplus/pom.xml +++ b/generate-race-cpcplus/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion generateRaceCpcPlus - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE generate-race-cpcplus jar @@ -56,6 +56,11 @@ + + com.fasterxml.jackson.core + jackson-core + 2.21.2 + org.jdom jdom2 diff --git a/generate/pom.xml b/generate/pom.xml index 1f960c91c..60779bd5d 100644 --- a/generate/pom.xml +++ b/generate/pom.xml @@ -5,7 +5,7 @@ qpp-conversion-tool-parent gov.cms.qpp.conversion - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE ../pom.xml 4.0.0 @@ -57,6 +57,12 @@ + + com.fasterxml.jackson.core + jackson-core + 2.21.2 + + com.github.spullara.mustache.java diff --git a/pom.xml b/pom.xml index 48b8fc136..68476a7bf 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent pom - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE QPP Conversion Tool @@ -237,25 +237,25 @@ com.fasterxml.jackson.core jackson-core - 2.18.6 + 2.21.2 com.fasterxml.jackson.core jackson-annotations - 2.18.6 + 2.21 com.fasterxml.jackson.core jackson-databind - 2.18.6 + 2.21.2 com.fasterxml.jackson.dataformat jackson-dataformat-xml - 2.18.6 + 2.21.2 @@ -517,19 +517,19 @@ org.springframework spring-webmvc - 6.2.17 + 6.2.18 org.springframework spring-web - 6.2.17 + 6.2.18 org.springframework spring-framework-bom - 6.2.17 + 6.2.18 pom import @@ -537,13 +537,13 @@ org.bouncycastle bcprov-jdk18on - 1.83 + 1.84 com.fasterxml.jackson.module jackson-module-jaxb-annotations - 2.18.6 + 2.21.2 @@ -555,17 +555,17 @@ org.apache.tomcat.embed tomcat-embed-core - 10.1.52 + 10.1.54 org.apache.tomcat.embed tomcat-embed-el - 10.1.52 + 10.1.54 org.apache.tomcat.embed tomcat-embed-websocket - 10.1.52 + 10.1.54 diff --git a/qrda3-update-measures/pom.xml b/qrda3-update-measures/pom.xml index 25631f9fd..090a0bd6e 100644 --- a/qrda3-update-measures/pom.xml +++ b/qrda3-update-measures/pom.xml @@ -4,7 +4,7 @@ gov.cms.qpp.conversion qpp-update-measures - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE qrda3-update-measures jar @@ -37,6 +37,11 @@ + + com.fasterxml.jackson.core + jackson-core + 2.21.2 + org.jdom jdom2 diff --git a/rest-api/pom.xml b/rest-api/pom.xml index 73a72ae90..4bd2226f2 100644 --- a/rest-api/pom.xml +++ b/rest-api/pom.xml @@ -19,7 +19,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE ../pom.xml @@ -32,8 +32,9 @@ 0.90 - 6.2.17 - 10.1.52 + 6.2.18 + + managed-by-boot-bom 5.11.4 1.11.4 @@ -44,7 +45,7 @@ 6.1.0 - 6.5.9 + 6.5.10 @@ -58,7 +59,7 @@ org.springframework.boot spring-boot-maven-plugin - 3.4.8 + 3.5.13 repackage @@ -186,7 +187,7 @@ org.springframework.boot spring-boot-dependencies - 3.4.11 + 3.5.14 pom import @@ -196,39 +197,28 @@ org.springframework spring-webmvc - 6.2.17 + 6.2.18 org.springframework spring-beans - 6.2.17 + 6.2.18 - + org.springframework spring-framework-bom - 6.2.17 + 6.2.18 pom import - - - org.apache.tomcat.embed - tomcat-embed-core - 10.1.52 - - - org.apache.tomcat.embed - tomcat-embed-el - 10.1.52 - - - org.apache.tomcat.embed - tomcat-embed-websocket - 10.1.52 - + org.springframework.security diff --git a/rest-api/src/main/java/gov/cms/qpp/conversion/api/controllers/HealthCheckController.java b/rest-api/src/main/java/gov/cms/qpp/conversion/api/controllers/HealthCheckController.java index 109d1482f..abefcb0ba 100644 --- a/rest-api/src/main/java/gov/cms/qpp/conversion/api/controllers/HealthCheckController.java +++ b/rest-api/src/main/java/gov/cms/qpp/conversion/api/controllers/HealthCheckController.java @@ -39,8 +39,6 @@ public HealthCheckController(VersionService version) { HealthCheck healthCheck = new HealthCheck(); healthCheck.setImplementationVersion(version.getImplementationVersion()); healthCheck.setValidationUrl(System.getenv("VALIDATION_URL")); - healthCheck.setPcfClose(System.getenv("CPC_END_DATE") + " EST"); - healthCheck.setValidationFile(System.getenv("CPC_PLUS_VALIDATION_FILE")); healthCheck.setJavaVersion(System.getProperty("java.version")); healthCheck.setStatus(HttpStatus.OK); diff --git a/rest-api/src/main/java/gov/cms/qpp/conversion/api/model/HealthCheck.java b/rest-api/src/main/java/gov/cms/qpp/conversion/api/model/HealthCheck.java index 760930bb4..988436f65 100644 --- a/rest-api/src/main/java/gov/cms/qpp/conversion/api/model/HealthCheck.java +++ b/rest-api/src/main/java/gov/cms/qpp/conversion/api/model/HealthCheck.java @@ -11,9 +11,7 @@ public class HealthCheck { private String implementationVersion; private HttpStatus status; private String javaVersion; - private String pcfClose; private String validationUrl; - private String validationFile; public String getImplementationVersion() { return implementationVersion; @@ -33,16 +31,6 @@ public void setValidationUrl(String validationUrl) { this.validationUrl = validationUrl; } - public String getValidationFile() { return validationFile; } - public void setValidationFile(String validationFile) { - this.validationFile = validationFile; - } - - public String getPcfClose() { return pcfClose; } - public void setPcfClose(String pcfClose) { - this.pcfClose = pcfClose; - } - public HttpStatus getStatus() { return status; } public void setStatus(HttpStatus status) { this.status = status; @@ -63,15 +51,13 @@ public boolean equals(Object o) { boolean equals = Objects.equals(implementationVersion, that.implementationVersion); equals &= Objects.equals(status, that.status); equals &= Objects.equals(javaVersion, that.javaVersion); - equals &= Objects.equals(pcfClose, that.pcfClose); equals &= Objects.equals(validationUrl, that.validationUrl); - equals &= Objects.equals(validationFile, that.validationFile); return equals; } @Override public int hashCode() { - return Objects.hash(implementationVersion, status, javaVersion, pcfClose, validationUrl, validationFile); + return Objects.hash(implementationVersion, status, javaVersion, validationUrl); } } diff --git a/test-commons/pom.xml b/test-commons/pom.xml index 721766610..5b0f622b4 100644 --- a/test-commons/pom.xml +++ b/test-commons/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE ../pom.xml @@ -40,6 +40,12 @@ + + com.fasterxml.jackson.core + jackson-core + 2.21.2 + + com.jayway.jsonpath json-path diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml index 05d3db351..676e17f67 100644 --- a/test-coverage/pom.xml +++ b/test-coverage/pom.xml @@ -6,7 +6,7 @@ gov.cms.qpp.conversion qpp-conversion-tool-parent - 2026.03.31.01-RELEASE + 2026.05.01.01-RELEASE ../pom.xml @@ -19,6 +19,12 @@ + + com.fasterxml.jackson.core + jackson-core + 2.21.2 + + gov.cms.qpp.conversion converter