diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0d66505 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,65 @@ +# .dockerignore — files excluded from Docker build context + +# Maven / Gradle build output (compiled on container, not copied) +target/ +!.mvn/wrapper/ + +# IDE files +.idea/ +*.iml +.vscode/ +.eclipse/ +*.swp +*.swo +*~ + +# Git +.git/ +.gitignore +.gitattributes + +# Environment and secrets +.env +.env.* +*.env +!.env.example + +# Documentation (not needed inside the image) +*.md +README.md +CONTEXT.md +DECISIONS.md +SECURITY.md +AGENTS.md +HELP.md +CONTRIBUTING.md +CODE_OF_CONDUCT.md +LICENSE + +# Logs (generated at runtime) +logs/ +*.log + +# Database scripts (only used by PostgreSQL container, not the app) +database/ + +# Docker files (not needed inside the image) +docker-compose.yml +docker-compose.*.yml +Dockerfile +.dockerignore + +# Scripts +script/ + +# CI/CD +.github/ + +# OS junk +.DS_Store +Thumbs.db + +# Dependency vulnerability reports +owasp-suppressions.xml +dependency-check-report.* +target/dependency-check-*/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0f149df --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +# Stage 1: Build — compiles the project and produces the .jar +FROM maven:3.9-eclipse-temurin-17-alpine AS build + +WORKDIR /app + +# Copy pom.xml first to leverage Docker layer caching. +# If pom.xml hasn't changed, this layer is reused and dependencies +# are not downloaded again. +COPY pom.xml . + +# Download all dependencies without compiling. +# This creates a separate cacheable layer independent of source code. +RUN mvn dependency:go-offline -B + +COPY src ./src +RUN mvn package -B -DskipTests + +# Stage 2: Run — lightweight final image, only JRE + .jar +FROM eclipse-temurin:17-jre-alpine AS run + +# Create non-root user for security. +# OWASP A05: never run container processes as root. +RUN addgroup -S wallet && adduser -S wallet -G wallet + +WORKDIR /app + +# Copy the .jar from the build stage and set owner in one step. +# The *.jar pattern works because there is only one .jar in target/ +# (the sources jar is excluded in assembly config). +COPY --from=build --chown=wallet:wallet /app/target/*.jar app.jar + +# Switch to non-root user before running the app. +USER wallet + +# This does NOT open the port — docker-compose or docker run -p does that. +EXPOSE 8080 + +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/docker-compose.yml b/docker-compose.yml index 417ae12..6e1d0c0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,6 +34,32 @@ services: cpus: '0.5' memory: 256M + wallet-api: + build: + context: . + dockerfile: Dockerfile + container_name: secure-wallet-api + restart: no + environment: + SPRING_PROFILES_ACTIVE: dev + # POSTGRES_HOST=postgres because inside the Docker network + # services resolve by service name, not localhost. + POSTGRES_HOST: postgres + POSTGRES_PORT: ${POSTGRES_PORT} + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + # JWT from .env + JWT_SECRET: ${JWT_SECRET} + SERVER_PORT: ${SERVER_PORT:-8080} + ports: + - "${SERVER_PORT:-8080}:${SERVER_PORT:-8080}" + networks: + - wallet-network + depends_on: + postgres: + condition: service_healthy + pgadmin: image: dpage/pgadmin4:latest container_name: secure-wallet-pgadmin