Spaces:
Build error
Build error
Ajay Yadav commited on
Commit ·
688925d
1
Parent(s): 8fb8b38
Initial deployment of da-autocompliance-dev
Browse files- Dockerfile +27 -0
- README.md +34 -6
- build.gradle.kts +70 -0
- src/main/docker/Dockerfile +23 -0
- src/main/docker/Dockerfile.alpine-jlink +43 -0
- src/main/docker/Dockerfile.layered +34 -0
- src/main/docker/Dockerfile.native +20 -0
- src/main/java/com/dalab/autocompliance/DaAutocomplianceApplication.java +30 -0
- src/main/java/com/dalab/autocompliance/config/SpringSecurityAuditorAware.java +31 -0
- src/main/java/com/dalab/autocompliance/controller/ComplianceController.java +160 -0
- src/main/java/com/dalab/autocompliance/dto/AssetComplianceStatusDTO.java +44 -0
- src/main/java/com/dalab/autocompliance/dto/ComplianceControlDTO.java +29 -0
- src/main/java/com/dalab/autocompliance/dto/ComplianceReportDTO.java +59 -0
- src/main/java/com/dalab/autocompliance/dto/ComplianceReportDefinitionDTO.java +27 -0
- src/main/java/com/dalab/autocompliance/dto/ControlEvaluationRequestDTO.java +31 -0
- src/main/java/com/dalab/autocompliance/dto/ControlEvaluationResponseDTO.java +24 -0
- src/main/java/com/dalab/autocompliance/dto/ReportGenerationRequestDTO.java +27 -0
- src/main/java/com/dalab/autocompliance/dto/ReportGenerationResponseDTO.java +23 -0
- src/main/java/com/dalab/autocompliance/dto/ReportJobStatusDTO.java +27 -0
- src/main/java/com/dalab/autocompliance/model/entity/AbstractAuditableEntity.java +38 -0
- src/main/java/com/dalab/autocompliance/model/entity/ComplianceControlEntity.java +74 -0
- src/main/java/com/dalab/autocompliance/model/entity/ComplianceGeneratedReportEntity.java +59 -0
- src/main/java/com/dalab/autocompliance/model/entity/ComplianceReportDefinitionEntity.java +55 -0
- src/main/java/com/dalab/autocompliance/model/entity/ComplianceReportJobEntity.java +56 -0
- src/main/java/com/dalab/autocompliance/model/entity/ControlEvaluationJobEntity.java +67 -0
- src/main/java/com/dalab/autocompliance/model/entity/ReportFindingData.java +26 -0
- src/main/java/com/dalab/autocompliance/model/entity/ReportSummaryData.java +19 -0
- src/main/java/com/dalab/autocompliance/model/mapper/ComplianceControlMapper.java +22 -0
- src/main/java/com/dalab/autocompliance/model/mapper/ComplianceGeneratedReportMapper.java +46 -0
- src/main/java/com/dalab/autocompliance/model/mapper/ComplianceReportDefinitionMapper.java +25 -0
- src/main/java/com/dalab/autocompliance/model/mapper/ComplianceReportJobMapper.java +41 -0
- src/main/java/com/dalab/autocompliance/model/mapper/ControlEvaluationJobMapper.java +37 -0
- src/main/java/com/dalab/autocompliance/model/repository/ComplianceControlRepository.java +22 -0
- src/main/java/com/dalab/autocompliance/model/repository/ComplianceGeneratedReportRepository.java +28 -0
- src/main/java/com/dalab/autocompliance/model/repository/ComplianceReportDefinitionRepository.java +16 -0
- src/main/java/com/dalab/autocompliance/model/repository/ComplianceReportJobRepository.java +18 -0
- src/main/java/com/dalab/autocompliance/model/repository/ControlEvaluationJobRepository.java +19 -0
- src/main/java/com/dalab/autocompliance/service/IComplianceService.java +77 -0
- src/main/java/com/dalab/autocompliance/service/exception/ControlNotFoundException.java +15 -0
- src/main/java/com/dalab/autocompliance/service/exception/GeneratedReportNotFoundException.java +15 -0
- src/main/java/com/dalab/autocompliance/service/exception/ReportDefinitionNotFoundException.java +15 -0
- src/main/java/com/dalab/autocompliance/service/exception/ReportJobNotFoundException.java +15 -0
- src/main/java/com/dalab/autocompliance/service/impl/ComplianceServiceImpl.java +324 -0
- src/main/resources/application.properties +57 -0
- src/test/java/com/dalab/autocompliance/controller/ComplianceControllerTest.java +161 -0
- src/test/java/com/dalab/autocompliance/service/impl/ComplianceServiceImplTest.java +1 -0
Dockerfile
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM openjdk:21-jdk-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
# Install required packages
|
| 6 |
+
RUN apt-get update && apt-get install -y \
|
| 7 |
+
curl \
|
| 8 |
+
wget \
|
| 9 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 10 |
+
|
| 11 |
+
# Copy application files
|
| 12 |
+
COPY . .
|
| 13 |
+
|
| 14 |
+
# Build application (if build.gradle.kts exists)
|
| 15 |
+
RUN if [ -f "build.gradle.kts" ]; then \
|
| 16 |
+
./gradlew build -x test; \
|
| 17 |
+
fi
|
| 18 |
+
|
| 19 |
+
# Expose port
|
| 20 |
+
EXPOSE 8080
|
| 21 |
+
|
| 22 |
+
# Health check
|
| 23 |
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
| 24 |
+
CMD curl -f http://localhost:8080/actuator/health || exit 1
|
| 25 |
+
|
| 26 |
+
# Run application
|
| 27 |
+
CMD ["java", "-jar", "build/libs/da-autocompliance.jar"]
|
README.md
CHANGED
|
@@ -1,10 +1,38 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: docker
|
| 7 |
-
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: da-autocompliance (dev)
|
| 3 |
+
emoji: 🔧
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
sdk: docker
|
| 7 |
+
app_port: 8080
|
| 8 |
---
|
| 9 |
|
| 10 |
+
# da-autocompliance - dev Environment
|
| 11 |
+
|
| 12 |
+
This is the da-autocompliance microservice deployed in the dev environment.
|
| 13 |
+
|
| 14 |
+
## Features
|
| 15 |
+
|
| 16 |
+
- RESTful API endpoints
|
| 17 |
+
- Health monitoring via Actuator
|
| 18 |
+
- JWT authentication integration
|
| 19 |
+
- PostgreSQL database connectivity
|
| 20 |
+
|
| 21 |
+
## API Documentation
|
| 22 |
+
|
| 23 |
+
Once deployed, API documentation will be available at:
|
| 24 |
+
- Swagger UI: https://huggingface.co/spaces/dalabsai/da-autocompliance-dev/swagger-ui.html
|
| 25 |
+
- Health Check: https://huggingface.co/spaces/dalabsai/da-autocompliance-dev/actuator/health
|
| 26 |
+
|
| 27 |
+
## Environment
|
| 28 |
+
|
| 29 |
+
- **Environment**: dev
|
| 30 |
+
- **Port**: 8080
|
| 31 |
+
- **Java Version**: 21
|
| 32 |
+
- **Framework**: Spring Boot
|
| 33 |
+
|
| 34 |
+
## Deployment
|
| 35 |
+
|
| 36 |
+
This service is automatically deployed via the DALab CI/CD pipeline.
|
| 37 |
+
|
| 38 |
+
Last updated: 2025-06-16 23:40:18
|
build.gradle.kts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
plugins {
|
| 2 |
+
id("org.springframework.boot") version "3.2.5"
|
| 3 |
+
id("io.spring.dependency-management") version "1.1.4"
|
| 4 |
+
java
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
group = "com.dalab"
|
| 8 |
+
version = "0.0.1-SNAPSHOT"
|
| 9 |
+
|
| 10 |
+
java {
|
| 11 |
+
sourceCompatibility = JavaVersion.VERSION_17
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
repositories {
|
| 15 |
+
mavenCentral()
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
dependencyManagement {
|
| 19 |
+
imports {
|
| 20 |
+
// Consider adding Spring Cloud BOM if needed for Feign, etc.
|
| 21 |
+
// mavenBom("org.springframework.cloud:spring-cloud-dependencies:YYYY.X.X")
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
val mapstructVersion = "1.5.5.Final"
|
| 26 |
+
|
| 27 |
+
dependencies {
|
| 28 |
+
// Common Spring Boot dependencies
|
| 29 |
+
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
| 30 |
+
implementation("org.springframework.boot:spring-boot-starter-web")
|
| 31 |
+
implementation("org.springframework.boot:spring-boot-starter-validation")
|
| 32 |
+
implementation("org.springframework.boot:spring-boot-starter-security")
|
| 33 |
+
implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server")
|
| 34 |
+
implementation("org.springframework.boot:spring-boot-starter-oauth2-client")
|
| 35 |
+
|
| 36 |
+
// Shared proto dependency
|
| 37 |
+
implementation(project(":da-protos"))
|
| 38 |
+
|
| 39 |
+
// AutoCompliance-specific dependencies
|
| 40 |
+
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
| 41 |
+
implementation("org.springframework.kafka:spring-kafka")
|
| 42 |
+
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0")
|
| 43 |
+
|
| 44 |
+
// MapStruct
|
| 45 |
+
implementation("org.mapstruct:mapstruct:$mapstructVersion")
|
| 46 |
+
annotationProcessor("org.mapstruct:mapstruct-processor:$mapstructVersion")
|
| 47 |
+
annotationProcessor("org.projectlombok:lombok-mapstruct-binding:0.2.0")
|
| 48 |
+
|
| 49 |
+
// Database
|
| 50 |
+
runtimeOnly("org.postgresql:postgresql")
|
| 51 |
+
|
| 52 |
+
// Common development and runtime dependencies
|
| 53 |
+
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
| 54 |
+
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
|
| 55 |
+
|
| 56 |
+
// Lombok
|
| 57 |
+
compileOnly("org.projectlombok:lombok")
|
| 58 |
+
annotationProcessor("org.projectlombok:lombok")
|
| 59 |
+
|
| 60 |
+
// Test dependencies
|
| 61 |
+
testImplementation("org.springframework.boot:spring-boot-starter-test") {
|
| 62 |
+
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
|
| 63 |
+
}
|
| 64 |
+
testImplementation("org.springframework.security:spring-security-test")
|
| 65 |
+
testImplementation("org.springframework.kafka:spring-kafka-test")
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
tasks.named<org.springframework.boot.gradle.tasks.bundling.BootJar>("bootJar") {
|
| 69 |
+
archiveFileName.set("${project.name}.jar")
|
| 70 |
+
}
|
src/main/docker/Dockerfile
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ultra-lean container using Google Distroless
|
| 2 |
+
# Expected final size: ~120-180MB (minimal base + JRE + JAR only)
|
| 3 |
+
|
| 4 |
+
FROM gcr.io/distroless/java21-debian12:nonroot
|
| 5 |
+
|
| 6 |
+
# Set working directory
|
| 7 |
+
WORKDIR /app
|
| 8 |
+
|
| 9 |
+
# Copy JAR file
|
| 10 |
+
COPY build/libs/da-autocompliance.jar app.jar
|
| 11 |
+
|
| 12 |
+
# Expose standard Spring Boot port
|
| 13 |
+
EXPOSE 8080
|
| 14 |
+
|
| 15 |
+
# Run application (distroless has no shell, so use exec form)
|
| 16 |
+
ENTRYPOINT ["java", \
|
| 17 |
+
"-XX:+UseContainerSupport", \
|
| 18 |
+
"-XX:MaxRAMPercentage=75.0", \
|
| 19 |
+
"-XX:+UseG1GC", \
|
| 20 |
+
"-XX:+UseStringDeduplication", \
|
| 21 |
+
"-Djava.security.egd=file:/dev/./urandom", \
|
| 22 |
+
"-Dspring.backgroundpreinitializer.ignore=true", \
|
| 23 |
+
"-jar", "app.jar"]
|
src/main/docker/Dockerfile.alpine-jlink
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ultra-minimal Alpine + Custom JRE
|
| 2 |
+
# Expected size: ~120-160MB
|
| 3 |
+
|
| 4 |
+
# Stage 1: Create custom JRE with only needed modules
|
| 5 |
+
FROM eclipse-temurin:21-jdk-alpine as jre-builder
|
| 6 |
+
WORKDIR /app
|
| 7 |
+
|
| 8 |
+
# Analyze JAR to find required modules
|
| 9 |
+
COPY build/libs/*.jar app.jar
|
| 10 |
+
RUN jdeps --ignore-missing-deps --print-module-deps app.jar > modules.txt
|
| 11 |
+
|
| 12 |
+
# Create minimal JRE with only required modules
|
| 13 |
+
RUN jlink \
|
| 14 |
+
--add-modules $(cat modules.txt),java.logging,java.xml,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
|
| 15 |
+
--strip-debug \
|
| 16 |
+
--no-man-pages \
|
| 17 |
+
--no-header-files \
|
| 18 |
+
--compress=2 \
|
| 19 |
+
--output /custom-jre
|
| 20 |
+
|
| 21 |
+
# Stage 2: Production image
|
| 22 |
+
FROM alpine:3.19
|
| 23 |
+
RUN apk add --no-cache tzdata && \
|
| 24 |
+
addgroup -g 1001 -S appgroup && \
|
| 25 |
+
adduser -u 1001 -S appuser -G appgroup
|
| 26 |
+
|
| 27 |
+
# Copy custom JRE
|
| 28 |
+
COPY --from=jre-builder /custom-jre /opt/java
|
| 29 |
+
ENV JAVA_HOME=/opt/java
|
| 30 |
+
ENV PATH="$JAVA_HOME/bin:$PATH"
|
| 31 |
+
|
| 32 |
+
WORKDIR /app
|
| 33 |
+
COPY build/libs/*.jar app.jar
|
| 34 |
+
RUN chown appuser:appgroup app.jar
|
| 35 |
+
|
| 36 |
+
USER appuser
|
| 37 |
+
EXPOSE 8080
|
| 38 |
+
|
| 39 |
+
ENTRYPOINT ["java", \
|
| 40 |
+
"-XX:+UseContainerSupport", \
|
| 41 |
+
"-XX:MaxRAMPercentage=70.0", \
|
| 42 |
+
"-XX:+UseG1GC", \
|
| 43 |
+
"-jar", "app.jar"]
|
src/main/docker/Dockerfile.layered
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Ultra-optimized layered build using Distroless
|
| 2 |
+
# Expected size: ~180-220MB with better caching
|
| 3 |
+
|
| 4 |
+
FROM gcr.io/distroless/java21-debian12:nonroot as base
|
| 5 |
+
|
| 6 |
+
# Stage 1: Extract JAR layers for optimal caching
|
| 7 |
+
FROM eclipse-temurin:21-jdk-alpine as extractor
|
| 8 |
+
WORKDIR /app
|
| 9 |
+
COPY build/libs/*.jar app.jar
|
| 10 |
+
RUN java -Djarmode=layertools -jar app.jar extract
|
| 11 |
+
|
| 12 |
+
# Stage 2: Production image with extracted layers
|
| 13 |
+
FROM base
|
| 14 |
+
WORKDIR /app
|
| 15 |
+
|
| 16 |
+
# Copy layers in dependency order (best caching)
|
| 17 |
+
COPY --from=extractor /app/dependencies/ ./
|
| 18 |
+
COPY --from=extractor /app/spring-boot-loader/ ./
|
| 19 |
+
COPY --from=extractor /app/snapshot-dependencies/ ./
|
| 20 |
+
COPY --from=extractor /app/application/ ./
|
| 21 |
+
|
| 22 |
+
EXPOSE 8080
|
| 23 |
+
|
| 24 |
+
# Optimized JVM settings for micro-containers
|
| 25 |
+
ENTRYPOINT ["java", \
|
| 26 |
+
"-XX:+UseContainerSupport", \
|
| 27 |
+
"-XX:MaxRAMPercentage=70.0", \
|
| 28 |
+
"-XX:+UseG1GC", \
|
| 29 |
+
"-XX:+UseStringDeduplication", \
|
| 30 |
+
"-XX:+CompactStrings", \
|
| 31 |
+
"-Xshare:on", \
|
| 32 |
+
"-Djava.security.egd=file:/dev/./urandom", \
|
| 33 |
+
"-Dspring.backgroundpreinitializer.ignore=true", \
|
| 34 |
+
"org.springframework.boot.loader.JarLauncher"]
|
src/main/docker/Dockerfile.native
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# GraalVM Native Image - Ultra-fast startup, tiny size
|
| 2 |
+
# Expected size: ~50-80MB, startup <100ms
|
| 3 |
+
# Note: Requires native compilation support in Spring Boot
|
| 4 |
+
|
| 5 |
+
# Stage 1: Native compilation
|
| 6 |
+
FROM ghcr.io/graalvm/graalvm-ce:ol9-java21 as native-builder
|
| 7 |
+
WORKDIR /app
|
| 8 |
+
|
| 9 |
+
# Install native-image
|
| 10 |
+
RUN gu install native-image
|
| 11 |
+
|
| 12 |
+
# Copy source and build native executable
|
| 13 |
+
COPY . .
|
| 14 |
+
RUN ./gradlew nativeCompile
|
| 15 |
+
|
| 16 |
+
# Stage 2: Minimal runtime
|
| 17 |
+
FROM scratch
|
| 18 |
+
COPY --from=native-builder /app/build/native/nativeCompile/app /app
|
| 19 |
+
EXPOSE 8080
|
| 20 |
+
ENTRYPOINT ["/app"]
|
src/main/java/com/dalab/autocompliance/DaAutocomplianceApplication.java
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance;
|
| 2 |
+
|
| 3 |
+
import io.swagger.v3.oas.models.OpenAPI;
|
| 4 |
+
import io.swagger.v3.oas.models.info.Info;
|
| 5 |
+
import io.swagger.v3.oas.models.info.License;
|
| 6 |
+
import org.springframework.boot.SpringApplication;
|
| 7 |
+
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
| 8 |
+
import org.springframework.context.annotation.Bean;
|
| 9 |
+
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
| 10 |
+
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
| 11 |
+
|
| 12 |
+
@SpringBootApplication
|
| 13 |
+
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
|
| 14 |
+
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
|
| 15 |
+
public class DaAutocomplianceApplication {
|
| 16 |
+
|
| 17 |
+
public static void main(String[] args) {
|
| 18 |
+
SpringApplication.run(DaAutocomplianceApplication.class, args);
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
@Bean
|
| 22 |
+
public OpenAPI customOpenAPI() {
|
| 23 |
+
return new OpenAPI()
|
| 24 |
+
.info(new Info().title("DALab AutoCompliance Service API")
|
| 25 |
+
.version("v1")
|
| 26 |
+
.description("API for managing compliance reports, checks, and asset compliance status.")
|
| 27 |
+
.termsOfService("http://swagger.io/terms/")
|
| 28 |
+
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
|
| 29 |
+
}
|
| 30 |
+
}
|
src/main/java/com/dalab/autocompliance/config/SpringSecurityAuditorAware.java
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.config;
|
| 2 |
+
|
| 3 |
+
import org.springframework.data.domain.AuditorAware;
|
| 4 |
+
import org.springframework.security.core.Authentication;
|
| 5 |
+
import org.springframework.security.core.context.SecurityContextHolder;
|
| 6 |
+
import org.springframework.security.core.userdetails.User;
|
| 7 |
+
import org.springframework.stereotype.Component;
|
| 8 |
+
|
| 9 |
+
import java.util.Optional;
|
| 10 |
+
|
| 11 |
+
@Component("auditorProvider")
|
| 12 |
+
public class SpringSecurityAuditorAware implements AuditorAware<String> {
|
| 13 |
+
|
| 14 |
+
@Override
|
| 15 |
+
public Optional<String> getCurrentAuditor() {
|
| 16 |
+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
| 17 |
+
|
| 18 |
+
if (authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal() instanceof String && "anonymousUser".equals(authentication.getPrincipal())) {
|
| 19 |
+
return Optional.of("system"); // Default to system if no user or anonymous
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
Object principal = authentication.getPrincipal();
|
| 23 |
+
if (principal instanceof User) {
|
| 24 |
+
return Optional.of(((User) principal).getUsername());
|
| 25 |
+
} else if (principal instanceof String) {
|
| 26 |
+
return Optional.of((String) principal);
|
| 27 |
+
}
|
| 28 |
+
// For other principal types, you might need custom logic or return a default
|
| 29 |
+
return Optional.of("system");
|
| 30 |
+
}
|
| 31 |
+
}
|
src/main/java/com/dalab/autocompliance/controller/ComplianceController.java
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.controller;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.dto.ComplianceReportDefinitionDTO;
|
| 4 |
+
import com.dalab.autocompliance.dto.ReportGenerationRequestDTO;
|
| 5 |
+
import com.dalab.autocompliance.dto.ReportGenerationResponseDTO;
|
| 6 |
+
import com.dalab.autocompliance.dto.ReportJobStatusDTO;
|
| 7 |
+
import com.dalab.autocompliance.dto.ComplianceReportDTO;
|
| 8 |
+
import com.dalab.autocompliance.dto.AssetComplianceStatusDTO;
|
| 9 |
+
import com.dalab.autocompliance.dto.ComplianceControlDTO;
|
| 10 |
+
import com.dalab.autocompliance.dto.ControlEvaluationRequestDTO;
|
| 11 |
+
import com.dalab.autocompliance.dto.ControlEvaluationResponseDTO;
|
| 12 |
+
import com.dalab.autocompliance.service.IComplianceService;
|
| 13 |
+
import io.swagger.v3.oas.annotations.Operation;
|
| 14 |
+
import io.swagger.v3.oas.annotations.Parameter;
|
| 15 |
+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
| 16 |
+
import io.swagger.v3.oas.annotations.tags.Tag;
|
| 17 |
+
import jakarta.validation.Valid;
|
| 18 |
+
import lombok.RequiredArgsConstructor;
|
| 19 |
+
import org.springframework.http.HttpStatus;
|
| 20 |
+
import org.springframework.http.ResponseEntity;
|
| 21 |
+
import org.springframework.security.access.prepost.PreAuthorize;
|
| 22 |
+
import org.springframework.web.bind.annotation.*;
|
| 23 |
+
|
| 24 |
+
import java.util.List;
|
| 25 |
+
|
| 26 |
+
@RestController
|
| 27 |
+
@RequestMapping("/api/v1/compliance")
|
| 28 |
+
@Tag(name = "Compliance API", description = "APIs for managing compliance checks, reports, and evaluations")
|
| 29 |
+
@RequiredArgsConstructor
|
| 30 |
+
public class ComplianceController {
|
| 31 |
+
|
| 32 |
+
private final IComplianceService complianceService;
|
| 33 |
+
|
| 34 |
+
@Operation(summary = "List available compliance report definitions",
|
| 35 |
+
description = "Provides a list of all configured compliance report types that can be generated.",
|
| 36 |
+
responses = {
|
| 37 |
+
@ApiResponse(responseCode = "200", description = "Successfully retrieved report definitions")
|
| 38 |
+
})
|
| 39 |
+
@GetMapping("/reports")
|
| 40 |
+
@PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')") // Broad access to see what reports are available
|
| 41 |
+
public ResponseEntity<List<ComplianceReportDefinitionDTO>> listAvailableReportDefinitions() {
|
| 42 |
+
List<ComplianceReportDefinitionDTO> definitions = complianceService.listAvailableReportDefinitions();
|
| 43 |
+
return ResponseEntity.ok(definitions);
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
@Operation(summary = "Generate a compliance report",
|
| 47 |
+
description = "Triggers the asynchronous generation of a specific compliance report based on its type and provided parameters.",
|
| 48 |
+
responses = {
|
| 49 |
+
@ApiResponse(responseCode = "202", description = "Report generation request accepted."),
|
| 50 |
+
@ApiResponse(responseCode = "400", description = "Invalid request (e.g., missing parameters, report type not found)"),
|
| 51 |
+
@ApiResponse(responseCode = "404", description = "Report type not found") // Covered by 400 in current impl
|
| 52 |
+
})
|
| 53 |
+
@PostMapping("/reports/{reportType}/generate")
|
| 54 |
+
@PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD')") // Users who can trigger generation
|
| 55 |
+
public ResponseEntity<ReportGenerationResponseDTO> generateComplianceReport(
|
| 56 |
+
@Parameter(description = "Unique identifier of the report type to generate", required = true)
|
| 57 |
+
@PathVariable String reportType,
|
| 58 |
+
@Parameter(description = "Parameters required for the report generation", required = true)
|
| 59 |
+
@Valid @RequestBody ReportGenerationRequestDTO request) {
|
| 60 |
+
|
| 61 |
+
ReportGenerationResponseDTO response = complianceService.generateComplianceReport(reportType, request);
|
| 62 |
+
|
| 63 |
+
if ("FAILED_VALIDATION".equals(response.getStatus())) {
|
| 64 |
+
return ResponseEntity.badRequest().body(response);
|
| 65 |
+
}
|
| 66 |
+
return ResponseEntity.status(HttpStatus.ACCEPTED).body(response);
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
@Operation(summary = "Get compliance report generation job status",
|
| 70 |
+
description = "Retrieves the current status of an asynchronous report generation job.",
|
| 71 |
+
responses = {
|
| 72 |
+
@ApiResponse(responseCode = "200", description = "Successfully retrieved job status."),
|
| 73 |
+
@ApiResponse(responseCode = "404", description = "Job ID not found.")
|
| 74 |
+
})
|
| 75 |
+
@GetMapping("/reports/jobs/{jobId}")
|
| 76 |
+
@PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')") // Users who can view job status
|
| 77 |
+
public ResponseEntity<ReportJobStatusDTO> getReportGenerationJobStatus(
|
| 78 |
+
@Parameter(description = "ID of the report generation job", required = true)
|
| 79 |
+
@PathVariable String jobId) {
|
| 80 |
+
ReportJobStatusDTO jobStatus = complianceService.getReportGenerationJobStatus(jobId);
|
| 81 |
+
if ("NOT_FOUND".equals(jobStatus.getStatus())) {
|
| 82 |
+
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(jobStatus);
|
| 83 |
+
}
|
| 84 |
+
return ResponseEntity.ok(jobStatus);
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
@Operation(summary = "Retrieve a generated compliance report",
|
| 88 |
+
description = "Fetches the detailed contents of a previously generated compliance report.",
|
| 89 |
+
responses = {
|
| 90 |
+
@ApiResponse(responseCode = "200", description = "Successfully retrieved the report."),
|
| 91 |
+
@ApiResponse(responseCode = "404", description = "Report ID not found.")
|
| 92 |
+
})
|
| 93 |
+
@GetMapping("/reports/results/{reportId}")
|
| 94 |
+
@PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')") // Users who can view reports
|
| 95 |
+
public ResponseEntity<ComplianceReportDTO> getGeneratedReport(
|
| 96 |
+
@Parameter(description = "ID of the generated compliance report", required = true)
|
| 97 |
+
@PathVariable String reportId) {
|
| 98 |
+
ComplianceReportDTO report = complianceService.getGeneratedReport(reportId);
|
| 99 |
+
if (report == null) {
|
| 100 |
+
return ResponseEntity.notFound().build();
|
| 101 |
+
}
|
| 102 |
+
return ResponseEntity.ok(report);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
@Operation(summary = "Get compliance status for an asset",
|
| 106 |
+
description = "Retrieves the overall compliance status and recent findings for a specific asset.",
|
| 107 |
+
responses = {
|
| 108 |
+
@ApiResponse(responseCode = "200", description = "Successfully retrieved asset compliance status."),
|
| 109 |
+
@ApiResponse(responseCode = "404", description = "Asset ID not found or no compliance data available.")
|
| 110 |
+
})
|
| 111 |
+
@GetMapping("/assets/{assetId}/status")
|
| 112 |
+
@PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')")
|
| 113 |
+
public ResponseEntity<AssetComplianceStatusDTO> getAssetComplianceStatus(
|
| 114 |
+
@Parameter(description = "ID of the asset (e.g., cloud resource ID)", required = true)
|
| 115 |
+
@PathVariable String assetId) {
|
| 116 |
+
AssetComplianceStatusDTO status = complianceService.getAssetComplianceStatus(assetId);
|
| 117 |
+
if ("UNKNOWN".equals(status.getOverallComplianceStatus()) && status.getRelevantReportIds() == null) { // Basic check for 'not found'
|
| 118 |
+
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(status); // Provide status with UNKNOWN if created that way
|
| 119 |
+
}
|
| 120 |
+
return ResponseEntity.ok(status);
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
@Operation(summary = "List available compliance controls",
|
| 124 |
+
description = "Provides a list of all configured and typically enabled compliance controls that can be evaluated.",
|
| 125 |
+
responses = {
|
| 126 |
+
@ApiResponse(responseCode = "200", description = "Successfully retrieved compliance controls")
|
| 127 |
+
})
|
| 128 |
+
@GetMapping("/controls")
|
| 129 |
+
@PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')") // Broad access to see available controls
|
| 130 |
+
public ResponseEntity<List<ComplianceControlDTO>> listAvailableControls() {
|
| 131 |
+
List<ComplianceControlDTO> controls = complianceService.listAvailableControls();
|
| 132 |
+
return ResponseEntity.ok(controls);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
@Operation(summary = "Evaluate a compliance control",
|
| 136 |
+
description = "Triggers the asynchronous evaluation of a specific compliance control.",
|
| 137 |
+
responses = {
|
| 138 |
+
@ApiResponse(responseCode = "202", description = "Control evaluation request accepted."),
|
| 139 |
+
@ApiResponse(responseCode = "400", description = "Invalid request (e.g., missing parameters, control not enabled)"),
|
| 140 |
+
@ApiResponse(responseCode = "404", description = "Control ID not found")
|
| 141 |
+
})
|
| 142 |
+
@PostMapping("/controls/{controlId}/evaluate")
|
| 143 |
+
@PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD')") // Users who can trigger evaluations
|
| 144 |
+
public ResponseEntity<ControlEvaluationResponseDTO> evaluateControl(
|
| 145 |
+
@Parameter(description = "Unique identifier of the control to evaluate", required = true)
|
| 146 |
+
@PathVariable String controlId,
|
| 147 |
+
@Parameter(description = "Parameters for the control evaluation", required = true)
|
| 148 |
+
@Valid @RequestBody ControlEvaluationRequestDTO request) {
|
| 149 |
+
|
| 150 |
+
ControlEvaluationResponseDTO response = complianceService.evaluateControl(controlId, request);
|
| 151 |
+
|
| 152 |
+
if ("FAILED_VALIDATION".equals(response.getStatus())) {
|
| 153 |
+
return ResponseEntity.badRequest().body(response);
|
| 154 |
+
}
|
| 155 |
+
// Assuming ControlNotFoundException is handled by a global exception handler to return 404
|
| 156 |
+
return ResponseEntity.status(HttpStatus.ACCEPTED).body(response);
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
// TODO: Add endpoint for GET /controls/evaluations/{jobId} (status of a control evaluation job)
|
| 160 |
+
}
|
src/main/java/com/dalab/autocompliance/dto/AssetComplianceStatusDTO.java
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.dto;
|
| 2 |
+
|
| 3 |
+
import lombok.Builder;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.NoArgsConstructor;
|
| 6 |
+
import lombok.AllArgsConstructor;
|
| 7 |
+
|
| 8 |
+
import java.time.LocalDateTime;
|
| 9 |
+
import java.util.List;
|
| 10 |
+
import java.util.Map;
|
| 11 |
+
|
| 12 |
+
/**
|
| 13 |
+
* DTO representing the compliance status of a specific asset.
|
| 14 |
+
*/
|
| 15 |
+
@Data
|
| 16 |
+
@Builder
|
| 17 |
+
@NoArgsConstructor
|
| 18 |
+
@AllArgsConstructor
|
| 19 |
+
public class AssetComplianceStatusDTO {
|
| 20 |
+
private String assetId;
|
| 21 |
+
private String assetType; // e.g., GCP_COMPUTE_INSTANCE, AWS_S3_BUCKET
|
| 22 |
+
private String assetName; // User-friendly name if available
|
| 23 |
+
private String overallComplianceStatus; // e.g., COMPLIANT, NON_COMPLIANT, PARTIALLY_COMPLIANT, UNKNOWN
|
| 24 |
+
private LocalDateTime lastEvaluatedAt;
|
| 25 |
+
private int totalChecksApplied;
|
| 26 |
+
private int compliantChecks;
|
| 27 |
+
private int nonCompliantChecks;
|
| 28 |
+
private List<ComplianceFindingSummaryDTO> recentNonCompliantFindings; // Summaries of key issues
|
| 29 |
+
|
| 30 |
+
// Could also include links to full reports involving this asset
|
| 31 |
+
private List<String> relevantReportIds;
|
| 32 |
+
|
| 33 |
+
@Data
|
| 34 |
+
@Builder
|
| 35 |
+
@NoArgsConstructor
|
| 36 |
+
@AllArgsConstructor
|
| 37 |
+
public static class ComplianceFindingSummaryDTO {
|
| 38 |
+
private String checkId;
|
| 39 |
+
private String description;
|
| 40 |
+
private String severity;
|
| 41 |
+
private String reportId; // Report where this finding was detailed
|
| 42 |
+
private LocalDateTime findingTimestamp;
|
| 43 |
+
}
|
| 44 |
+
}
|
src/main/java/com/dalab/autocompliance/dto/ComplianceControlDTO.java
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.dto;
|
| 2 |
+
|
| 3 |
+
import lombok.Builder;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.NoArgsConstructor;
|
| 6 |
+
import lombok.AllArgsConstructor;
|
| 7 |
+
|
| 8 |
+
import java.util.List;
|
| 9 |
+
import java.util.Map;
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* DTO representing a single, executable compliance control or check.
|
| 13 |
+
*/
|
| 14 |
+
@Data
|
| 15 |
+
@Builder
|
| 16 |
+
@NoArgsConstructor
|
| 17 |
+
@AllArgsConstructor
|
| 18 |
+
public class ComplianceControlDTO {
|
| 19 |
+
private String controlId; // Unique identifier for the control (e.g., "CIS-GCP-1.1", "PCI-REQ-3.4")
|
| 20 |
+
private String name; // Short, human-readable name of the control
|
| 21 |
+
private String description; // Detailed description of what the control checks
|
| 22 |
+
private String severity; // e.g., CRITICAL, HIGH, MEDIUM, LOW, INFORMATIONAL
|
| 23 |
+
private List<String> applicableFrameworks; // e.g., ["CIS Benchmark v1.3", "PCI DSS v3.2.1"]
|
| 24 |
+
private List<String> targetAssetTypes; // Asset types this control applies to (e.g., "GCP_BUCKET", "AWS_IAM_USER")
|
| 25 |
+
private String remediationSteps; // Suggested steps to remediate a non-compliant finding
|
| 26 |
+
private Map<String, String> evaluationParametersDefinition; // Parameters needed to evaluate this control (name: type)
|
| 27 |
+
private String detailsLink; // Link to external documentation for this control
|
| 28 |
+
private boolean enabled; // Whether this control is currently active for evaluation
|
| 29 |
+
}
|
src/main/java/com/dalab/autocompliance/dto/ComplianceReportDTO.java
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.dto;
|
| 2 |
+
|
| 3 |
+
import lombok.Builder;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.NoArgsConstructor;
|
| 6 |
+
import lombok.AllArgsConstructor;
|
| 7 |
+
|
| 8 |
+
import java.time.LocalDateTime;
|
| 9 |
+
import java.util.List;
|
| 10 |
+
import java.util.Map;
|
| 11 |
+
|
| 12 |
+
/**
|
| 13 |
+
* DTO representing a generated compliance report.
|
| 14 |
+
*/
|
| 15 |
+
@Data
|
| 16 |
+
@Builder
|
| 17 |
+
@NoArgsConstructor
|
| 18 |
+
@AllArgsConstructor
|
| 19 |
+
public class ComplianceReportDTO {
|
| 20 |
+
private String reportId; // Unique ID of this generated report instance
|
| 21 |
+
private String reportType; // e.g., "cis-gcp-foundations-v1.3"
|
| 22 |
+
private String displayName; // User-friendly name of the report type
|
| 23 |
+
private LocalDateTime generationTimestamp;
|
| 24 |
+
private String overallStatus; // e.g., COMPLIANT, NON_COMPLIANT, PARTIALLY_COMPLIANT, ERROR
|
| 25 |
+
private Map<String, Object> generationParameters; // Parameters used to generate this report
|
| 26 |
+
|
| 27 |
+
private SummaryDTO summary; // High-level summary statistics
|
| 28 |
+
private List<FindingDTO> findings; // Detailed list of findings
|
| 29 |
+
|
| 30 |
+
// Nested DTOs for structure
|
| 31 |
+
@Data
|
| 32 |
+
@Builder
|
| 33 |
+
@NoArgsConstructor
|
| 34 |
+
@AllArgsConstructor
|
| 35 |
+
public static class SummaryDTO {
|
| 36 |
+
private int totalChecks;
|
| 37 |
+
private int compliantChecks;
|
| 38 |
+
private int nonCompliantChecks;
|
| 39 |
+
private int errorChecks;
|
| 40 |
+
private double complianceScore; // e.g., percentage
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
@Data
|
| 44 |
+
@Builder
|
| 45 |
+
@NoArgsConstructor
|
| 46 |
+
@AllArgsConstructor
|
| 47 |
+
public static class FindingDTO {
|
| 48 |
+
private String checkId; // Unique identifier for the specific check/control
|
| 49 |
+
private String description;
|
| 50 |
+
private String assetId; // ID of the asset evaluated
|
| 51 |
+
private String assetType;
|
| 52 |
+
private String assetName; // User-friendly name of the asset
|
| 53 |
+
private String status; // COMPLIANT, NON_COMPLIANT, ERROR, NOT_APPLICABLE
|
| 54 |
+
private String severity; // INFO, LOW, MEDIUM, HIGH, CRITICAL
|
| 55 |
+
private String recommendation;
|
| 56 |
+
private Map<String, Object> details; // Specific details about the finding
|
| 57 |
+
private String evidenceLink; // Link to evidence if applicable
|
| 58 |
+
}
|
| 59 |
+
}
|
src/main/java/com/dalab/autocompliance/dto/ComplianceReportDefinitionDTO.java
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.dto;
|
| 2 |
+
|
| 3 |
+
import lombok.Builder;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.NoArgsConstructor;
|
| 6 |
+
import lombok.AllArgsConstructor;
|
| 7 |
+
|
| 8 |
+
import java.util.List;
|
| 9 |
+
import java.util.Map;
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* DTO representing the definition of a compliance report type.
|
| 13 |
+
*/
|
| 14 |
+
@Data
|
| 15 |
+
@Builder
|
| 16 |
+
@NoArgsConstructor
|
| 17 |
+
@AllArgsConstructor
|
| 18 |
+
public class ComplianceReportDefinitionDTO {
|
| 19 |
+
private String reportType; // Unique identifier for the report type (e.g., "pci-dss-q1", "cis-benchmark-gcp")
|
| 20 |
+
private String displayName; // User-friendly name (e.g., "PCI DSS Requirement 1 Check", "CIS Google Cloud Platform Foundation Benchmark")
|
| 21 |
+
private String description;
|
| 22 |
+
private String version; // Version of the report definition/benchmark
|
| 23 |
+
private List<String> applicableComplianceFrameworks; // e.g., ["PCI DSS v3.2.1", "HIPAA"]
|
| 24 |
+
private List<String> targetAssetTypes; // e.g., ["GCP_COMPUTE_INSTANCE", "AWS_S3_BUCKET"]
|
| 25 |
+
private Map<String, String> generationParameters; // Key-value pairs for parameters needed to generate this report (e.g., {"gcpProjectId": "string"})
|
| 26 |
+
private String detailsLink; // Link to more information about this compliance check/report
|
| 27 |
+
}
|
src/main/java/com/dalab/autocompliance/dto/ControlEvaluationRequestDTO.java
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.dto;
|
| 2 |
+
|
| 3 |
+
import lombok.Builder;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.NoArgsConstructor;
|
| 6 |
+
import lombok.AllArgsConstructor;
|
| 7 |
+
|
| 8 |
+
import jakarta.validation.constraints.NotEmpty;
|
| 9 |
+
import java.util.List;
|
| 10 |
+
import java.util.Map;
|
| 11 |
+
|
| 12 |
+
/**
|
| 13 |
+
* DTO for requesting the evaluation of a specific compliance control.
|
| 14 |
+
*/
|
| 15 |
+
@Data
|
| 16 |
+
@Builder
|
| 17 |
+
@NoArgsConstructor
|
| 18 |
+
@AllArgsConstructor
|
| 19 |
+
public class ControlEvaluationRequestDTO {
|
| 20 |
+
|
| 21 |
+
// Specific assets to target for this evaluation. If empty, might apply to all relevant assets.
|
| 22 |
+
private List<String> targetAssetIds;
|
| 23 |
+
|
| 24 |
+
// Override or provide specific parameters for this evaluation run for the control.
|
| 25 |
+
// These would align with or override those in ComplianceControlDTO.evaluationParametersDefinition.
|
| 26 |
+
private Map<String, Object> evaluationParameters;
|
| 27 |
+
|
| 28 |
+
private String triggeredBy; // Optional: User or system that triggered the evaluation
|
| 29 |
+
private String notificationEmail; // Optional: Email to notify upon completion/failure
|
| 30 |
+
private boolean forceReevaluation; // Optional: If true, re-evaluate even if recent results exist
|
| 31 |
+
}
|
src/main/java/com/dalab/autocompliance/dto/ControlEvaluationResponseDTO.java
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.dto;
|
| 2 |
+
|
| 3 |
+
import lombok.Builder;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.NoArgsConstructor;
|
| 6 |
+
import lombok.AllArgsConstructor;
|
| 7 |
+
|
| 8 |
+
import java.time.LocalDateTime;
|
| 9 |
+
|
| 10 |
+
/**
|
| 11 |
+
* DTO representing the response after submitting a control evaluation request.
|
| 12 |
+
*/
|
| 13 |
+
@Data
|
| 14 |
+
@Builder
|
| 15 |
+
@NoArgsConstructor
|
| 16 |
+
@AllArgsConstructor
|
| 17 |
+
public class ControlEvaluationResponseDTO {
|
| 18 |
+
private String jobId; // ID of the asynchronous evaluation job
|
| 19 |
+
private String controlId;
|
| 20 |
+
private String status; // e.g., ACCEPTED, FAILED_VALIDATION, QUEUED
|
| 21 |
+
private LocalDateTime submittedAt;
|
| 22 |
+
private String message; // e.g., "Control evaluation accepted and queued.", "Invalid parameters for control."
|
| 23 |
+
private int targetedAssetCount; // Number of assets targeted for this evaluation run
|
| 24 |
+
}
|
src/main/java/com/dalab/autocompliance/dto/ReportGenerationRequestDTO.java
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.dto;
|
| 2 |
+
|
| 3 |
+
import lombok.Builder;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.NoArgsConstructor;
|
| 6 |
+
import lombok.AllArgsConstructor;
|
| 7 |
+
|
| 8 |
+
import jakarta.validation.constraints.NotEmpty;
|
| 9 |
+
import java.util.Map;
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* DTO for requesting the generation of a specific compliance report.
|
| 13 |
+
*/
|
| 14 |
+
@Data
|
| 15 |
+
@Builder
|
| 16 |
+
@NoArgsConstructor
|
| 17 |
+
@AllArgsConstructor
|
| 18 |
+
public class ReportGenerationRequestDTO {
|
| 19 |
+
|
| 20 |
+
// Parameters required for this specific report type, matching those defined in ComplianceReportDefinitionDTO.generationParameters
|
| 21 |
+
// For example, {"gcpProjectId": "my-gcp-project", "targetRegions": ["us-central1", "us-east1"]}
|
| 22 |
+
@NotEmpty(message = "Generation parameters cannot be empty.")
|
| 23 |
+
private Map<String, Object> parameters;
|
| 24 |
+
|
| 25 |
+
private String triggeredBy; // Optional: User or system that triggered the generation
|
| 26 |
+
private String notificationEmail; // Optional: Email to notify upon completion/failure
|
| 27 |
+
}
|
src/main/java/com/dalab/autocompliance/dto/ReportGenerationResponseDTO.java
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.dto;
|
| 2 |
+
|
| 3 |
+
import lombok.Builder;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.NoArgsConstructor;
|
| 6 |
+
import lombok.AllArgsConstructor;
|
| 7 |
+
|
| 8 |
+
import java.time.LocalDateTime;
|
| 9 |
+
|
| 10 |
+
/**
|
| 11 |
+
* DTO representing the response after submitting a report generation request.
|
| 12 |
+
*/
|
| 13 |
+
@Data
|
| 14 |
+
@Builder
|
| 15 |
+
@NoArgsConstructor
|
| 16 |
+
@AllArgsConstructor
|
| 17 |
+
public class ReportGenerationResponseDTO {
|
| 18 |
+
private String jobId; // ID of the asynchronous generation job
|
| 19 |
+
private String reportType;
|
| 20 |
+
private String status; // e.g., ACCEPTED, FAILED_VALIDATION, QUEUED
|
| 21 |
+
private LocalDateTime submittedAt;
|
| 22 |
+
private String message; // e.g., "Report generation accepted and queued.", "Invalid parameters for report type."
|
| 23 |
+
}
|
src/main/java/com/dalab/autocompliance/dto/ReportJobStatusDTO.java
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.dto;
|
| 2 |
+
|
| 3 |
+
import lombok.Builder;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.NoArgsConstructor;
|
| 6 |
+
import lombok.AllArgsConstructor;
|
| 7 |
+
|
| 8 |
+
import java.time.LocalDateTime;
|
| 9 |
+
|
| 10 |
+
/**
|
| 11 |
+
* DTO for representing the status of a compliance report generation job.
|
| 12 |
+
*/
|
| 13 |
+
@Data
|
| 14 |
+
@Builder
|
| 15 |
+
@NoArgsConstructor
|
| 16 |
+
@AllArgsConstructor
|
| 17 |
+
public class ReportJobStatusDTO {
|
| 18 |
+
private String jobId;
|
| 19 |
+
private String reportType;
|
| 20 |
+
private String status; // e.g., QUEUED, PROCESSING, COMPLETED_SUCCESS, COMPLETED_FAILURE, NOT_FOUND
|
| 21 |
+
private LocalDateTime submittedAt;
|
| 22 |
+
private LocalDateTime startedAt;
|
| 23 |
+
private LocalDateTime completedAt;
|
| 24 |
+
private String message; // e.g., "Processing started", "Report generated successfully", "Failed due to: ..."
|
| 25 |
+
private String reportId; // ID of the generated report if completed successfully
|
| 26 |
+
private String downloadLink; // Link to download the report if applicable
|
| 27 |
+
}
|
src/main/java/com/dalab/autocompliance/model/entity/AbstractAuditableEntity.java
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.entity;
|
| 2 |
+
|
| 3 |
+
import jakarta.persistence.Column;
|
| 4 |
+
import jakarta.persistence.EntityListeners;
|
| 5 |
+
import jakarta.persistence.MappedSuperclass;
|
| 6 |
+
import lombok.Data;
|
| 7 |
+
import org.springframework.data.annotation.CreatedBy;
|
| 8 |
+
import org.springframework.data.annotation.CreatedDate;
|
| 9 |
+
import org.springframework.data.annotation.LastModifiedBy;
|
| 10 |
+
import org.springframework.data.annotation.LastModifiedDate;
|
| 11 |
+
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
| 12 |
+
|
| 13 |
+
import java.io.Serializable;
|
| 14 |
+
import java.time.Instant;
|
| 15 |
+
|
| 16 |
+
@Data
|
| 17 |
+
@MappedSuperclass
|
| 18 |
+
@EntityListeners(AuditingEntityListener.class)
|
| 19 |
+
public abstract class AbstractAuditableEntity implements Serializable {
|
| 20 |
+
|
| 21 |
+
private static final long serialVersionUID = 1L;
|
| 22 |
+
|
| 23 |
+
@CreatedBy
|
| 24 |
+
@Column(name = "created_by", nullable = false, length = 50, updatable = false)
|
| 25 |
+
private String createdBy;
|
| 26 |
+
|
| 27 |
+
@CreatedDate
|
| 28 |
+
@Column(name = "created_date", nullable = false, updatable = false)
|
| 29 |
+
private Instant createdDate = Instant.now();
|
| 30 |
+
|
| 31 |
+
@LastModifiedBy
|
| 32 |
+
@Column(name = "last_modified_by", length = 50)
|
| 33 |
+
private String lastModifiedBy;
|
| 34 |
+
|
| 35 |
+
@LastModifiedDate
|
| 36 |
+
@Column(name = "last_modified_date")
|
| 37 |
+
private Instant lastModifiedDate = Instant.now();
|
| 38 |
+
}
|
src/main/java/com/dalab/autocompliance/model/entity/ComplianceControlEntity.java
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.entity;
|
| 2 |
+
|
| 3 |
+
import java.util.List;
|
| 4 |
+
import java.util.Map;
|
| 5 |
+
|
| 6 |
+
import org.hibernate.annotations.JdbcTypeCode;
|
| 7 |
+
import org.hibernate.type.SqlTypes;
|
| 8 |
+
|
| 9 |
+
import jakarta.persistence.CollectionTable;
|
| 10 |
+
import jakarta.persistence.Column;
|
| 11 |
+
import jakarta.persistence.ElementCollection;
|
| 12 |
+
import jakarta.persistence.Entity;
|
| 13 |
+
import jakarta.persistence.FetchType;
|
| 14 |
+
import jakarta.persistence.Id;
|
| 15 |
+
import jakarta.persistence.Index;
|
| 16 |
+
import jakarta.persistence.JoinColumn;
|
| 17 |
+
import jakarta.persistence.Lob;
|
| 18 |
+
import jakarta.persistence.Table;
|
| 19 |
+
import lombok.AllArgsConstructor;
|
| 20 |
+
import lombok.Builder;
|
| 21 |
+
import lombok.Data;
|
| 22 |
+
import lombok.EqualsAndHashCode;
|
| 23 |
+
import lombok.NoArgsConstructor;
|
| 24 |
+
|
| 25 |
+
@Entity
|
| 26 |
+
@Table(name = "compliance_controls", indexes = {
|
| 27 |
+
@Index(name = "idx_control_severity", columnList = "severity"),
|
| 28 |
+
@Index(name = "idx_control_enabled", columnList = "enabled")
|
| 29 |
+
})
|
| 30 |
+
@Data
|
| 31 |
+
@EqualsAndHashCode(callSuper = true)
|
| 32 |
+
@NoArgsConstructor
|
| 33 |
+
@AllArgsConstructor
|
| 34 |
+
@Builder
|
| 35 |
+
public class ComplianceControlEntity extends AbstractAuditableEntity {
|
| 36 |
+
|
| 37 |
+
@Id
|
| 38 |
+
@Column(nullable = false, unique = true, length = 100)
|
| 39 |
+
private String controlId;
|
| 40 |
+
|
| 41 |
+
@Column(nullable = false, length = 255)
|
| 42 |
+
private String name;
|
| 43 |
+
|
| 44 |
+
@Lob
|
| 45 |
+
@JdbcTypeCode(SqlTypes.LONGVARCHAR)
|
| 46 |
+
private String description;
|
| 47 |
+
|
| 48 |
+
@Column(length = 50)
|
| 49 |
+
private String severity;
|
| 50 |
+
|
| 51 |
+
@ElementCollection(fetch = FetchType.EAGER)
|
| 52 |
+
@CollectionTable(name = "control_frameworks", joinColumns = @JoinColumn(name = "control_id"))
|
| 53 |
+
@Column(name = "framework_name")
|
| 54 |
+
private List<String> applicableFrameworks;
|
| 55 |
+
|
| 56 |
+
@ElementCollection(fetch = FetchType.EAGER)
|
| 57 |
+
@CollectionTable(name = "control_asset_types", joinColumns = @JoinColumn(name = "control_id"))
|
| 58 |
+
@Column(name = "asset_type")
|
| 59 |
+
private List<String> targetAssetTypes;
|
| 60 |
+
|
| 61 |
+
@Lob
|
| 62 |
+
@JdbcTypeCode(SqlTypes.LONGVARCHAR)
|
| 63 |
+
private String remediationSteps;
|
| 64 |
+
|
| 65 |
+
@JdbcTypeCode(SqlTypes.JSON)
|
| 66 |
+
@Column(columnDefinition = "jsonb")
|
| 67 |
+
private Map<String, String> evaluationParametersDefinition;
|
| 68 |
+
|
| 69 |
+
@Column(length = 512)
|
| 70 |
+
private String detailsLink;
|
| 71 |
+
|
| 72 |
+
@Builder.Default
|
| 73 |
+
private boolean enabled = true;
|
| 74 |
+
}
|
src/main/java/com/dalab/autocompliance/model/entity/ComplianceGeneratedReportEntity.java
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.entity;
|
| 2 |
+
|
| 3 |
+
import jakarta.persistence.*;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.EqualsAndHashCode;
|
| 6 |
+
import lombok.NoArgsConstructor;
|
| 7 |
+
import lombok.AllArgsConstructor;
|
| 8 |
+
import lombok.Builder;
|
| 9 |
+
import org.hibernate.annotations.JdbcTypeCode;
|
| 10 |
+
import org.hibernate.type.SqlTypes;
|
| 11 |
+
|
| 12 |
+
import java.time.LocalDateTime;
|
| 13 |
+
import java.util.List;
|
| 14 |
+
import java.util.Map;
|
| 15 |
+
|
| 16 |
+
@Entity
|
| 17 |
+
@Table(name = "compliance_generated_reports")
|
| 18 |
+
@Data
|
| 19 |
+
@EqualsAndHashCode(callSuper = true)
|
| 20 |
+
@NoArgsConstructor
|
| 21 |
+
@AllArgsConstructor
|
| 22 |
+
@Builder
|
| 23 |
+
public class ComplianceGeneratedReportEntity extends AbstractAuditableEntity {
|
| 24 |
+
|
| 25 |
+
@Id
|
| 26 |
+
@Column(length = 36) // UUID length
|
| 27 |
+
private String reportId;
|
| 28 |
+
|
| 29 |
+
@Column(nullable = false, length = 100)
|
| 30 |
+
private String reportType; // Corresponds to ComplianceReportDefinitionEntity.reportType
|
| 31 |
+
|
| 32 |
+
@Column(length = 255)
|
| 33 |
+
private String displayName; // User-friendly name of the report type at the time of generation
|
| 34 |
+
|
| 35 |
+
@Column(nullable = false)
|
| 36 |
+
private LocalDateTime generationTimestamp;
|
| 37 |
+
|
| 38 |
+
@Column(length = 50)
|
| 39 |
+
private String overallStatus; // e.g., COMPLIANT, NON_COMPLIANT, PARTIALLY_COMPLIANT, ERROR
|
| 40 |
+
|
| 41 |
+
@JdbcTypeCode(SqlTypes.JSON)
|
| 42 |
+
@Column(columnDefinition = "jsonb")
|
| 43 |
+
private Map<String, Object> generationParameters; // Parameters used to generate this specific report instance
|
| 44 |
+
|
| 45 |
+
// Storing summary and findings as JSONB.
|
| 46 |
+
// If specific fields within these need to be frequently queried, consider normalizing them.
|
| 47 |
+
@JdbcTypeCode(SqlTypes.JSON)
|
| 48 |
+
@Column(columnDefinition = "jsonb")
|
| 49 |
+
private ReportSummaryData summaryData; // Corresponds to ComplianceReportDTO.SummaryDTO
|
| 50 |
+
|
| 51 |
+
@JdbcTypeCode(SqlTypes.JSON)
|
| 52 |
+
@Column(columnDefinition = "jsonb")
|
| 53 |
+
private List<ReportFindingData> findingsData; // Corresponds to List<ComplianceReportDTO.FindingDTO>
|
| 54 |
+
|
| 55 |
+
// Link back to the job that generated this report
|
| 56 |
+
@OneToOne(fetch = FetchType.LAZY)
|
| 57 |
+
@JoinColumn(name = "job_id", referencedColumnName = "jobId")
|
| 58 |
+
private ComplianceReportJobEntity reportJob;
|
| 59 |
+
}
|
src/main/java/com/dalab/autocompliance/model/entity/ComplianceReportDefinitionEntity.java
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.entity;
|
| 2 |
+
|
| 3 |
+
import jakarta.persistence.*;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.EqualsAndHashCode;
|
| 6 |
+
import lombok.NoArgsConstructor;
|
| 7 |
+
import lombok.AllArgsConstructor;
|
| 8 |
+
import lombok.Builder;
|
| 9 |
+
import org.hibernate.annotations.JdbcTypeCode;
|
| 10 |
+
import org.hibernate.type.SqlTypes;
|
| 11 |
+
|
| 12 |
+
import java.util.List;
|
| 13 |
+
import java.util.Map;
|
| 14 |
+
|
| 15 |
+
@Entity
|
| 16 |
+
@Table(name = "compliance_report_definitions")
|
| 17 |
+
@Data
|
| 18 |
+
@EqualsAndHashCode(callSuper = true)
|
| 19 |
+
@NoArgsConstructor
|
| 20 |
+
@AllArgsConstructor
|
| 21 |
+
@Builder
|
| 22 |
+
public class ComplianceReportDefinitionEntity extends AbstractAuditableEntity {
|
| 23 |
+
|
| 24 |
+
@Id
|
| 25 |
+
@Column(nullable = false, unique = true, length = 100)
|
| 26 |
+
private String reportType; // e.g., "cis-gcp-foundations-v1.3"
|
| 27 |
+
|
| 28 |
+
@Column(nullable = false, length = 255)
|
| 29 |
+
private String displayName;
|
| 30 |
+
|
| 31 |
+
@Lob
|
| 32 |
+
@JdbcTypeCode(SqlTypes.LONGVARCHAR)
|
| 33 |
+
private String description;
|
| 34 |
+
|
| 35 |
+
@Column(length = 50)
|
| 36 |
+
private String version;
|
| 37 |
+
|
| 38 |
+
@ElementCollection(fetch = FetchType.EAGER)
|
| 39 |
+
@CollectionTable(name = "report_def_frameworks", joinColumns = @JoinColumn(name = "report_type"))
|
| 40 |
+
@Column(name = "framework_name")
|
| 41 |
+
private List<String> applicableComplianceFrameworks;
|
| 42 |
+
|
| 43 |
+
@ElementCollection(fetch = FetchType.EAGER)
|
| 44 |
+
@CollectionTable(name = "report_def_asset_types", joinColumns = @JoinColumn(name = "report_type"))
|
| 45 |
+
@Column(name = "asset_type")
|
| 46 |
+
private List<String> targetAssetTypes;
|
| 47 |
+
|
| 48 |
+
// Storing parameter definitions (name and type, e.g., "gcpProjectId": "string")
|
| 49 |
+
@JdbcTypeCode(SqlTypes.JSON)
|
| 50 |
+
@Column(columnDefinition = "jsonb")
|
| 51 |
+
private Map<String, String> generationParametersDefinition; // Renamed for clarity from DTO's 'generationParameters'
|
| 52 |
+
|
| 53 |
+
@Column(length = 512)
|
| 54 |
+
private String detailsLink;
|
| 55 |
+
}
|
src/main/java/com/dalab/autocompliance/model/entity/ComplianceReportJobEntity.java
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.entity;
|
| 2 |
+
|
| 3 |
+
import jakarta.persistence.*;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.EqualsAndHashCode;
|
| 6 |
+
import lombok.NoArgsConstructor;
|
| 7 |
+
import lombok.AllArgsConstructor;
|
| 8 |
+
import lombok.Builder;
|
| 9 |
+
|
| 10 |
+
import java.time.LocalDateTime;
|
| 11 |
+
import java.util.Map;
|
| 12 |
+
|
| 13 |
+
@Entity
|
| 14 |
+
@Table(name = "compliance_report_jobs")
|
| 15 |
+
@Data
|
| 16 |
+
@EqualsAndHashCode(callSuper = true)
|
| 17 |
+
@NoArgsConstructor
|
| 18 |
+
@AllArgsConstructor
|
| 19 |
+
@Builder
|
| 20 |
+
public class ComplianceReportJobEntity extends AbstractAuditableEntity {
|
| 21 |
+
|
| 22 |
+
@Id
|
| 23 |
+
@Column(length = 36) // UUID length
|
| 24 |
+
private String jobId;
|
| 25 |
+
|
| 26 |
+
@Column(nullable = false, length = 100)
|
| 27 |
+
private String reportType; // Corresponds to ComplianceReportDefinitionEntity.reportType
|
| 28 |
+
|
| 29 |
+
@Column(nullable = false, length = 50)
|
| 30 |
+
private String status; // e.g., QUEUED, PROCESSING, COMPLETED_SUCCESS, COMPLETED_FAILURE
|
| 31 |
+
|
| 32 |
+
private LocalDateTime submittedAt;
|
| 33 |
+
private LocalDateTime startedAt;
|
| 34 |
+
private LocalDateTime completedAt;
|
| 35 |
+
|
| 36 |
+
@Lob
|
| 37 |
+
@Basic(fetch = FetchType.LAZY) // Message could be long, fetch lazily
|
| 38 |
+
private String message;
|
| 39 |
+
|
| 40 |
+
@Column(length = 36) // UUID length, if report is generated
|
| 41 |
+
private String generatedReportId; // Links to ComplianceGeneratedReportEntity.reportId
|
| 42 |
+
|
| 43 |
+
// Parameters used for this specific job instance.
|
| 44 |
+
// In DTO this was Map<String, Object>. For DB, JSON is suitable.
|
| 45 |
+
// Consider if complex objects need to be queryable. If so, separate columns or normalized tables might be better.
|
| 46 |
+
// For now, storing as JSONB is a flexible approach.
|
| 47 |
+
@org.hibernate.annotations.JdbcTypeCode(org.hibernate.type.SqlTypes.JSON)
|
| 48 |
+
@Column(columnDefinition = "jsonb")
|
| 49 |
+
private Map<String, Object> generationParameters;
|
| 50 |
+
|
| 51 |
+
@Column(length = 255)
|
| 52 |
+
private String triggeredBy; // User or system that triggered it
|
| 53 |
+
|
| 54 |
+
@Column(length = 255)
|
| 55 |
+
private String notificationEmail; // Email for notification
|
| 56 |
+
}
|
src/main/java/com/dalab/autocompliance/model/entity/ControlEvaluationJobEntity.java
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.entity;
|
| 2 |
+
|
| 3 |
+
import jakarta.persistence.*;
|
| 4 |
+
import lombok.Data;
|
| 5 |
+
import lombok.EqualsAndHashCode;
|
| 6 |
+
import lombok.NoArgsConstructor;
|
| 7 |
+
import lombok.AllArgsConstructor;
|
| 8 |
+
import lombok.Builder;
|
| 9 |
+
import org.hibernate.annotations.JdbcTypeCode;
|
| 10 |
+
import org.hibernate.type.SqlTypes;
|
| 11 |
+
|
| 12 |
+
import java.time.LocalDateTime;
|
| 13 |
+
import java.util.List;
|
| 14 |
+
import java.util.Map;
|
| 15 |
+
|
| 16 |
+
@Entity
|
| 17 |
+
@Table(name = "compliance_control_evaluation_jobs", indexes = {
|
| 18 |
+
@Index(name = "idx_ctrl_eval_job_control_id", columnList = "controlId"),
|
| 19 |
+
@Index(name = "idx_ctrl_eval_job_status", columnList = "status")
|
| 20 |
+
})
|
| 21 |
+
@Data
|
| 22 |
+
@EqualsAndHashCode(callSuper = true)
|
| 23 |
+
@NoArgsConstructor
|
| 24 |
+
@AllArgsConstructor
|
| 25 |
+
@Builder
|
| 26 |
+
public class ControlEvaluationJobEntity extends AbstractAuditableEntity {
|
| 27 |
+
|
| 28 |
+
@Id
|
| 29 |
+
@Column(length = 36) // UUID length
|
| 30 |
+
private String jobId;
|
| 31 |
+
|
| 32 |
+
@Column(nullable = false, length = 100)
|
| 33 |
+
private String controlId; // Foreign key to ComplianceControlEntity.controlId
|
| 34 |
+
|
| 35 |
+
@Column(nullable = false, length = 50)
|
| 36 |
+
private String status; // e.g., QUEUED, PROCESSING, COMPLETED_SUCCESS, COMPLETED_FAILURE, PARTIAL_FAILURE
|
| 37 |
+
|
| 38 |
+
private LocalDateTime submittedAt;
|
| 39 |
+
private LocalDateTime startedAt;
|
| 40 |
+
private LocalDateTime completedAt;
|
| 41 |
+
|
| 42 |
+
@Lob
|
| 43 |
+
@Basic(fetch = FetchType.LAZY)
|
| 44 |
+
private String message; // Overall message for the job execution
|
| 45 |
+
|
| 46 |
+
@ElementCollection(fetch = FetchType.LAZY) // Store targeted asset IDs
|
| 47 |
+
@CollectionTable(name = "control_eval_job_target_assets", joinColumns = @JoinColumn(name = "job_id"))
|
| 48 |
+
@Column(name = "asset_id")
|
| 49 |
+
private List<String> targetAssetIds;
|
| 50 |
+
|
| 51 |
+
@JdbcTypeCode(SqlTypes.JSON)
|
| 52 |
+
@Column(columnDefinition = "jsonb")
|
| 53 |
+
private Map<String, Object> evaluationParameters; // Parameters used for this specific evaluation run
|
| 54 |
+
|
| 55 |
+
private boolean forceReevaluation;
|
| 56 |
+
|
| 57 |
+
@Column(length = 255)
|
| 58 |
+
private String triggeredBy;
|
| 59 |
+
|
| 60 |
+
@Column(length = 255)
|
| 61 |
+
private String notificationEmail;
|
| 62 |
+
|
| 63 |
+
// In a more detailed model, you might have a list of ControlEvaluationResultEntity linked here.
|
| 64 |
+
// For now, the results (findings) would likely be new entries in the main GeneratedReport or a similar table,
|
| 65 |
+
// or a dedicated ControlFindingEntity. This part needs further thought based on how results are stored/queried.
|
| 66 |
+
// For simplicity, this job entity primarily tracks the execution.
|
| 67 |
+
}
|
src/main/java/com/dalab/autocompliance/model/entity/ReportFindingData.java
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.entity;
|
| 2 |
+
|
| 3 |
+
import lombok.Data;
|
| 4 |
+
import lombok.NoArgsConstructor;
|
| 5 |
+
import lombok.AllArgsConstructor;
|
| 6 |
+
import lombok.Builder;
|
| 7 |
+
|
| 8 |
+
import java.util.Map;
|
| 9 |
+
|
| 10 |
+
// This is a simple POJO, not an entity. Used for JSONB mapping.
|
| 11 |
+
@Data
|
| 12 |
+
@Builder
|
| 13 |
+
@NoArgsConstructor
|
| 14 |
+
@AllArgsConstructor
|
| 15 |
+
public class ReportFindingData {
|
| 16 |
+
private String checkId;
|
| 17 |
+
private String description;
|
| 18 |
+
private String assetId;
|
| 19 |
+
private String assetType;
|
| 20 |
+
private String assetName;
|
| 21 |
+
private String status;
|
| 22 |
+
private String severity;
|
| 23 |
+
private String recommendation;
|
| 24 |
+
private Map<String, Object> details;
|
| 25 |
+
private String evidenceLink;
|
| 26 |
+
}
|
src/main/java/com/dalab/autocompliance/model/entity/ReportSummaryData.java
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.entity;
|
| 2 |
+
|
| 3 |
+
import lombok.Data;
|
| 4 |
+
import lombok.NoArgsConstructor;
|
| 5 |
+
import lombok.AllArgsConstructor;
|
| 6 |
+
import lombok.Builder;
|
| 7 |
+
|
| 8 |
+
// This is a simple POJO, not an entity. Used for JSONB mapping.
|
| 9 |
+
@Data
|
| 10 |
+
@Builder
|
| 11 |
+
@NoArgsConstructor
|
| 12 |
+
@AllArgsConstructor
|
| 13 |
+
public class ReportSummaryData {
|
| 14 |
+
private int totalChecks;
|
| 15 |
+
private int compliantChecks;
|
| 16 |
+
private int nonCompliantChecks;
|
| 17 |
+
private int errorChecks;
|
| 18 |
+
private double complianceScore;
|
| 19 |
+
}
|
src/main/java/com/dalab/autocompliance/model/mapper/ComplianceControlMapper.java
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.mapper;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.dto.ComplianceControlDTO;
|
| 4 |
+
import com.dalab.autocompliance.model.entity.ComplianceControlEntity;
|
| 5 |
+
import org.mapstruct.Mapper;
|
| 6 |
+
import org.mapstruct.factory.Mappers;
|
| 7 |
+
|
| 8 |
+
import java.util.List;
|
| 9 |
+
|
| 10 |
+
@Mapper(componentModel = "spring")
|
| 11 |
+
public interface ComplianceControlMapper {
|
| 12 |
+
|
| 13 |
+
ComplianceControlMapper INSTANCE = Mappers.getMapper(ComplianceControlMapper.class);
|
| 14 |
+
|
| 15 |
+
ComplianceControlDTO toDto(ComplianceControlEntity entity);
|
| 16 |
+
|
| 17 |
+
ComplianceControlEntity toEntity(ComplianceControlDTO dto);
|
| 18 |
+
|
| 19 |
+
List<ComplianceControlDTO> toDtoList(List<ComplianceControlEntity> entities);
|
| 20 |
+
|
| 21 |
+
List<ComplianceControlEntity> toEntityList(List<ComplianceControlDTO> dtos);
|
| 22 |
+
}
|
src/main/java/com/dalab/autocompliance/model/mapper/ComplianceGeneratedReportMapper.java
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.mapper;
|
| 2 |
+
|
| 3 |
+
import java.util.List;
|
| 4 |
+
|
| 5 |
+
import org.mapstruct.Mapper;
|
| 6 |
+
import org.mapstruct.Mapping;
|
| 7 |
+
import org.mapstruct.factory.Mappers;
|
| 8 |
+
|
| 9 |
+
import com.dalab.autocompliance.dto.ComplianceReportDTO;
|
| 10 |
+
import com.dalab.autocompliance.model.entity.ComplianceGeneratedReportEntity;
|
| 11 |
+
import com.dalab.autocompliance.model.entity.ReportFindingData;
|
| 12 |
+
import com.dalab.autocompliance.model.entity.ReportSummaryData;
|
| 13 |
+
|
| 14 |
+
/**
|
| 15 |
+
* Mapper interface for converting between ComplianceGeneratedReportEntity and DTOs.
|
| 16 |
+
*/
|
| 17 |
+
@Mapper(componentModel = "spring")
|
| 18 |
+
public interface ComplianceGeneratedReportMapper {
|
| 19 |
+
|
| 20 |
+
ComplianceGeneratedReportMapper INSTANCE = Mappers.getMapper(ComplianceGeneratedReportMapper.class);
|
| 21 |
+
|
| 22 |
+
// Entity to DTO
|
| 23 |
+
@Mapping(source = "summaryData", target = "summary")
|
| 24 |
+
@Mapping(source = "findingsData", target = "findings")
|
| 25 |
+
ComplianceReportDTO toDto(ComplianceGeneratedReportEntity entity);
|
| 26 |
+
|
| 27 |
+
List<ComplianceReportDTO> toDtoList(List<ComplianceGeneratedReportEntity> entities);
|
| 28 |
+
|
| 29 |
+
// DTO to Entity
|
| 30 |
+
@Mapping(source = "summary", target = "summaryData")
|
| 31 |
+
@Mapping(source = "findings", target = "findingsData")
|
| 32 |
+
@Mapping(target = "reportJob", ignore = true) // Typically set separately or via jobId
|
| 33 |
+
ComplianceGeneratedReportEntity toEntity(ComplianceReportDTO dto);
|
| 34 |
+
|
| 35 |
+
// Mappings for nested POJOs (if MapStruct doesn't handle them automatically, which it often does)
|
| 36 |
+
// These might not be strictly necessary if names and types match and MapStruct can infer them.
|
| 37 |
+
ReportSummaryData toReportSummaryData(ComplianceReportDTO.SummaryDTO summaryDTO);
|
| 38 |
+
ComplianceReportDTO.SummaryDTO toSummaryDTO(ReportSummaryData reportSummaryData);
|
| 39 |
+
|
| 40 |
+
List<ReportFindingData> toReportFindingDataList(List<ComplianceReportDTO.FindingDTO> findingDTOs);
|
| 41 |
+
List<ComplianceReportDTO.FindingDTO> toFindingDTOList(List<ReportFindingData> reportFindingDataList);
|
| 42 |
+
|
| 43 |
+
ReportFindingData toReportFindingData(ComplianceReportDTO.FindingDTO findingDTO);
|
| 44 |
+
ComplianceReportDTO.FindingDTO toFindingDTO(ReportFindingData reportFindingData);
|
| 45 |
+
|
| 46 |
+
}
|
src/main/java/com/dalab/autocompliance/model/mapper/ComplianceReportDefinitionMapper.java
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.mapper;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.dto.ComplianceReportDefinitionDTO;
|
| 4 |
+
import com.dalab.autocompliance.model.entity.ComplianceReportDefinitionEntity;
|
| 5 |
+
import org.mapstruct.Mapper;
|
| 6 |
+
import org.mapstruct.Mapping;
|
| 7 |
+
import org.mapstruct.factory.Mappers;
|
| 8 |
+
|
| 9 |
+
import java.util.List;
|
| 10 |
+
|
| 11 |
+
@Mapper(componentModel = "spring")
|
| 12 |
+
public interface ComplianceReportDefinitionMapper {
|
| 13 |
+
|
| 14 |
+
ComplianceReportDefinitionMapper INSTANCE = Mappers.getMapper(ComplianceReportDefinitionMapper.class);
|
| 15 |
+
|
| 16 |
+
@Mapping(source = "generationParametersDefinition", target = "generationParameters")
|
| 17 |
+
ComplianceReportDefinitionDTO toDto(ComplianceReportDefinitionEntity entity);
|
| 18 |
+
|
| 19 |
+
@Mapping(source = "generationParameters", target = "generationParametersDefinition")
|
| 20 |
+
ComplianceReportDefinitionEntity toEntity(ComplianceReportDefinitionDTO dto);
|
| 21 |
+
|
| 22 |
+
List<ComplianceReportDefinitionDTO> toDtoList(List<ComplianceReportDefinitionEntity> entities);
|
| 23 |
+
|
| 24 |
+
List<ComplianceReportDefinitionEntity> toEntityList(List<ComplianceReportDefinitionDTO> dtos);
|
| 25 |
+
}
|
src/main/java/com/dalab/autocompliance/model/mapper/ComplianceReportJobMapper.java
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.mapper;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.dto.ReportJobStatusDTO;
|
| 4 |
+
import com.dalab.autocompliance.dto.ReportGenerationRequestDTO; // For mapping parameters
|
| 5 |
+
import com.dalab.autocompliance.model.entity.ComplianceReportJobEntity;
|
| 6 |
+
import org.mapstruct.Mapper;
|
| 7 |
+
import org.mapstruct.Mapping;
|
| 8 |
+
import org.mapstruct.Named;
|
| 9 |
+
import org.mapstruct.factory.Mappers;
|
| 10 |
+
|
| 11 |
+
import java.util.Map;
|
| 12 |
+
import java.util.List;
|
| 13 |
+
|
| 14 |
+
/**
|
| 15 |
+
* Mapper interface for converting between ComplianceReportJobEntity and DTOs.
|
| 16 |
+
*/
|
| 17 |
+
@Mapper
|
| 18 |
+
public interface ComplianceReportJobMapper {
|
| 19 |
+
|
| 20 |
+
ComplianceReportJobMapper INSTANCE = Mappers.getMapper(ComplianceReportJobMapper.class);
|
| 21 |
+
|
| 22 |
+
// From Entity to DTO (ReportJobStatusDTO)
|
| 23 |
+
@Mapping(target = "reportId", ignore = true)
|
| 24 |
+
@Mapping(target = "downloadLink", ignore = true)
|
| 25 |
+
ReportJobStatusDTO toDto(ComplianceReportJobEntity entity);
|
| 26 |
+
|
| 27 |
+
List<ReportJobStatusDTO> toDtoList(List<ComplianceReportJobEntity> entities);
|
| 28 |
+
|
| 29 |
+
// From DTO (ReportGenerationRequestDTO for submission) to Entity
|
| 30 |
+
// Note: JobId will be set in service. Status will be set. reportId will be null initially.
|
| 31 |
+
@Mapping(source = "dto.parameters", target = "generationParameters") // Map<String, Object> to Map<String, Object>
|
| 32 |
+
@Mapping(target = "jobId", ignore = true) // Set by service
|
| 33 |
+
@Mapping(target = "status", ignore = true) // Set by service
|
| 34 |
+
@Mapping(target = "submittedAt", ignore = true) // Set by service or DB default
|
| 35 |
+
@Mapping(target = "startedAt", ignore = true)
|
| 36 |
+
@Mapping(target = "completedAt", ignore = true)
|
| 37 |
+
@Mapping(target = "message", ignore = true)
|
| 38 |
+
@Mapping(target = "generatedReportId", ignore = true)
|
| 39 |
+
ComplianceReportJobEntity fromGenerationRequest(ReportGenerationRequestDTO dto, String reportType);
|
| 40 |
+
|
| 41 |
+
}
|
src/main/java/com/dalab/autocompliance/model/mapper/ControlEvaluationJobMapper.java
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.mapper;
|
| 2 |
+
|
| 3 |
+
import java.time.LocalDateTime;
|
| 4 |
+
import java.util.UUID;
|
| 5 |
+
|
| 6 |
+
import org.mapstruct.Mapper;
|
| 7 |
+
import org.mapstruct.Mapping;
|
| 8 |
+
import org.mapstruct.factory.Mappers;
|
| 9 |
+
|
| 10 |
+
import com.dalab.autocompliance.dto.ControlEvaluationRequestDTO;
|
| 11 |
+
import com.dalab.autocompliance.dto.ControlEvaluationResponseDTO;
|
| 12 |
+
import com.dalab.autocompliance.model.entity.ControlEvaluationJobEntity;
|
| 13 |
+
|
| 14 |
+
/**
|
| 15 |
+
* Mapper interface for converting between ControlEvaluationJobEntity and DTOs.
|
| 16 |
+
*/
|
| 17 |
+
@Mapper(imports = {UUID.class, LocalDateTime.class})
|
| 18 |
+
public interface ControlEvaluationJobMapper {
|
| 19 |
+
|
| 20 |
+
ControlEvaluationJobMapper INSTANCE = Mappers.getMapper(ControlEvaluationJobMapper.class);
|
| 21 |
+
|
| 22 |
+
// To DTO (ControlEvaluationResponseDTO is simpler, doesn't carry all entity details by default)
|
| 23 |
+
@Mapping(target = "targetedAssetCount", expression = "java(entity.getTargetAssetIds() != null ? entity.getTargetAssetIds().size() : 0)")
|
| 24 |
+
ControlEvaluationResponseDTO toResponseDto(ControlEvaluationJobEntity entity);
|
| 25 |
+
|
| 26 |
+
// From Request DTO to Entity
|
| 27 |
+
@Mapping(target = "jobId", expression = "java(UUID.randomUUID().toString())")
|
| 28 |
+
@Mapping(target = "submittedAt", expression = "java(LocalDateTime.now())")
|
| 29 |
+
@Mapping(target = "status", constant = "QUEUED")
|
| 30 |
+
@Mapping(target = "startedAt", ignore = true)
|
| 31 |
+
@Mapping(target = "completedAt", ignore = true)
|
| 32 |
+
@Mapping(target = "message", ignore = true)
|
| 33 |
+
ControlEvaluationJobEntity fromRequestDto(ControlEvaluationRequestDTO requestDto, String controlId);
|
| 34 |
+
|
| 35 |
+
// If you need a more detailed DTO for job status (like ReportJobStatusDTO), you'd create another one.
|
| 36 |
+
// For now, the response DTO is used for the immediate POST response.
|
| 37 |
+
}
|
src/main/java/com/dalab/autocompliance/model/repository/ComplianceControlRepository.java
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.repository;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.model.entity.ComplianceControlEntity;
|
| 4 |
+
import org.springframework.data.jpa.repository.JpaRepository;
|
| 5 |
+
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
| 6 |
+
import org.springframework.stereotype.Repository;
|
| 7 |
+
|
| 8 |
+
import java.util.List;
|
| 9 |
+
import java.util.Optional;
|
| 10 |
+
|
| 11 |
+
@Repository
|
| 12 |
+
public interface ComplianceControlRepository extends JpaRepository<ComplianceControlEntity, String>, JpaSpecificationExecutor<ComplianceControlEntity> {
|
| 13 |
+
// String is the type of the ID (controlId)
|
| 14 |
+
|
| 15 |
+
Optional<ComplianceControlEntity> findByControlIdIgnoreCase(String controlId);
|
| 16 |
+
|
| 17 |
+
List<ComplianceControlEntity> findByEnabledTrue();
|
| 18 |
+
|
| 19 |
+
List<ComplianceControlEntity> findBySeverityIgnoreCaseAndEnabledTrue(String severity);
|
| 20 |
+
|
| 21 |
+
// JpaSpecificationExecutor allows for dynamic queries based on criteria, useful for filtering controls
|
| 22 |
+
}
|
src/main/java/com/dalab/autocompliance/model/repository/ComplianceGeneratedReportRepository.java
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.repository;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.model.entity.ComplianceGeneratedReportEntity;
|
| 4 |
+
import org.springframework.data.domain.Page;
|
| 5 |
+
import org.springframework.data.domain.Pageable;
|
| 6 |
+
import org.springframework.data.jpa.repository.JpaRepository;
|
| 7 |
+
import org.springframework.data.jpa.repository.Query;
|
| 8 |
+
import org.springframework.data.repository.query.Param;
|
| 9 |
+
import org.springframework.stereotype.Repository;
|
| 10 |
+
|
| 11 |
+
import java.util.List;
|
| 12 |
+
|
| 13 |
+
@Repository
|
| 14 |
+
public interface ComplianceGeneratedReportRepository extends JpaRepository<ComplianceGeneratedReportEntity, String> {
|
| 15 |
+
// String is the type of the ID (reportId)
|
| 16 |
+
|
| 17 |
+
Page<ComplianceGeneratedReportEntity> findByReportTypeIgnoreCase(String reportType, Pageable pageable);
|
| 18 |
+
|
| 19 |
+
// Example of a query that might be needed to get asset status (though this is complex for JSONB)
|
| 20 |
+
// This is a conceptual query; actual JSONB querying capabilities depend heavily on the database (e.g., PostgreSQL).
|
| 21 |
+
// It's often better to process this in the service layer after fetching relevant reports,
|
| 22 |
+
// or use a dedicated search index if performance is critical.
|
| 23 |
+
@Query(value = "SELECT cgr.* FROM compliance_generated_reports cgr " +
|
| 24 |
+
"WHERE EXISTS (SELECT 1 FROM jsonb_array_elements(cgr.findings_data) AS finding " +
|
| 25 |
+
"WHERE finding ->> 'assetId' = :assetId)",
|
| 26 |
+
nativeQuery = true)
|
| 27 |
+
List<ComplianceGeneratedReportEntity> findReportsContainingAssetId(@Param("assetId") String assetId);
|
| 28 |
+
}
|
src/main/java/com/dalab/autocompliance/model/repository/ComplianceReportDefinitionRepository.java
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.repository;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.model.entity.ComplianceReportDefinitionEntity;
|
| 4 |
+
import org.springframework.data.jpa.repository.JpaRepository;
|
| 5 |
+
import org.springframework.stereotype.Repository;
|
| 6 |
+
|
| 7 |
+
import java.util.Optional;
|
| 8 |
+
|
| 9 |
+
@Repository
|
| 10 |
+
public interface ComplianceReportDefinitionRepository extends JpaRepository<ComplianceReportDefinitionEntity, String> {
|
| 11 |
+
// String is the type of the ID (reportType)
|
| 12 |
+
|
| 13 |
+
Optional<ComplianceReportDefinitionEntity> findByReportTypeIgnoreCase(String reportType);
|
| 14 |
+
|
| 15 |
+
boolean existsByReportTypeIgnoreCase(String reportType);
|
| 16 |
+
}
|
src/main/java/com/dalab/autocompliance/model/repository/ComplianceReportJobRepository.java
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.repository;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.model.entity.ComplianceReportJobEntity;
|
| 4 |
+
import org.springframework.data.domain.Page;
|
| 5 |
+
import org.springframework.data.domain.Pageable;
|
| 6 |
+
import org.springframework.data.jpa.repository.JpaRepository;
|
| 7 |
+
import org.springframework.stereotype.Repository;
|
| 8 |
+
|
| 9 |
+
import java.util.List;
|
| 10 |
+
|
| 11 |
+
@Repository
|
| 12 |
+
public interface ComplianceReportJobRepository extends JpaRepository<ComplianceReportJobEntity, String> {
|
| 13 |
+
// String is the type of the ID (jobId)
|
| 14 |
+
|
| 15 |
+
Page<ComplianceReportJobEntity> findByReportTypeIgnoreCase(String reportType, Pageable pageable);
|
| 16 |
+
|
| 17 |
+
List<ComplianceReportJobEntity> findByStatusIn(List<String> statuses); // For finding active jobs etc.
|
| 18 |
+
}
|
src/main/java/com/dalab/autocompliance/model/repository/ControlEvaluationJobRepository.java
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.model.repository;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.model.entity.ControlEvaluationJobEntity;
|
| 4 |
+
import org.springframework.data.domain.Page;
|
| 5 |
+
import org.springframework.data.domain.Pageable;
|
| 6 |
+
import org.springframework.data.jpa.repository.JpaRepository;
|
| 7 |
+
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
| 8 |
+
import org.springframework.stereotype.Repository;
|
| 9 |
+
|
| 10 |
+
import java.util.List;
|
| 11 |
+
|
| 12 |
+
@Repository
|
| 13 |
+
public interface ControlEvaluationJobRepository extends JpaRepository<ControlEvaluationJobEntity, String>, JpaSpecificationExecutor<ControlEvaluationJobEntity> {
|
| 14 |
+
// String is the type of the ID (jobId)
|
| 15 |
+
|
| 16 |
+
Page<ControlEvaluationJobEntity> findByControlIdIgnoreCase(String controlId, Pageable pageable);
|
| 17 |
+
|
| 18 |
+
List<ControlEvaluationJobEntity> findByStatusIn(List<String> statuses);
|
| 19 |
+
}
|
src/main/java/com/dalab/autocompliance/service/IComplianceService.java
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.service;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.dto.ComplianceReportDefinitionDTO;
|
| 4 |
+
import com.dalab.autocompliance.dto.ReportGenerationRequestDTO;
|
| 5 |
+
import com.dalab.autocompliance.dto.ReportGenerationResponseDTO;
|
| 6 |
+
import com.dalab.autocompliance.dto.ReportJobStatusDTO;
|
| 7 |
+
import com.dalab.autocompliance.dto.ComplianceReportDTO;
|
| 8 |
+
import com.dalab.autocompliance.dto.AssetComplianceStatusDTO;
|
| 9 |
+
import com.dalab.autocompliance.dto.ComplianceControlDTO;
|
| 10 |
+
import com.dalab.autocompliance.dto.ControlEvaluationRequestDTO;
|
| 11 |
+
import com.dalab.autocompliance.dto.ControlEvaluationResponseDTO;
|
| 12 |
+
// Future DTOs:
|
| 13 |
+
// import com.dalab.autocompliance.dto.ReportGenerationRequestDTO;
|
| 14 |
+
// import com.dalab.autocompliance.dto.ReportGenerationResponseDTO;
|
| 15 |
+
// import com.dalab.autocompliance.dto.ReportJobStatusDTO;
|
| 16 |
+
|
| 17 |
+
import java.util.List;
|
| 18 |
+
|
| 19 |
+
public interface IComplianceService {
|
| 20 |
+
|
| 21 |
+
/**
|
| 22 |
+
* Lists all available compliance report definitions.
|
| 23 |
+
* @return A list of ComplianceReportDefinitionDTOs.
|
| 24 |
+
*/
|
| 25 |
+
List<ComplianceReportDefinitionDTO> listAvailableReportDefinitions();
|
| 26 |
+
|
| 27 |
+
/**
|
| 28 |
+
* Initiates the generation of a specific compliance report.
|
| 29 |
+
* @param reportType The type of report to generate.
|
| 30 |
+
* @param request DTO containing parameters for report generation.
|
| 31 |
+
* @return A response DTO with the job ID and status.
|
| 32 |
+
*/
|
| 33 |
+
ReportGenerationResponseDTO generateComplianceReport(String reportType, ReportGenerationRequestDTO request);
|
| 34 |
+
|
| 35 |
+
/**
|
| 36 |
+
* Retrieves the status of a specific compliance report generation job.
|
| 37 |
+
* @param jobId The ID of the job.
|
| 38 |
+
* @return A DTO with the job status details.
|
| 39 |
+
*/
|
| 40 |
+
ReportJobStatusDTO getReportGenerationJobStatus(String jobId);
|
| 41 |
+
|
| 42 |
+
/**
|
| 43 |
+
* Retrieves a generated compliance report by its ID.
|
| 44 |
+
* @param reportId The ID of the generated report.
|
| 45 |
+
* @return The ComplianceReportDTO or null if not found.
|
| 46 |
+
*/
|
| 47 |
+
ComplianceReportDTO getGeneratedReport(String reportId);
|
| 48 |
+
|
| 49 |
+
/**
|
| 50 |
+
* Retrieves the overall compliance status for a specific asset.
|
| 51 |
+
* @param assetId The ID of the asset.
|
| 52 |
+
* @return AssetComplianceStatusDTO or null if asset not found or no status available.
|
| 53 |
+
*/
|
| 54 |
+
AssetComplianceStatusDTO getAssetComplianceStatus(String assetId);
|
| 55 |
+
|
| 56 |
+
/**
|
| 57 |
+
* Lists all available (and typically enabled) compliance controls.
|
| 58 |
+
* @return A list of ComplianceControlDTOs.
|
| 59 |
+
*/
|
| 60 |
+
List<ComplianceControlDTO> listAvailableControls();
|
| 61 |
+
|
| 62 |
+
/**
|
| 63 |
+
* Initiates the evaluation of a specific compliance control.
|
| 64 |
+
* @param controlId The ID of the control to evaluate.
|
| 65 |
+
* @param request DTO containing parameters for the evaluation.
|
| 66 |
+
* @return A response DTO with the job ID and status.
|
| 67 |
+
*/
|
| 68 |
+
ControlEvaluationResponseDTO evaluateControl(String controlId, ControlEvaluationRequestDTO request);
|
| 69 |
+
|
| 70 |
+
// TODO: Add method to get status of a control evaluation job
|
| 71 |
+
// ControlEvaluationJobStatusDTO getControlEvaluationJobStatus(String jobId);
|
| 72 |
+
|
| 73 |
+
// Methods to be added later:
|
| 74 |
+
// ReportGenerationResponseDTO generateComplianceReport(String reportType, ReportGenerationRequestDTO request);
|
| 75 |
+
// ReportJobStatusDTO getReportGenerationJobStatus(String jobId);
|
| 76 |
+
// ... and others for controls and asset status
|
| 77 |
+
}
|
src/main/java/com/dalab/autocompliance/service/exception/ControlNotFoundException.java
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.service.exception;
|
| 2 |
+
|
| 3 |
+
import org.springframework.http.HttpStatus;
|
| 4 |
+
import org.springframework.web.bind.annotation.ResponseStatus;
|
| 5 |
+
|
| 6 |
+
@ResponseStatus(HttpStatus.NOT_FOUND)
|
| 7 |
+
public class ControlNotFoundException extends RuntimeException {
|
| 8 |
+
public ControlNotFoundException(String message) {
|
| 9 |
+
super(message);
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
public ControlNotFoundException(String message, Throwable cause) {
|
| 13 |
+
super(message, cause);
|
| 14 |
+
}
|
| 15 |
+
}
|
src/main/java/com/dalab/autocompliance/service/exception/GeneratedReportNotFoundException.java
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.service.exception;
|
| 2 |
+
|
| 3 |
+
import org.springframework.http.HttpStatus;
|
| 4 |
+
import org.springframework.web.bind.annotation.ResponseStatus;
|
| 5 |
+
|
| 6 |
+
@ResponseStatus(HttpStatus.NOT_FOUND)
|
| 7 |
+
public class GeneratedReportNotFoundException extends RuntimeException {
|
| 8 |
+
public GeneratedReportNotFoundException(String message) {
|
| 9 |
+
super(message);
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
public GeneratedReportNotFoundException(String message, Throwable cause) {
|
| 13 |
+
super(message, cause);
|
| 14 |
+
}
|
| 15 |
+
}
|
src/main/java/com/dalab/autocompliance/service/exception/ReportDefinitionNotFoundException.java
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.service.exception;
|
| 2 |
+
|
| 3 |
+
import org.springframework.http.HttpStatus;
|
| 4 |
+
import org.springframework.web.bind.annotation.ResponseStatus;
|
| 5 |
+
|
| 6 |
+
@ResponseStatus(HttpStatus.NOT_FOUND)
|
| 7 |
+
public class ReportDefinitionNotFoundException extends RuntimeException {
|
| 8 |
+
public ReportDefinitionNotFoundException(String message) {
|
| 9 |
+
super(message);
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
public ReportDefinitionNotFoundException(String message, Throwable cause) {
|
| 13 |
+
super(message, cause);
|
| 14 |
+
}
|
| 15 |
+
}
|
src/main/java/com/dalab/autocompliance/service/exception/ReportJobNotFoundException.java
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.service.exception;
|
| 2 |
+
|
| 3 |
+
import org.springframework.http.HttpStatus;
|
| 4 |
+
import org.springframework.web.bind.annotation.ResponseStatus;
|
| 5 |
+
|
| 6 |
+
@ResponseStatus(HttpStatus.NOT_FOUND)
|
| 7 |
+
public class ReportJobNotFoundException extends RuntimeException {
|
| 8 |
+
public ReportJobNotFoundException(String message) {
|
| 9 |
+
super(message);
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
public ReportJobNotFoundException(String message, Throwable cause) {
|
| 13 |
+
super(message, cause);
|
| 14 |
+
}
|
| 15 |
+
}
|
src/main/java/com/dalab/autocompliance/service/impl/ComplianceServiceImpl.java
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.service.impl;
|
| 2 |
+
|
| 3 |
+
import java.time.LocalDateTime;
|
| 4 |
+
import java.util.ArrayList;
|
| 5 |
+
import java.util.List;
|
| 6 |
+
import java.util.Map;
|
| 7 |
+
import java.util.UUID;
|
| 8 |
+
import java.util.stream.Collectors;
|
| 9 |
+
|
| 10 |
+
import org.springframework.stereotype.Service;
|
| 11 |
+
import org.springframework.transaction.annotation.Transactional;
|
| 12 |
+
|
| 13 |
+
import com.dalab.autocompliance.dto.AssetComplianceStatusDTO;
|
| 14 |
+
import com.dalab.autocompliance.dto.ComplianceControlDTO;
|
| 15 |
+
import com.dalab.autocompliance.dto.ComplianceReportDTO;
|
| 16 |
+
import com.dalab.autocompliance.dto.ComplianceReportDefinitionDTO;
|
| 17 |
+
import com.dalab.autocompliance.dto.ControlEvaluationRequestDTO;
|
| 18 |
+
import com.dalab.autocompliance.dto.ControlEvaluationResponseDTO;
|
| 19 |
+
import com.dalab.autocompliance.dto.ReportGenerationRequestDTO;
|
| 20 |
+
import com.dalab.autocompliance.dto.ReportGenerationResponseDTO;
|
| 21 |
+
import com.dalab.autocompliance.dto.ReportJobStatusDTO;
|
| 22 |
+
import com.dalab.autocompliance.model.entity.ComplianceControlEntity;
|
| 23 |
+
import com.dalab.autocompliance.model.entity.ComplianceGeneratedReportEntity;
|
| 24 |
+
import com.dalab.autocompliance.model.entity.ComplianceReportDefinitionEntity;
|
| 25 |
+
import com.dalab.autocompliance.model.entity.ComplianceReportJobEntity;
|
| 26 |
+
import com.dalab.autocompliance.model.entity.ControlEvaluationJobEntity;
|
| 27 |
+
import com.dalab.autocompliance.model.mapper.ComplianceControlMapper;
|
| 28 |
+
import com.dalab.autocompliance.model.mapper.ComplianceGeneratedReportMapper;
|
| 29 |
+
import com.dalab.autocompliance.model.mapper.ComplianceReportDefinitionMapper;
|
| 30 |
+
import com.dalab.autocompliance.model.mapper.ComplianceReportJobMapper;
|
| 31 |
+
import com.dalab.autocompliance.model.mapper.ControlEvaluationJobMapper;
|
| 32 |
+
import com.dalab.autocompliance.model.repository.ComplianceControlRepository;
|
| 33 |
+
import com.dalab.autocompliance.model.repository.ComplianceGeneratedReportRepository;
|
| 34 |
+
import com.dalab.autocompliance.model.repository.ComplianceReportDefinitionRepository;
|
| 35 |
+
import com.dalab.autocompliance.model.repository.ComplianceReportJobRepository;
|
| 36 |
+
import com.dalab.autocompliance.model.repository.ControlEvaluationJobRepository;
|
| 37 |
+
import com.dalab.autocompliance.service.IComplianceService;
|
| 38 |
+
import com.dalab.autocompliance.service.exception.ControlNotFoundException;
|
| 39 |
+
import com.dalab.autocompliance.service.exception.GeneratedReportNotFoundException;
|
| 40 |
+
import com.dalab.autocompliance.service.exception.ReportDefinitionNotFoundException;
|
| 41 |
+
import com.dalab.autocompliance.service.exception.ReportJobNotFoundException;
|
| 42 |
+
|
| 43 |
+
import jakarta.annotation.PostConstruct;
|
| 44 |
+
import lombok.RequiredArgsConstructor;
|
| 45 |
+
import lombok.extern.slf4j.Slf4j;
|
| 46 |
+
|
| 47 |
+
@Service("complianceService")
|
| 48 |
+
@RequiredArgsConstructor
|
| 49 |
+
@Slf4j
|
| 50 |
+
public class ComplianceServiceImpl implements IComplianceService {
|
| 51 |
+
|
| 52 |
+
private final ComplianceReportDefinitionRepository reportDefinitionRepository;
|
| 53 |
+
private final ComplianceReportJobRepository reportJobRepository;
|
| 54 |
+
private final ComplianceGeneratedReportRepository generatedReportRepository;
|
| 55 |
+
private final ComplianceControlRepository controlRepository;
|
| 56 |
+
private final ControlEvaluationJobRepository controlEvaluationJobRepository;
|
| 57 |
+
|
| 58 |
+
private final ComplianceReportDefinitionMapper reportDefinitionMapper;
|
| 59 |
+
private final ComplianceReportJobMapper reportJobMapper;
|
| 60 |
+
private final ComplianceGeneratedReportMapper generatedReportMapper;
|
| 61 |
+
private final ComplianceControlMapper controlMapper;
|
| 62 |
+
private final ControlEvaluationJobMapper controlEvaluationJobMapper;
|
| 63 |
+
|
| 64 |
+
@PostConstruct
|
| 65 |
+
@Transactional
|
| 66 |
+
public void initDefaultData() {
|
| 67 |
+
initDefaultReportDefinitions();
|
| 68 |
+
initDefaultControls();
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
public void initDefaultReportDefinitions() {
|
| 72 |
+
if (reportDefinitionRepository.count() == 0) {
|
| 73 |
+
log.info("Initializing default compliance report definitions...");
|
| 74 |
+
List<ComplianceReportDefinitionEntity> defaultDefinitions = new ArrayList<>();
|
| 75 |
+
defaultDefinitions.add(ComplianceReportDefinitionEntity.builder()
|
| 76 |
+
.reportType("cis-gcp-foundations-v1.3")
|
| 77 |
+
.displayName("CIS Google Cloud Platform Foundations Benchmark v1.3")
|
| 78 |
+
.description("Checks for compliance against the CIS GCP Foundations Benchmark v1.3.")
|
| 79 |
+
.version("1.3.0")
|
| 80 |
+
.applicableComplianceFrameworks(List.of("CIS Benchmark"))
|
| 81 |
+
.targetAssetTypes(List.of("GCP_PROJECT", "GCP_IAM_POLICY", "GCP_VPC_NETWORK"))
|
| 82 |
+
.generationParametersDefinition(Map.of("gcpProjectId", "string", "targetRegions", "list_string"))
|
| 83 |
+
.detailsLink("https://www.cisecurity.org/benchmark/google_cloud_computing_platform/")
|
| 84 |
+
.build());
|
| 85 |
+
|
| 86 |
+
defaultDefinitions.add(ComplianceReportDefinitionEntity.builder()
|
| 87 |
+
.reportType("pci-dss-aws-v3.2.1")
|
| 88 |
+
.displayName("PCI DSS v3.2.1 for AWS Infrastructure")
|
| 89 |
+
.description("Assesses AWS resources against applicable PCI DSS v3.2.1 requirements.")
|
| 90 |
+
.version("3.2.1")
|
| 91 |
+
.applicableComplianceFrameworks(List.of("PCI DSS v3.2.1"))
|
| 92 |
+
.targetAssetTypes(List.of("AWS_EC2_INSTANCE", "AWS_S3_BUCKET", "AWS_VPC"))
|
| 93 |
+
.generationParametersDefinition(Map.of("awsAccountId", "string", "awsRegion", "string"))
|
| 94 |
+
.detailsLink("https://aws.amazon.com/compliance/pci-dss/")
|
| 95 |
+
.build());
|
| 96 |
+
reportDefinitionRepository.saveAll(defaultDefinitions);
|
| 97 |
+
log.info("{} default compliance report definitions initialized.", defaultDefinitions.size());
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
public void initDefaultControls() {
|
| 102 |
+
if (controlRepository.count() == 0) {
|
| 103 |
+
log.info("Initializing default compliance controls...");
|
| 104 |
+
List<ComplianceControlEntity> defaultControls = new ArrayList<>();
|
| 105 |
+
defaultControls.add(ComplianceControlEntity.builder()
|
| 106 |
+
.controlId("CIS-GCP-1.1")
|
| 107 |
+
.name("Ensure that corporate login credentials are used instead of gmail.com accounts")
|
| 108 |
+
.description("GCP supports using Google Workspace or Cloud Identity to manage user identities. It is recommended to use managed corporate accounts instead of personal gmail.com accounts for managing cloud resources.")
|
| 109 |
+
.severity("MEDIUM")
|
| 110 |
+
.applicableFrameworks(List.of("CIS GCP Foundations Benchmark v1.3"))
|
| 111 |
+
.targetAssetTypes(List.of("GCP_IAM_POLICY"))
|
| 112 |
+
.remediationSteps("Migrate any gmail.com accounts with IAM roles to managed corporate accounts.")
|
| 113 |
+
.evaluationParametersDefinition(Map.of("gcpProjectId", "string"))
|
| 114 |
+
.detailsLink("https://www.cisecurity.org/benchmark/google_cloud_computing_platform/") // Point to specific control if possible
|
| 115 |
+
.enabled(true)
|
| 116 |
+
.build());
|
| 117 |
+
defaultControls.add(ComplianceControlEntity.builder()
|
| 118 |
+
.controlId("PCI-REQ-8.2.3")
|
| 119 |
+
.name("Use strong passwords (or passphrases)")
|
| 120 |
+
.description("Ensure passwords/passphrases meet minimum complexity requirements as defined by PCI DSS requirement 8.2.3.")
|
| 121 |
+
.severity("HIGH")
|
| 122 |
+
.applicableFrameworks(List.of("PCI DSS v3.2.1"))
|
| 123 |
+
.targetAssetTypes(List.of("AWS_IAM_USER", "Linux_Server")) // Example asset types
|
| 124 |
+
.remediationSteps("Configure password policies to enforce complexity. For existing users, enforce password change at next login.")
|
| 125 |
+
.evaluationParametersDefinition(Map.of("minPasswordLength", "integer", "requiresUppercase", "boolean")) // Example params
|
| 126 |
+
.detailsLink("https://www.pcisecuritystandards.org/") // Point to specific control
|
| 127 |
+
.enabled(true)
|
| 128 |
+
.build());
|
| 129 |
+
controlRepository.saveAll(defaultControls);
|
| 130 |
+
log.info("{} default compliance controls initialized.", defaultControls.size());
|
| 131 |
+
}
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
@Override
|
| 135 |
+
@Transactional(readOnly = true)
|
| 136 |
+
public List<ComplianceReportDefinitionDTO> listAvailableReportDefinitions() {
|
| 137 |
+
log.debug("Fetching all available report definitions.");
|
| 138 |
+
List<ComplianceReportDefinitionEntity> entities = reportDefinitionRepository.findAll();
|
| 139 |
+
return reportDefinitionMapper.toDtoList(entities);
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
@Override
|
| 143 |
+
@Transactional
|
| 144 |
+
public ReportGenerationResponseDTO generateComplianceReport(String reportType, ReportGenerationRequestDTO request) {
|
| 145 |
+
log.info("Request to generate report type: {} with parameters: {}", reportType, request.getParameters());
|
| 146 |
+
|
| 147 |
+
ComplianceReportDefinitionEntity definitionEntity = reportDefinitionRepository.findByReportTypeIgnoreCase(reportType)
|
| 148 |
+
.orElseThrow(() -> {
|
| 149 |
+
log.warn("Report type '{}' not found.", reportType);
|
| 150 |
+
return new ReportDefinitionNotFoundException("Report type " + reportType + " not found.");
|
| 151 |
+
});
|
| 152 |
+
|
| 153 |
+
// Validate parameters (basic check for key presence)
|
| 154 |
+
if (request.getParameters() == null ||
|
| 155 |
+
!request.getParameters().keySet().containsAll(definitionEntity.getGenerationParametersDefinition().keySet())) {
|
| 156 |
+
String errorMsg = String.format("Missing required parameters for report type '%s'. Required: %s, Provided: %s",
|
| 157 |
+
reportType, definitionEntity.getGenerationParametersDefinition().keySet(),
|
| 158 |
+
request.getParameters() != null ? request.getParameters().keySet() : "null");
|
| 159 |
+
log.warn(errorMsg);
|
| 160 |
+
// For immediate feedback, we can return a response, though throwing an exception is also an option.
|
| 161 |
+
return ReportGenerationResponseDTO.builder()
|
| 162 |
+
.jobId(null).reportType(reportType).status("FAILED_VALIDATION")
|
| 163 |
+
.submittedAt(LocalDateTime.now()).message(errorMsg)
|
| 164 |
+
.build();
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
ComplianceReportJobEntity jobEntity = reportJobMapper.fromGenerationRequest(request, reportType);
|
| 168 |
+
jobEntity.setJobId(UUID.randomUUID().toString());
|
| 169 |
+
jobEntity.setStatus("QUEUED");
|
| 170 |
+
jobEntity.setSubmittedAt(LocalDateTime.now());
|
| 171 |
+
jobEntity.setReportType(definitionEntity.getReportType()); // Ensure canonical report type
|
| 172 |
+
// triggeredBy and notificationEmail are mapped by mapper if present in request
|
| 173 |
+
|
| 174 |
+
reportJobRepository.save(jobEntity);
|
| 175 |
+
log.info("Report generation job {} for report type '{}' accepted and queued.", jobEntity.getJobId(), reportType);
|
| 176 |
+
|
| 177 |
+
// TODO: Trigger actual asynchronous report generation (e.g., via @Async method or Kafka message)
|
| 178 |
+
// This async process would later update the jobEntity status and link to a ComplianceGeneratedReportEntity.
|
| 179 |
+
|
| 180 |
+
return ReportGenerationResponseDTO.builder()
|
| 181 |
+
.jobId(jobEntity.getJobId()).reportType(reportType).status("ACCEPTED")
|
| 182 |
+
.submittedAt(jobEntity.getSubmittedAt()).message("Report generation accepted and queued.")
|
| 183 |
+
.build();
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
@Override
|
| 187 |
+
@Transactional(readOnly = true)
|
| 188 |
+
public ReportJobStatusDTO getReportGenerationJobStatus(String jobId) {
|
| 189 |
+
log.debug("Fetching status for job ID: {}", jobId);
|
| 190 |
+
ComplianceReportJobEntity jobEntity = reportJobRepository.findById(jobId)
|
| 191 |
+
.orElseThrow(() -> {
|
| 192 |
+
log.warn("Job ID '{}' not found.", jobId);
|
| 193 |
+
return new ReportJobNotFoundException("Job ID " + jobId + " not found.");
|
| 194 |
+
});
|
| 195 |
+
return reportJobMapper.toDto(jobEntity);
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
@Override
|
| 199 |
+
@Transactional(readOnly = true)
|
| 200 |
+
public ComplianceReportDTO getGeneratedReport(String reportId) {
|
| 201 |
+
log.debug("Fetching generated report for report ID: {}", reportId);
|
| 202 |
+
ComplianceGeneratedReportEntity reportEntity = generatedReportRepository.findById(reportId)
|
| 203 |
+
.orElseThrow(() -> {
|
| 204 |
+
log.warn("Report ID '{}' not found.", reportId);
|
| 205 |
+
return new GeneratedReportNotFoundException("Generated report with ID " + reportId + " not found.");
|
| 206 |
+
});
|
| 207 |
+
return generatedReportMapper.toDto(reportEntity);
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
@Override
|
| 211 |
+
@Transactional(readOnly = true)
|
| 212 |
+
public AssetComplianceStatusDTO getAssetComplianceStatus(String assetId) {
|
| 213 |
+
log.debug("Fetching compliance status for asset ID: {}", assetId);
|
| 214 |
+
|
| 215 |
+
// This is a simplified implementation. A more robust solution would involve:
|
| 216 |
+
// 1. Querying `ComplianceGeneratedReportEntity` for reports containing this assetId (potentially using the native query or service-layer filtering).
|
| 217 |
+
// 2. Aggregating findings from those reports.
|
| 218 |
+
// 3. Determining overall status based on those findings.
|
| 219 |
+
// For now, we mock it by looking for the dummy asset in any dummy report.
|
| 220 |
+
|
| 221 |
+
List<ComplianceGeneratedReportEntity> reportsWithAsset = generatedReportRepository.findReportsContainingAssetId(assetId);
|
| 222 |
+
|
| 223 |
+
if (reportsWithAsset.isEmpty()) {
|
| 224 |
+
log.warn("Asset ID '{}' not found in any generated reports or no compliance data available.", assetId);
|
| 225 |
+
return AssetComplianceStatusDTO.builder()
|
| 226 |
+
.assetId(assetId)
|
| 227 |
+
.overallComplianceStatus("UNKNOWN") // Or NOT_EVALUATED
|
| 228 |
+
.lastEvaluatedAt(LocalDateTime.now()) // Or null if never evaluated
|
| 229 |
+
.build();
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
List<AssetComplianceStatusDTO.ComplianceFindingSummaryDTO> assetFindingsSummaries = new ArrayList<>();
|
| 233 |
+
List<String> relevantReportIds = new ArrayList<>();
|
| 234 |
+
int compliantCount = 0;
|
| 235 |
+
int nonCompliantCount = 0;
|
| 236 |
+
String assetType = "UNKNOWN";
|
| 237 |
+
String assetName = "UNKNOWN";
|
| 238 |
+
LocalDateTime lastEvalTime = null;
|
| 239 |
+
|
| 240 |
+
for (ComplianceGeneratedReportEntity reportEntity : reportsWithAsset) {
|
| 241 |
+
relevantReportIds.add(reportEntity.getReportId());
|
| 242 |
+
if (reportEntity.getFindingsData() != null) {
|
| 243 |
+
for (com.dalab.autocompliance.model.entity.ReportFindingData findingData : reportEntity.getFindingsData()) {
|
| 244 |
+
if (assetId.equals(findingData.getAssetId())) {
|
| 245 |
+
// Update asset details from the first finding containing them (could be more sophisticated)
|
| 246 |
+
if ("UNKNOWN".equals(assetType) && findingData.getAssetType() != null) assetType = findingData.getAssetType();
|
| 247 |
+
if ("UNKNOWN".equals(assetName) && findingData.getAssetName() != null) assetName = findingData.getAssetName();
|
| 248 |
+
|
| 249 |
+
if ("NON_COMPLIANT".equalsIgnoreCase(findingData.getStatus())) {
|
| 250 |
+
nonCompliantCount++;
|
| 251 |
+
assetFindingsSummaries.add(AssetComplianceStatusDTO.ComplianceFindingSummaryDTO.builder()
|
| 252 |
+
.checkId(findingData.getCheckId())
|
| 253 |
+
.description(findingData.getDescription())
|
| 254 |
+
.severity(findingData.getSeverity())
|
| 255 |
+
.reportId(reportEntity.getReportId())
|
| 256 |
+
.findingTimestamp(reportEntity.getGenerationTimestamp())
|
| 257 |
+
.build());
|
| 258 |
+
} else if ("COMPLIANT".equalsIgnoreCase(findingData.getStatus())) {
|
| 259 |
+
compliantCount++;
|
| 260 |
+
}
|
| 261 |
+
// Update last evaluation time for this asset based on reports
|
| 262 |
+
if (lastEvalTime == null || reportEntity.getGenerationTimestamp().isAfter(lastEvalTime)) {
|
| 263 |
+
lastEvalTime = reportEntity.getGenerationTimestamp();
|
| 264 |
+
}
|
| 265 |
+
}
|
| 266 |
+
}
|
| 267 |
+
}
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
String overallStatus = "UNKNOWN";
|
| 271 |
+
if (compliantCount > 0 || nonCompliantCount > 0) {
|
| 272 |
+
overallStatus = nonCompliantCount > 0 ? "NON_COMPLIANT" : "COMPLIANT";
|
| 273 |
+
} else if (!reportsWithAsset.isEmpty()) {
|
| 274 |
+
overallStatus = "NO_FINDINGS"; // Or EVALUATED_COMPLIANT if all checks were compliant
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
return AssetComplianceStatusDTO.builder()
|
| 278 |
+
.assetId(assetId)
|
| 279 |
+
.assetType(assetType)
|
| 280 |
+
.assetName(assetName)
|
| 281 |
+
.overallComplianceStatus(overallStatus)
|
| 282 |
+
.lastEvaluatedAt(lastEvalTime != null ? lastEvalTime : LocalDateTime.now()) // Fallback, should ideally be from data
|
| 283 |
+
.totalChecksApplied(compliantCount + nonCompliantCount) // This is simplified, total checks could be different
|
| 284 |
+
.compliantChecks(compliantCount)
|
| 285 |
+
.nonCompliantChecks(nonCompliantCount)
|
| 286 |
+
.recentNonCompliantFindings(assetFindingsSummaries.stream().limit(5).collect(Collectors.toList()))
|
| 287 |
+
.relevantReportIds(relevantReportIds)
|
| 288 |
+
.build();
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
@Override
|
| 292 |
+
@Transactional(readOnly = true)
|
| 293 |
+
public List<ComplianceControlDTO> listAvailableControls() {
|
| 294 |
+
log.debug("Fetching all available and enabled compliance controls.");
|
| 295 |
+
List<ComplianceControlEntity> entities = controlRepository.findByEnabledTrue();
|
| 296 |
+
return controlMapper.toDtoList(entities);
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
@Override
|
| 300 |
+
@Transactional
|
| 301 |
+
public ControlEvaluationResponseDTO evaluateControl(String controlId, ControlEvaluationRequestDTO request) {
|
| 302 |
+
log.info("Request to evaluate control ID: {} with request: {}", controlId, request);
|
| 303 |
+
|
| 304 |
+
ComplianceControlEntity controlEntity = controlRepository.findByControlIdIgnoreCase(controlId)
|
| 305 |
+
.orElseThrow(() -> {
|
| 306 |
+
log.warn("Control ID '{}' not found.", controlId);
|
| 307 |
+
return new ControlNotFoundException("Control ID " + controlId + " not found.");
|
| 308 |
+
});
|
| 309 |
+
|
| 310 |
+
// Create and save the evaluation job
|
| 311 |
+
ControlEvaluationJobEntity jobEntity = controlEvaluationJobMapper.fromRequestDto(request, controlId);
|
| 312 |
+
jobEntity = controlEvaluationJobRepository.save(jobEntity);
|
| 313 |
+
|
| 314 |
+
log.info("Created control evaluation job {} for control {}", jobEntity.getJobId(), controlId);
|
| 315 |
+
|
| 316 |
+
// TODO: Implement actual control evaluation logic
|
| 317 |
+
// This would typically involve:
|
| 318 |
+
// 1. Fetching relevant assets based on request parameters
|
| 319 |
+
// 2. Applying the control's evaluation logic
|
| 320 |
+
// 3. Updating the job status and results
|
| 321 |
+
|
| 322 |
+
return controlEvaluationJobMapper.toResponseDto(jobEntity);
|
| 323 |
+
}
|
| 324 |
+
}
|
src/main/resources/application.properties
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# DALab AutoCompliance Service Configuration
|
| 2 |
+
spring.application.name=da-autocompliance
|
| 3 |
+
server.port=8080
|
| 4 |
+
|
| 5 |
+
# Database Configuration - da_autocompliance database
|
| 6 |
+
spring.datasource.url=jdbc:postgresql://localhost:5432/da_autocompliance
|
| 7 |
+
spring.datasource.username=da_autocompliance_user
|
| 8 |
+
spring.datasource.password=da_autocompliance_pass
|
| 9 |
+
spring.datasource.driver-class-name=org.postgresql.Driver
|
| 10 |
+
|
| 11 |
+
# JPA Configuration
|
| 12 |
+
spring.jpa.hibernate.ddl-auto=update
|
| 13 |
+
spring.jpa.show-sql=false
|
| 14 |
+
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
|
| 15 |
+
spring.jpa.properties.hibernate.format_sql=true
|
| 16 |
+
|
| 17 |
+
# Common entities database configuration (for da-protos entities)
|
| 18 |
+
dalab.common.datasource.url=jdbc:postgresql://localhost:5432/dalab_common
|
| 19 |
+
dalab.common.datasource.username=dalab_common_user
|
| 20 |
+
dalab.common.datasource.password=dalab_common_pass
|
| 21 |
+
|
| 22 |
+
# Kafka Configuration
|
| 23 |
+
spring.kafka.bootstrap-servers=localhost:9092
|
| 24 |
+
spring.kafka.consumer.group-id=da-autocompliance-group
|
| 25 |
+
spring.kafka.consumer.auto-offset-reset=earliest
|
| 26 |
+
spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer
|
| 27 |
+
spring.kafka.consumer.value-deserializer=org.springframework.kafka.support.serializer.JsonDeserializer
|
| 28 |
+
spring.kafka.consumer.properties.spring.json.trusted.packages=*
|
| 29 |
+
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
|
| 30 |
+
spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer
|
| 31 |
+
|
| 32 |
+
# Kafka Topics
|
| 33 |
+
dalab.kafka.topics.policy-actions=dalab.policies.actions
|
| 34 |
+
dalab.kafka.topics.compliance-events=dalab.compliance.events
|
| 35 |
+
|
| 36 |
+
# Security Configuration (Keycloak JWT)
|
| 37 |
+
spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8180/realms/dalab
|
| 38 |
+
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:8180/realms/dalab/protocol/openid-connect/certs
|
| 39 |
+
|
| 40 |
+
# Compliance Configuration
|
| 41 |
+
compliance.evaluation.batch.size=100
|
| 42 |
+
compliance.reports.default.retention.days=365
|
| 43 |
+
compliance.alerts.enabled=true
|
| 44 |
+
|
| 45 |
+
# Actuator Configuration
|
| 46 |
+
management.endpoints.web.exposure.include=health,info,metrics,prometheus
|
| 47 |
+
management.endpoint.health.show-details=when-authorized
|
| 48 |
+
management.metrics.export.prometheus.enabled=true
|
| 49 |
+
|
| 50 |
+
# OpenAPI Documentation
|
| 51 |
+
springdoc.api-docs.path=/v3/api-docs
|
| 52 |
+
springdoc.swagger-ui.path=/swagger-ui.html
|
| 53 |
+
|
| 54 |
+
# Logging Configuration
|
| 55 |
+
logging.level.com.dalab.autocompliance=INFO
|
| 56 |
+
logging.level.org.springframework.kafka=WARN
|
| 57 |
+
logging.level.org.springframework.security=WARN
|
src/test/java/com/dalab/autocompliance/controller/ComplianceControllerTest.java
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package com.dalab.autocompliance.controller;
|
| 2 |
+
|
| 3 |
+
import com.dalab.autocompliance.dto.*;
|
| 4 |
+
import com.dalab.autocompliance.service.IComplianceService;
|
| 5 |
+
import com.fasterxml.jackson.databind.ObjectMapper;
|
| 6 |
+
import org.junit.jupiter.api.BeforeEach;
|
| 7 |
+
import org.junit.jupiter.api.Test;
|
| 8 |
+
import org.springframework.beans.factory.annotation.Autowired;
|
| 9 |
+
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
| 10 |
+
import org.springframework.boot.test.mock.mockito.MockBean;
|
| 11 |
+
import org.springframework.http.MediaType;
|
| 12 |
+
import org.springframework.security.test.context.support.WithMockUser;
|
| 13 |
+
import org.springframework.test.web.servlet.MockMvc;
|
| 14 |
+
|
| 15 |
+
import java.time.LocalDateTime;
|
| 16 |
+
import java.util.Collections;
|
| 17 |
+
import java.util.List;
|
| 18 |
+
import java.util.Map;
|
| 19 |
+
import java.util.UUID;
|
| 20 |
+
|
| 21 |
+
import static org.mockito.ArgumentMatchers.any;
|
| 22 |
+
import static org.mockito.ArgumentMatchers.anyString;
|
| 23 |
+
import static org.mockito.BDDMockito.given;
|
| 24 |
+
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
| 25 |
+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
| 26 |
+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
| 27 |
+
|
| 28 |
+
@WebMvcTest(ComplianceController.class)
|
| 29 |
+
class ComplianceControllerTest {
|
| 30 |
+
|
| 31 |
+
@Autowired
|
| 32 |
+
private MockMvc mockMvc;
|
| 33 |
+
|
| 34 |
+
@MockBean
|
| 35 |
+
private IComplianceService complianceService;
|
| 36 |
+
|
| 37 |
+
@Autowired
|
| 38 |
+
private ObjectMapper objectMapper;
|
| 39 |
+
|
| 40 |
+
private ComplianceReportDefinitionDTO reportDefinitionDTO;
|
| 41 |
+
private ReportGenerationRequestDTO reportGenerationRequestDTO;
|
| 42 |
+
private ReportGenerationResponseDTO reportGenerationResponseDTO;
|
| 43 |
+
private ReportJobStatusDTO reportJobStatusDTO;
|
| 44 |
+
private ComplianceReportDTO complianceReportDTO;
|
| 45 |
+
private AssetComplianceStatusDTO assetComplianceStatusDTO;
|
| 46 |
+
private ComplianceControlDTO complianceControlDTO;
|
| 47 |
+
private ControlEvaluationRequestDTO controlEvaluationRequestDTO;
|
| 48 |
+
private ControlEvaluationResponseDTO controlEvaluationResponseDTO;
|
| 49 |
+
|
| 50 |
+
@BeforeEach
|
| 51 |
+
void setUp() {
|
| 52 |
+
reportDefinitionDTO = ComplianceReportDefinitionDTO.builder().reportType("test-report").displayName("Test Report").build();
|
| 53 |
+
|
| 54 |
+
reportGenerationRequestDTO = ReportGenerationRequestDTO.builder().parameters(Map.of("param1", "value1")).build();
|
| 55 |
+
reportGenerationResponseDTO = ReportGenerationResponseDTO.builder().jobId(UUID.randomUUID().toString()).status("ACCEPTED").build();
|
| 56 |
+
|
| 57 |
+
reportJobStatusDTO = ReportJobStatusDTO.builder().jobId(UUID.randomUUID().toString()).status("COMPLETED_SUCCESS").build();
|
| 58 |
+
|
| 59 |
+
complianceReportDTO = ComplianceReportDTO.builder().reportId(UUID.randomUUID().toString()).overallStatus("COMPLIANT").build();
|
| 60 |
+
|
| 61 |
+
assetComplianceStatusDTO = AssetComplianceStatusDTO.builder().assetId("asset-123").overallComplianceStatus("COMPLIANT").build();
|
| 62 |
+
|
| 63 |
+
complianceControlDTO = ComplianceControlDTO.builder().controlId("control-001").name("Test Control").enabled(true).build();
|
| 64 |
+
|
| 65 |
+
controlEvaluationRequestDTO = ControlEvaluationRequestDTO.builder().targetAssetIds(List.of("asset-123")).build();
|
| 66 |
+
controlEvaluationResponseDTO = ControlEvaluationResponseDTO.builder().jobId(UUID.randomUUID().toString()).status("ACCEPTED").build();
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
@Test
|
| 70 |
+
@WithMockUser(roles = "USER")
|
| 71 |
+
void listAvailableReportDefinitions_shouldReturnOk() throws Exception {
|
| 72 |
+
given(complianceService.listAvailableReportDefinitions()).willReturn(Collections.singletonList(reportDefinitionDTO));
|
| 73 |
+
mockMvc.perform(get("/api/v1/compliance/reports"))
|
| 74 |
+
.andExpect(status().isOk())
|
| 75 |
+
.andExpect(jsonPath("$[0].reportType").value("test-report"));
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
@Test
|
| 79 |
+
@WithMockUser(roles = "ADMIN")
|
| 80 |
+
void generateComplianceReport_shouldReturnAccepted() throws Exception {
|
| 81 |
+
given(complianceService.generateComplianceReport(anyString(), any(ReportGenerationRequestDTO.class))).willReturn(reportGenerationResponseDTO);
|
| 82 |
+
mockMvc.perform(post("/api/v1/compliance/reports/test-report/generate").with(csrf())
|
| 83 |
+
.contentType(MediaType.APPLICATION_JSON)
|
| 84 |
+
.content(objectMapper.writeValueAsString(reportGenerationRequestDTO)))
|
| 85 |
+
.andExpect(status().isAccepted())
|
| 86 |
+
.andExpect(jsonPath("$.status").value("ACCEPTED"));
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
@Test
|
| 90 |
+
@WithMockUser(roles = "USER")
|
| 91 |
+
void getReportGenerationJobStatus_shouldReturnOk() throws Exception {
|
| 92 |
+
given(complianceService.getReportGenerationJobStatus(anyString())).willReturn(reportJobStatusDTO);
|
| 93 |
+
mockMvc.perform(get("/api/v1/compliance/reports/jobs/some-job-id"))
|
| 94 |
+
.andExpect(status().isOk())
|
| 95 |
+
.andExpect(jsonPath("$.status").value("COMPLETED_SUCCESS"));
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
@Test
|
| 99 |
+
@WithMockUser(roles = "USER")
|
| 100 |
+
void getReportGenerationJobStatus_whenNotFound_shouldReturnNotFound() throws Exception {
|
| 101 |
+
ReportJobStatusDTO notFoundDto = ReportJobStatusDTO.builder().jobId("not-found-id").status("NOT_FOUND").build();
|
| 102 |
+
given(complianceService.getReportGenerationJobStatus("not-found-id")).willReturn(notFoundDto);
|
| 103 |
+
mockMvc.perform(get("/api/v1/compliance/reports/jobs/not-found-id"))
|
| 104 |
+
.andExpect(status().isNotFound());
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
@Test
|
| 108 |
+
@WithMockUser(roles = "USER")
|
| 109 |
+
void getGeneratedReport_shouldReturnOk() throws Exception {
|
| 110 |
+
given(complianceService.getGeneratedReport(anyString())).willReturn(complianceReportDTO);
|
| 111 |
+
mockMvc.perform(get("/api/v1/compliance/reports/results/some-report-id"))
|
| 112 |
+
.andExpect(status().isOk())
|
| 113 |
+
.andExpect(jsonPath("$.overallStatus").value("COMPLIANT"));
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
@Test
|
| 117 |
+
@WithMockUser(roles = "USER")
|
| 118 |
+
void getGeneratedReport_whenNotFound_shouldReturnNotFound() throws Exception {
|
| 119 |
+
given(complianceService.getGeneratedReport("not-found-id")).willReturn(null);
|
| 120 |
+
mockMvc.perform(get("/api/v1/compliance/reports/results/not-found-id"))
|
| 121 |
+
.andExpect(status().isNotFound());
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
@Test
|
| 125 |
+
@WithMockUser(roles = "USER")
|
| 126 |
+
void getAssetComplianceStatus_shouldReturnOk() throws Exception {
|
| 127 |
+
given(complianceService.getAssetComplianceStatus(anyString())).willReturn(assetComplianceStatusDTO);
|
| 128 |
+
mockMvc.perform(get("/api/v1/compliance/assets/asset-123"))
|
| 129 |
+
.andExpect(status().isOk())
|
| 130 |
+
.andExpect(jsonPath("$.overallComplianceStatus").value("COMPLIANT"));
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
@Test
|
| 134 |
+
@WithMockUser(roles = "USER")
|
| 135 |
+
void getAssetComplianceStatus_whenNotFound_shouldReturnNotFound() throws Exception {
|
| 136 |
+
AssetComplianceStatusDTO notFoundStatus = AssetComplianceStatusDTO.builder().assetId("asset-not-found").overallComplianceStatus("UNKNOWN").relevantReportIds(null).build();
|
| 137 |
+
given(complianceService.getAssetComplianceStatus("asset-not-found")).willReturn(notFoundStatus);
|
| 138 |
+
mockMvc.perform(get("/api/v1/compliance/assets/asset-not-found"))
|
| 139 |
+
.andExpect(status().isNotFound());
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
@Test
|
| 143 |
+
@WithMockUser(roles = "USER")
|
| 144 |
+
void listAvailableControls_shouldReturnOk() throws Exception {
|
| 145 |
+
given(complianceService.listAvailableControls()).willReturn(Collections.singletonList(complianceControlDTO));
|
| 146 |
+
mockMvc.perform(get("/api/v1/compliance/controls"))
|
| 147 |
+
.andExpect(status().isOk())
|
| 148 |
+
.andExpect(jsonPath("$[0].controlId").value("control-001"));
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
@Test
|
| 152 |
+
@WithMockUser(roles = "ADMIN")
|
| 153 |
+
void evaluateControl_shouldReturnAccepted() throws Exception {
|
| 154 |
+
given(complianceService.evaluateControl(anyString(), any(ControlEvaluationRequestDTO.class))).willReturn(controlEvaluationResponseDTO);
|
| 155 |
+
mockMvc.perform(post("/api/v1/compliance/controls/control-001/evaluate").with(csrf())
|
| 156 |
+
.contentType(MediaType.APPLICATION_JSON)
|
| 157 |
+
.content(objectMapper.writeValueAsString(controlEvaluationRequestDTO)))
|
| 158 |
+
.andExpect(status().isAccepted())
|
| 159 |
+
.andExpect(jsonPath("$.status").value("ACCEPTED"));
|
| 160 |
+
}
|
| 161 |
+
}
|
src/test/java/com/dalab/autocompliance/service/impl/ComplianceServiceImplTest.java
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|