Skip to content

Commit 94a84f5

Browse files
committed
feat: implement compliance orchestrator backend client and evaluation logic
1 parent 610552f commit 94a84f5

12 files changed

Lines changed: 192 additions & 13 deletions

File tree

backend/src/main/java/com/park/utmstack/config/Constants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ public final class Constants {
164164
public static final List<String> API_ENDPOINT_IGNORE = Collections.emptyList();
165165

166166
// Application version file
167-
public static final String APP_VERSION_FILE = "/updates/version.json";
167+
public static final String APP_VERSION_FILE = "/Users/elena/Documents/Work/UTM Stack/version.json"; //TODO: ELENA
168168

169169
public static final String ADMIN_EMAIL = "admin@localhost";
170170

backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import org.springframework.stereotype.Service;
1212

1313
import javax.transaction.Transactional;
14-
import java.util.List;
1514
import java.util.Map;
1615
import java.util.stream.Collectors;
1716

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.park.utmstack.service.compliance.config;
2+
3+
import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto;
4+
import com.park.utmstack.service.elasticsearch.ElasticsearchService;
5+
import org.springframework.stereotype.Service;
6+
7+
import java.util.List;
8+
9+
@Service
10+
public class UtmComplianceControlEvaluationService {
11+
12+
private final ElasticsearchService elasticsearchService;
13+
14+
public UtmComplianceControlEvaluationService(ElasticsearchService elasticsearchService) {
15+
this.elasticsearchService = elasticsearchService;
16+
}
17+
18+
public List<UtmComplianceControlEvaluationDto> findByControlId(Long controlId) {
19+
return elasticsearchService.getControlEvaluations(controlId);
20+
}
21+
}
22+
23+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.park.utmstack.service.dto.compliance;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import lombok.Data;
5+
6+
import java.time.Instant;
7+
import java.util.List;
8+
9+
@Data
10+
@JsonIgnoreProperties(ignoreUnknown = true)
11+
public class UtmComplianceControlEvaluationDto {
12+
13+
private Long controlId;
14+
private String controlName;
15+
private String status;
16+
private Instant timestamp;
17+
private List<UtmComplianceQueryEvaluationDto> queryEvaluations;
18+
}
19+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.park.utmstack.service.dto.compliance;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import lombok.Data;
5+
6+
import java.util.List;
7+
import java.util.Map;
8+
9+
@Data
10+
@JsonIgnoreProperties(ignoreUnknown = true)
11+
public class UtmComplianceQueryEvaluationDto {
12+
13+
private Long queryConfigId;
14+
private String queryName;
15+
private Integer hits;
16+
private String status;
17+
private String errorMessage;
18+
private List<Map<String, Object>> evidence;
19+
}

backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import com.park.utmstack.service.MailService;
1111
import com.park.utmstack.service.UtmSpaceNotificationControlService;
1212
import com.park.utmstack.service.application_events.ApplicationEventService;
13+
import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto;
14+
import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationMapper;
1315
import com.park.utmstack.util.chart_builder.IndexPropertyType;
1416
import com.park.utmstack.util.exceptions.OpenSearchIndexNotFoundException;
1517
import com.park.utmstack.util.exceptions.UtmElasticsearchException;
@@ -20,6 +22,7 @@
2022
import com.utmstack.opensearch_connector.types.IndexSort;
2123
import com.utmstack.opensearch_connector.types.SearchSqlResponse;
2224
import com.utmstack.opensearch_connector.types.SqlQueryRequest;
25+
import org.opensearch.client.opensearch._types.FieldValue;
2326
import org.opensearch.client.opensearch._types.SortOrder;
2427
import org.opensearch.client.opensearch._types.query_dsl.Query;
2528
import org.opensearch.client.opensearch.cat.indices.IndicesRecord;
@@ -403,4 +406,20 @@ public <T> SearchSqlResponse<T> searchBySql(SqlQueryRequest request, Class<T> re
403406
throw new RuntimeException(ctx + ": " + e.getMessage());
404407
}
405408
}
409+
410+
public List<UtmComplianceControlEvaluationDto> getControlEvaluations(Long controlId) {
411+
final String ctx = CLASSNAME + ".getControlEvaluations";
412+
try {
413+
Query query = Query.of(q -> q.term(t -> t.field("control_id").value(FieldValue.of(controlId.toString())))
414+
);
415+
416+
SearchRequest request = new SearchRequest.Builder().index("v11-log-compliance-evaluation").query(query).size(1000).build();
417+
SearchResponse<Map> response = search(request, Map.class);
418+
419+
return response.hits().hits().stream().map(hit -> UtmComplianceControlEvaluationMapper.mapToEvaluationDto(hit.source())).toList();
420+
421+
} catch (Exception e) {
422+
throw new RuntimeException(ctx + ": " + e.getMessage(), e);
423+
}
424+
}
406425
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.park.utmstack.service.mapper.compliance;
2+
3+
import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto;
4+
import com.park.utmstack.service.dto.compliance.UtmComplianceQueryEvaluationDto;
5+
6+
import java.time.Instant;
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
public class UtmComplianceControlEvaluationMapper {
11+
12+
private UtmComplianceControlEvaluationMapper() {
13+
14+
}
15+
16+
public static UtmComplianceControlEvaluationDto mapToEvaluationDto(Map<String, Object> src) {
17+
UtmComplianceControlEvaluationDto dto = new UtmComplianceControlEvaluationDto();
18+
19+
dto.setControlId(((Number) src.get("control_id")).longValue());
20+
dto.setControlName((String) src.get("control_name"));
21+
dto.setStatus((String) src.get("status"));
22+
dto.setTimestamp(Instant.parse((String) src.get("timestamp")));
23+
24+
List<Map<String, Object>> q = (List<Map<String, Object>>) src.get("query_evaluations");
25+
if (q != null) {
26+
dto.setQueryEvaluations(q.stream().map(UtmComplianceControlEvaluationMapper::mapQueryEval).toList());
27+
}
28+
29+
return dto;
30+
}
31+
32+
private static UtmComplianceQueryEvaluationDto mapQueryEval(Map<String, Object> src) {
33+
UtmComplianceQueryEvaluationDto dto = new UtmComplianceQueryEvaluationDto();
34+
35+
dto.setQueryConfigId(((Number) src.get("queryConfigId")).longValue());
36+
dto.setQueryName((String) src.get("queryName"));
37+
dto.setHits(((Number) src.get("hits")).intValue());
38+
dto.setStatus((String) src.get("status"));
39+
dto.setEvidence((List<Map<String, Object>>) src.get("evidence"));
40+
41+
return dto;
42+
}
43+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.park.utmstack.web.rest.compliance.config;
2+
3+
import com.park.utmstack.service.compliance.config.UtmComplianceControlEvaluationService;
4+
import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto;
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.annotation.*;
7+
8+
import java.util.List;
9+
10+
@RestController
11+
@RequestMapping("/api/compliance/control-config")
12+
public class UtmComplianceControlEvaluationResource {
13+
14+
private final UtmComplianceControlEvaluationService evaluationService;
15+
16+
public UtmComplianceControlEvaluationResource(UtmComplianceControlEvaluationService evaluationService) {
17+
this.evaluationService = evaluationService;
18+
}
19+
20+
@GetMapping("/{id}/evaluations")
21+
public ResponseEntity<List<UtmComplianceControlEvaluationDto>> getControlEvaluations(@PathVariable Long id) {
22+
var evaluations = evaluationService.findByControlId(id);
23+
return ResponseEntity.ok(evaluations);
24+
}
25+
}
26+

plugins/compliance-orchestrator/client/opensearch.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ func ConnectOpenSearch() error {
3030
}
3131

3232
type SQLResponse struct {
33-
Total int `json:"total"`
33+
Schema []any `json:"schema"`
34+
DataRows [][]any `json:"datarows"`
35+
Total int `json:"total"`
3436
}
3537

36-
func (b *BackendClient) ExecuteSQLQuery(ctx context.Context, sql string) (int, error) {
38+
func (b *BackendClient) ExecuteSQLQuery(ctx context.Context, sql string) (SQLResult, error) {
3739
baseURL := plugins.PluginCfg("org.opensearch", false).Get("opensearch").String()
3840
sqlEndpoint := fmt.Sprintf("%s/_plugins/_sql", baseURL)
3941

@@ -43,26 +45,30 @@ func (b *BackendClient) ExecuteSQLQuery(ctx context.Context, sql string) (int, e
4345

4446
jsonBody, err := json.Marshal(body)
4547
if err != nil {
46-
return 0, fmt.Errorf("failed to marshal SQL body: %w", err)
48+
return SQLResult{}, fmt.Errorf("failed to marshal SQL body: %w", err)
4749
}
4850

4951
req, err := http.NewRequestWithContext(ctx, "POST", sqlEndpoint, bytes.NewBuffer(jsonBody))
5052
if err != nil {
51-
return 0, fmt.Errorf("failed to create SQL request: %w", err)
53+
return SQLResult{}, fmt.Errorf("failed to create SQL request: %w", err)
5254
}
5355

5456
req.Header.Set("Content-Type", "application/json")
5557

5658
resp, err := b.httpClient.Do(req)
5759
if err != nil {
58-
return 0, fmt.Errorf("SQL request failed: %w", err)
60+
return SQLResult{}, fmt.Errorf("SQL request failed: %w", err)
5961
}
6062
defer resp.Body.Close()
6163

6264
var result SQLResponse
6365
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
64-
return 0, fmt.Errorf("failed to decode SQL response: %w", err)
66+
return SQLResult{}, fmt.Errorf("failed to decode SQL response: %w", err)
6567
}
6668

67-
return result.Total, nil
69+
// Convertir a tu tipo interno
70+
return SQLResult{
71+
Rows: result.DataRows,
72+
Count: result.Total,
73+
}, nil
6874
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package client
2+
3+
type SQLResult struct {
4+
Rows [][]any
5+
Count int
6+
}

0 commit comments

Comments
 (0)