File size: 9,387 Bytes
688925d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package com.dalab.autocompliance.controller;

import com.dalab.autocompliance.dto.ComplianceReportDefinitionDTO;
import com.dalab.autocompliance.dto.ReportGenerationRequestDTO;
import com.dalab.autocompliance.dto.ReportGenerationResponseDTO;
import com.dalab.autocompliance.dto.ReportJobStatusDTO;
import com.dalab.autocompliance.dto.ComplianceReportDTO;
import com.dalab.autocompliance.dto.AssetComplianceStatusDTO;
import com.dalab.autocompliance.dto.ComplianceControlDTO;
import com.dalab.autocompliance.dto.ControlEvaluationRequestDTO;
import com.dalab.autocompliance.dto.ControlEvaluationResponseDTO;
import com.dalab.autocompliance.service.IComplianceService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/v1/compliance")
@Tag(name = "Compliance API", description = "APIs for managing compliance checks, reports, and evaluations")
@RequiredArgsConstructor
public class ComplianceController {

    private final IComplianceService complianceService;

    @Operation(summary = "List available compliance report definitions",
               description = "Provides a list of all configured compliance report types that can be generated.",
               responses = {
                   @ApiResponse(responseCode = "200", description = "Successfully retrieved report definitions")
               })
    @GetMapping("/reports")
    @PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')") // Broad access to see what reports are available
    public ResponseEntity<List<ComplianceReportDefinitionDTO>> listAvailableReportDefinitions() {
        List<ComplianceReportDefinitionDTO> definitions = complianceService.listAvailableReportDefinitions();
        return ResponseEntity.ok(definitions);
    }

    @Operation(summary = "Generate a compliance report",
               description = "Triggers the asynchronous generation of a specific compliance report based on its type and provided parameters.",
               responses = {
                   @ApiResponse(responseCode = "202", description = "Report generation request accepted."),
                   @ApiResponse(responseCode = "400", description = "Invalid request (e.g., missing parameters, report type not found)"),
                   @ApiResponse(responseCode = "404", description = "Report type not found") // Covered by 400 in current impl
               })
    @PostMapping("/reports/{reportType}/generate")
    @PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD')") // Users who can trigger generation
    public ResponseEntity<ReportGenerationResponseDTO> generateComplianceReport(
            @Parameter(description = "Unique identifier of the report type to generate", required = true) 
            @PathVariable String reportType,
            @Parameter(description = "Parameters required for the report generation", required = true)
            @Valid @RequestBody ReportGenerationRequestDTO request) {
        
        ReportGenerationResponseDTO response = complianceService.generateComplianceReport(reportType, request);
        
        if ("FAILED_VALIDATION".equals(response.getStatus())) {
            return ResponseEntity.badRequest().body(response);
        }
        return ResponseEntity.status(HttpStatus.ACCEPTED).body(response);
    }

    @Operation(summary = "Get compliance report generation job status",
               description = "Retrieves the current status of an asynchronous report generation job.",
               responses = {
                   @ApiResponse(responseCode = "200", description = "Successfully retrieved job status."),
                   @ApiResponse(responseCode = "404", description = "Job ID not found.")
               })
    @GetMapping("/reports/jobs/{jobId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')") // Users who can view job status
    public ResponseEntity<ReportJobStatusDTO> getReportGenerationJobStatus(
            @Parameter(description = "ID of the report generation job", required = true) 
            @PathVariable String jobId) {
        ReportJobStatusDTO jobStatus = complianceService.getReportGenerationJobStatus(jobId);
        if ("NOT_FOUND".equals(jobStatus.getStatus())) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(jobStatus);
        }
        return ResponseEntity.ok(jobStatus);
    }

    @Operation(summary = "Retrieve a generated compliance report",
               description = "Fetches the detailed contents of a previously generated compliance report.",
               responses = {
                   @ApiResponse(responseCode = "200", description = "Successfully retrieved the report."),
                   @ApiResponse(responseCode = "404", description = "Report ID not found.")
               })
    @GetMapping("/reports/results/{reportId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')") // Users who can view reports
    public ResponseEntity<ComplianceReportDTO> getGeneratedReport(
            @Parameter(description = "ID of the generated compliance report", required = true) 
            @PathVariable String reportId) {
        ComplianceReportDTO report = complianceService.getGeneratedReport(reportId);
        if (report == null) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok(report);
    }

    @Operation(summary = "Get compliance status for an asset",
               description = "Retrieves the overall compliance status and recent findings for a specific asset.",
               responses = {
                   @ApiResponse(responseCode = "200", description = "Successfully retrieved asset compliance status."),
                   @ApiResponse(responseCode = "404", description = "Asset ID not found or no compliance data available.")
               })
    @GetMapping("/assets/{assetId}/status")
    @PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')")
    public ResponseEntity<AssetComplianceStatusDTO> getAssetComplianceStatus(
            @Parameter(description = "ID of the asset (e.g., cloud resource ID)", required = true) 
            @PathVariable String assetId) {
        AssetComplianceStatusDTO status = complianceService.getAssetComplianceStatus(assetId);
        if ("UNKNOWN".equals(status.getOverallComplianceStatus()) && status.getRelevantReportIds() == null) { // Basic check for 'not found'
             return ResponseEntity.status(HttpStatus.NOT_FOUND).body(status); // Provide status with UNKNOWN if created that way
        }
        return ResponseEntity.ok(status);
    }

    @Operation(summary = "List available compliance controls",
               description = "Provides a list of all configured and typically enabled compliance controls that can be evaluated.",
               responses = {
                   @ApiResponse(responseCode = "200", description = "Successfully retrieved compliance controls")
               })
    @GetMapping("/controls")
    @PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD', 'USER', 'AUDITOR')") // Broad access to see available controls
    public ResponseEntity<List<ComplianceControlDTO>> listAvailableControls() {
        List<ComplianceControlDTO> controls = complianceService.listAvailableControls();
        return ResponseEntity.ok(controls);
    }

    @Operation(summary = "Evaluate a compliance control",
               description = "Triggers the asynchronous evaluation of a specific compliance control.",
               responses = {
                   @ApiResponse(responseCode = "202", description = "Control evaluation request accepted."),
                   @ApiResponse(responseCode = "400", description = "Invalid request (e.g., missing parameters, control not enabled)"),
                   @ApiResponse(responseCode = "404", description = "Control ID not found")
               })
    @PostMapping("/controls/{controlId}/evaluate")
    @PreAuthorize("hasAnyRole('ADMIN', 'DATA_STEWARD')") // Users who can trigger evaluations
    public ResponseEntity<ControlEvaluationResponseDTO> evaluateControl(
            @Parameter(description = "Unique identifier of the control to evaluate", required = true) 
            @PathVariable String controlId,
            @Parameter(description = "Parameters for the control evaluation", required = true)
            @Valid @RequestBody ControlEvaluationRequestDTO request) {
        
        ControlEvaluationResponseDTO response = complianceService.evaluateControl(controlId, request);
        
        if ("FAILED_VALIDATION".equals(response.getStatus())) {
            return ResponseEntity.badRequest().body(response);
        }
        // Assuming ControlNotFoundException is handled by a global exception handler to return 404
        return ResponseEntity.status(HttpStatus.ACCEPTED).body(response);
    }

    // TODO: Add endpoint for GET /controls/evaluations/{jobId} (status of a control evaluation job)
}