From c511374c953a69cc6c97ca9bad8b12fd82cd035c Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Tue, 13 Jan 2026 21:29:40 -0600 Subject: [PATCH 001/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../UtmComplianceControlConfig.java | 46 +++++++++++++++ .../UtmComplianceControlQueryConfig.java | 44 ++++++++++++++ .../compliance/enums/ComplianceStrategy.java | 7 +++ .../compliance/enums/EvaluationRule.java | 8 +++ .../UtmComplianceControlConfigRepository.java | 14 +++++ ...omplianceControlQueryConfigRepository.java | 15 +++++ .../UtmComplianceControlConfigService.java | 18 ++++++ ...tmComplianceControlQueryConfigService.java | 15 +++++ .../UtmComplianceControlConfigRequestDto.java | 12 ++++ ...UtmComplianceControlConfigResponseDto.java | 13 +++++ ...omplianceControlQueryConfigRequestDto.java | 12 ++++ ...mplianceControlQueryConfigResponseDto.java | 12 ++++ ...UtmComplianceControlConfigServiceImpl.java | 44 ++++++++++++++ ...mplianceControlQueryConfigServiceImpl.java | 34 +++++++++++ .../UtmComplianceControlConfigMapper.java | 16 +++++ ...UtmComplianceControlQueryConfigMapper.java | 16 +++++ .../UtmComplianceControlConfigResource.java | 58 +++++++++++++++++++ ...omplianceControlQueryConfigController.java | 29 ++++++++++ ...create_table_compliance_control_config.xml | 50 ++++++++++++++++ ..._table_compliance_control_query_config.xml | 48 +++++++++++++++ .../resources/config/liquibase/master.xml | 3 + 21 files changed, 514 insertions(+) create mode 100644 backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java create mode 100644 backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlQueryConfig.java create mode 100644 backend/src/main/java/com/park/utmstack/domain/compliance/enums/ComplianceStrategy.java create mode 100644 backend/src/main/java/com/park/utmstack/domain/compliance/enums/EvaluationRule.java create mode 100644 backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java create mode 100644 backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlQueryConfigRepository.java create mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java create mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlQueryConfigService.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigRequestDto.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigResponseDto.java create mode 100644 backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlConfigServiceImpl.java create mode 100644 backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlQueryConfigServiceImpl.java create mode 100644 backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java create mode 100644 backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlQueryConfigMapper.java create mode 100644 backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java create mode 100644 backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java create mode 100644 backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml create mode 100644 backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_query_config.xml diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java new file mode 100644 index 000000000..bc9d11222 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java @@ -0,0 +1,46 @@ +package com.park.utmstack.domain.compliance; + +import com.park.utmstack.domain.compliance.enums.ComplianceStrategy; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.*; +import java.io.Serializable; +import java.util.List; + +@Getter +@Setter +@Entity +@Table(name = "utm_compliance_control_config") +public class UtmComplianceControlConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GenericGenerator(name = "CustomIdentityGenerator", + strategy = "com.park.utmstack.util.CustomIdentityGenerator") + @GeneratedValue(generator = "CustomIdentityGenerator") + private Long id; + + @ManyToOne + @JoinColumn(name = "standard_section_id", referencedColumnName = "id", insertable = false, updatable = false) + private UtmComplianceStandardSection section; + + @Column(name = "control_name", length = 50) + private String controlName; + + @Column(name = "control_solution") + private String controlSolution; + + @Column(name = "control_remediation") + private String controlRemediation; + + @Enumerated(EnumType.STRING) + @Column(name = "control_strategy") + private ComplianceStrategy controlStrategy; + + @OneToMany(cascade = CascadeType.ALL) + @JoinColumn(name = "control_config_id") + private List queriesConfigs; +} diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlQueryConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlQueryConfig.java new file mode 100644 index 000000000..b6398255a --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlQueryConfig.java @@ -0,0 +1,44 @@ +package com.park.utmstack.domain.compliance; + +import com.park.utmstack.domain.compliance.enums.EvaluationRule; +import com.park.utmstack.domain.index_pattern.UtmIndexPattern; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.*; +import java.io.Serializable; + +@Getter +@Setter +@Entity +@Table(name = "utm_compliance_control_query_config") +public class UtmComplianceControlQueryConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GenericGenerator( + name = "CustomIdentityGenerator", + strategy = "com.park.utmstack.util.CustomIdentityGenerator" + ) + @GeneratedValue(generator = "CustomIdentityGenerator") + private Long id; + + @Column(name = "query_description", columnDefinition = "TEXT") + private String queryDescription; + + @Column(name = "sql_query", columnDefinition = "TEXT") + private String sqlQuery; + + @Enumerated(EnumType.STRING) + @Column(name = "evaluation_rule") + private EvaluationRule evaluationRule; + + @ManyToOne + @JoinColumn(name = "index_pattern_id", referencedColumnName = "id") + private UtmIndexPattern indexPattern; + + @Column(name = "control_config_id") + private Long controlConfigId; +} diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/enums/ComplianceStrategy.java b/backend/src/main/java/com/park/utmstack/domain/compliance/enums/ComplianceStrategy.java new file mode 100644 index 000000000..ff0a6a967 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/enums/ComplianceStrategy.java @@ -0,0 +1,7 @@ +package com.park.utmstack.domain.compliance.enums; + +public enum ComplianceStrategy { + ALL, + ANY, + MAJORITY +} diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/enums/EvaluationRule.java b/backend/src/main/java/com/park/utmstack/domain/compliance/enums/EvaluationRule.java new file mode 100644 index 000000000..f60138409 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/enums/EvaluationRule.java @@ -0,0 +1,8 @@ +package com.park.utmstack.domain.compliance.enums; + +public enum EvaluationRule { + NO_HITS_ALLOWED, + MIN_HITS_REQUIRED, + THRESHOLD_MAX, + MATCH_FIELD_VALUE +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java new file mode 100644 index 000000000..bb512ed19 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java @@ -0,0 +1,14 @@ +package com.park.utmstack.repository.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface UtmComplianceControlConfigRepository extends JpaRepository { + + List findBySectionId(Long sectionId); + +} diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlQueryConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlQueryConfigRepository.java new file mode 100644 index 000000000..ce35a6ff3 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlQueryConfigRepository.java @@ -0,0 +1,15 @@ +package com.park.utmstack.repository.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceControlQueryConfig; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface UtmComplianceControlQueryConfigRepository extends JpaRepository { + + List findByControlConfigId(Long controlConfigId); + +} + diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java new file mode 100644 index 000000000..1c38b310b --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -0,0 +1,18 @@ +package com.park.utmstack.service.compliance.config; + +import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; + +import java.util.List; + +public interface UtmComplianceControlConfigService { + + UtmComplianceControlConfig create(UtmComplianceControlConfig config); + + UtmComplianceControlConfig update(Long id, UtmComplianceControlConfig config); + + void delete(Long id); + + UtmComplianceControlConfig findById(Long id); + + List findAll(); +} diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlQueryConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlQueryConfigService.java new file mode 100644 index 000000000..3dcd5560a --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlQueryConfigService.java @@ -0,0 +1,15 @@ +package com.park.utmstack.service.compliance.config; + +import com.park.utmstack.domain.compliance.UtmComplianceControlQueryConfig; + +import java.util.List; + +public interface UtmComplianceControlQueryConfigService { + + UtmComplianceControlQueryConfig create(UtmComplianceControlQueryConfig config); + + List findByReportConfig(Long reportConfigId); + + void delete(Long id); +} + diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java new file mode 100644 index 000000000..4bf42a100 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java @@ -0,0 +1,12 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Data; + +@Data +public class UtmComplianceControlConfigRequestDto { + private Long standardSectionId; + private String controlName; + private String controlSolution; + private String controlRemediation; + private String controlStrategy; +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java new file mode 100644 index 000000000..878cade26 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java @@ -0,0 +1,13 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Data; + +@Data +public class UtmComplianceControlConfigResponseDto { + private Long id; + private Long standardSectionId; + private String controlName; + private String controlSolution; + private String controlRemediation; + private String controlStrategy; +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigRequestDto.java new file mode 100644 index 000000000..1e5d29448 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigRequestDto.java @@ -0,0 +1,12 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Data; + +@Data +public class UtmComplianceControlQueryConfigRequestDto { + private String queryDescription; + private String sqlQuery; + private String evaluationRule; + private Long indexPatternId; + private Long reportConfigId; +} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigResponseDto.java new file mode 100644 index 000000000..364a71bc4 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigResponseDto.java @@ -0,0 +1,12 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Data; + +@Data +public class UtmComplianceControlQueryConfigResponseDto { + private String queryDescription; + private String sqlQuery; + private String evaluationRule; + private Long indexPatternId; + private Long reportConfigId; +} diff --git a/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlConfigServiceImpl.java b/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlConfigServiceImpl.java new file mode 100644 index 000000000..3bb80bf15 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlConfigServiceImpl.java @@ -0,0 +1,44 @@ +package com.park.utmstack.service.impl.compliance.config; + +import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; +import com.park.utmstack.repository.compliance.UtmComplianceControlConfigRepository; +import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UtmComplianceControlConfigServiceImpl implements UtmComplianceControlConfigService { + + private final UtmComplianceControlConfigRepository repository; + + public UtmComplianceControlConfigServiceImpl(UtmComplianceControlConfigRepository repository) { + this.repository = repository; + } + + @Override + public UtmComplianceControlConfig create(UtmComplianceControlConfig config) { + return repository.save(config); + } + + @Override + public UtmComplianceControlConfig update(Long id, UtmComplianceControlConfig config) { + config.setId(id); + return repository.save(config); + } + + @Override + public void delete(Long id) { + repository.deleteById(id); + } + + @Override + public UtmComplianceControlConfig findById(Long id) { + return repository.findById(id).orElse(null); + } + + @Override + public List findAll() { + return repository.findAll(); + } +} diff --git a/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlQueryConfigServiceImpl.java b/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlQueryConfigServiceImpl.java new file mode 100644 index 000000000..91cfcbd2a --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlQueryConfigServiceImpl.java @@ -0,0 +1,34 @@ +package com.park.utmstack.service.impl.compliance.config; + +import com.park.utmstack.domain.compliance.UtmComplianceControlQueryConfig; +import com.park.utmstack.repository.compliance.UtmComplianceControlQueryConfigRepository; +import com.park.utmstack.service.compliance.config.UtmComplianceControlQueryConfigService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UtmComplianceControlQueryConfigServiceImpl implements UtmComplianceControlQueryConfigService { + + private final UtmComplianceControlQueryConfigRepository repository; + + public UtmComplianceControlQueryConfigServiceImpl(UtmComplianceControlQueryConfigRepository repository) { + this.repository = repository; + } + + @Override + public UtmComplianceControlQueryConfig create(UtmComplianceControlQueryConfig config) { + return repository.save(config); + } + + @Override + public List findByReportConfig(Long reportConfigId) { + return repository.findByControlConfigId(reportConfigId); + } + + @Override + public void delete(Long id) { + repository.deleteById(id); + } +} + diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java new file mode 100644 index 000000000..a87816027 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java @@ -0,0 +1,16 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; + +@Mapper(componentModel = "spring") +public interface UtmComplianceControlConfigMapper { + UtmComplianceControlConfig toEntity(UtmComplianceControlConfigRequestDto dto); + + UtmComplianceControlConfigResponseDto toResponse(UtmComplianceControlConfig entity); + + void updateEntity(@MappingTarget UtmComplianceControlConfig entity, UtmComplianceControlConfigRequestDto dto); +} diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlQueryConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlQueryConfigMapper.java new file mode 100644 index 000000000..b69f6696a --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlQueryConfigMapper.java @@ -0,0 +1,16 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceControlQueryConfig; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlQueryConfigRequestDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlQueryConfigResponseDto; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; + +@Mapper(componentModel = "spring") +public interface UtmComplianceControlQueryConfigMapper { + UtmComplianceControlQueryConfig toEntity(UtmComplianceControlQueryConfigRequestDto dto); + + UtmComplianceControlQueryConfigResponseDto toResponse(UtmComplianceControlQueryConfig entity); + + void updateEntity(@MappingTarget UtmComplianceControlQueryConfig entity, UtmComplianceControlQueryConfigRequestDto dto); +} diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java new file mode 100644 index 000000000..9c1a2550b --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -0,0 +1,58 @@ +package com.park.utmstack.web.rest.compliance.config; + +import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/compliance/control") +public class UtmComplianceControlConfigResource { + + private final UtmComplianceControlConfigService service; + private final UtmComplianceControlConfigMapper mapper; + + public UtmComplianceControlConfigResource( + UtmComplianceControlConfigService service, + UtmComplianceControlConfigMapper mapper + ) { + this.service = service; + this.mapper = mapper; + } + + @PostMapping + public ResponseEntity create(@RequestBody UtmComplianceControlConfigRequestDto dto) { + var entity = mapper.toEntity(dto); + var saved = service.create(entity); + return ResponseEntity.ok(mapper.toResponse(saved)); + } + + @GetMapping("/{id}") + public ResponseEntity getById(@PathVariable Long id) { + var entity = service.findById(id); + if (entity == null) return ResponseEntity.notFound().build(); + return ResponseEntity.ok(mapper.toResponse(entity)); + } + + @PutMapping("/{id}") + public ResponseEntity update( + @PathVariable Long id, + @RequestBody UtmComplianceControlConfigRequestDto dto + ) { + var existing = service.findById(id); + if (existing == null) return ResponseEntity.notFound().build(); + + mapper.updateEntity(existing, dto); + var updated = service.update(id, existing); + + return ResponseEntity.ok(mapper.toResponse(updated)); + } + + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + service.delete(id); + return ResponseEntity.noContent().build(); + } +} diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java new file mode 100644 index 000000000..ebfa82fd8 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java @@ -0,0 +1,29 @@ +package com.park.utmstack.web.rest.compliance.config; + +import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlQueryConfigMapper; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + + +@RestController +@RequestMapping("/api/compliance/query") +public class UtmComplianceControlQueryConfigController { + + private final UtmComplianceControlConfigService service; + private final UtmComplianceControlQueryConfigMapper mapper; + + public UtmComplianceControlQueryConfigController( + UtmComplianceControlConfigService service, + UtmComplianceControlQueryConfigMapper mapper + ) { + this.service = service; + this.mapper = mapper; + } + + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + service.delete(id); + return ResponseEntity.noContent().build(); + } +} diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml new file mode 100644 index 000000000..6baace35d --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_query_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_query_config.xml new file mode 100644 index 000000000..6119c46fe --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_query_config.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/master.xml b/backend/src/main/resources/config/liquibase/master.xml index dfefaf11b..0d4d1b253 100644 --- a/backend/src/main/resources/config/liquibase/master.xml +++ b/backend/src/main/resources/config/liquibase/master.xml @@ -299,5 +299,8 @@ + + + From 6f53a4fd5723772dc73130d5185c476f34ed3674 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 14 Jan 2026 19:46:02 -0600 Subject: [PATCH 002/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../UtmComplianceControlConfig.java | 2 +- ...fig.java => UtmComplianceQueryConfig.java} | 4 +- ...omplianceControlQueryConfigRepository.java | 15 ------- .../UtmComplianceQueryConfigRepository.java | 15 +++++++ .../UtmComplianceControlConfigService.java | 42 +++++++++++++----- ...tmComplianceControlQueryConfigService.java | 15 ------- .../UtmComplianceQueryConfigService.java | 30 +++++++++++++ ...> UtmComplianceQueryConfigRequestDto.java} | 2 +- ... UtmComplianceQueryConfigResponseDto.java} | 2 +- ...UtmComplianceControlConfigServiceImpl.java | 44 ------------------- ...mplianceControlQueryConfigServiceImpl.java | 34 -------------- ...UtmComplianceControlQueryConfigMapper.java | 16 ------- .../UtmComplianceQueryConfigMapper.java | 16 +++++++ .../UtmComplianceControlConfigResource.java | 1 - ...omplianceControlQueryConfigController.java | 7 ++- ..._create_table_compliance_query_config.xml} | 2 +- .../resources/config/liquibase/master.xml | 2 +- 17 files changed, 102 insertions(+), 147 deletions(-) rename backend/src/main/java/com/park/utmstack/domain/compliance/{UtmComplianceControlQueryConfig.java => UtmComplianceQueryConfig.java} (90%) delete mode 100644 backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlQueryConfigRepository.java create mode 100644 backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java delete mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlQueryConfigService.java create mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java rename backend/src/main/java/com/park/utmstack/service/dto/compliance/{UtmComplianceControlQueryConfigRequestDto.java => UtmComplianceQueryConfigRequestDto.java} (81%) rename backend/src/main/java/com/park/utmstack/service/dto/compliance/{UtmComplianceControlQueryConfigResponseDto.java => UtmComplianceQueryConfigResponseDto.java} (80%) delete mode 100644 backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlConfigServiceImpl.java delete mode 100644 backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlQueryConfigServiceImpl.java delete mode 100644 backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlQueryConfigMapper.java create mode 100644 backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java rename backend/src/main/resources/config/liquibase/changelog/{20260112002_create_table_compliance_control_query_config.xml => 20260112002_create_table_compliance_query_config.xml} (96%) diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java index bc9d11222..26bada910 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java @@ -42,5 +42,5 @@ public class UtmComplianceControlConfig implements Serializable { @OneToMany(cascade = CascadeType.ALL) @JoinColumn(name = "control_config_id") - private List queriesConfigs; + private List queriesConfigs; } diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlQueryConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java similarity index 90% rename from backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlQueryConfig.java rename to backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java index b6398255a..ab315d683 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlQueryConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java @@ -12,8 +12,8 @@ @Getter @Setter @Entity -@Table(name = "utm_compliance_control_query_config") -public class UtmComplianceControlQueryConfig implements Serializable { +@Table(name = "utm_compliance_query_config") +public class UtmComplianceQueryConfig implements Serializable { private static final long serialVersionUID = 1L; diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlQueryConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlQueryConfigRepository.java deleted file mode 100644 index ce35a6ff3..000000000 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlQueryConfigRepository.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.park.utmstack.repository.compliance; - -import com.park.utmstack.domain.compliance.UtmComplianceControlQueryConfig; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface UtmComplianceControlQueryConfigRepository extends JpaRepository { - - List findByControlConfigId(Long controlConfigId); - -} - diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java new file mode 100644 index 000000000..58a4100cc --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java @@ -0,0 +1,15 @@ +package com.park.utmstack.repository.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface UtmComplianceQueryConfigRepository extends JpaRepository { + + List findByControlConfigId(Long controlConfigId); + +} + diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 1c38b310b..80ab71182 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -1,18 +1,38 @@ package com.park.utmstack.service.compliance.config; import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; +import com.park.utmstack.repository.compliance.UtmComplianceControlConfigRepository; +import org.springframework.stereotype.Service; import java.util.List; -public interface UtmComplianceControlConfigService { - - UtmComplianceControlConfig create(UtmComplianceControlConfig config); - - UtmComplianceControlConfig update(Long id, UtmComplianceControlConfig config); - - void delete(Long id); - - UtmComplianceControlConfig findById(Long id); - - List findAll(); +@Service +public class UtmComplianceControlConfigService { + + private final UtmComplianceControlConfigRepository repository; + + public UtmComplianceControlConfigService(UtmComplianceControlConfigRepository repository) { + this.repository = repository; + } + + public UtmComplianceControlConfig create(UtmComplianceControlConfig config) { + return repository.save(config); + } + + public UtmComplianceControlConfig update(Long id, UtmComplianceControlConfig config) { + config.setId(id); + return repository.save(config); + } + + public void delete(Long id) { + repository.deleteById(id); + } + + public UtmComplianceControlConfig findById(Long id) { + return repository.findById(id).orElse(null); + } + + public List findAll() { + return repository.findAll(); + } } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlQueryConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlQueryConfigService.java deleted file mode 100644 index 3dcd5560a..000000000 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlQueryConfigService.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.park.utmstack.service.compliance.config; - -import com.park.utmstack.domain.compliance.UtmComplianceControlQueryConfig; - -import java.util.List; - -public interface UtmComplianceControlQueryConfigService { - - UtmComplianceControlQueryConfig create(UtmComplianceControlQueryConfig config); - - List findByReportConfig(Long reportConfigId); - - void delete(Long id); -} - diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java new file mode 100644 index 000000000..739ae4fe3 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java @@ -0,0 +1,30 @@ +package com.park.utmstack.service.compliance.config; + +import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; +import com.park.utmstack.repository.compliance.UtmComplianceQueryConfigRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UtmComplianceQueryConfigService { + + private final UtmComplianceQueryConfigRepository repository; + + public UtmComplianceQueryConfigService(UtmComplianceQueryConfigRepository repository) { + this.repository = repository; + } + + public UtmComplianceQueryConfig create(UtmComplianceQueryConfig config) { + return repository.save(config); + } + + public List findByReportConfig(Long reportConfigId) { + return repository.findByControlConfigId(reportConfigId); + } + + public void delete(Long id) { + repository.deleteById(id); + } +} + diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java similarity index 81% rename from backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigRequestDto.java rename to backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java index 1e5d29448..527a55cd7 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigRequestDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java @@ -3,7 +3,7 @@ import lombok.Data; @Data -public class UtmComplianceControlQueryConfigRequestDto { +public class UtmComplianceQueryConfigRequestDto { private String queryDescription; private String sqlQuery; private String evaluationRule; diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java similarity index 80% rename from backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigResponseDto.java rename to backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java index 364a71bc4..d1e20d992 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlQueryConfigResponseDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java @@ -3,7 +3,7 @@ import lombok.Data; @Data -public class UtmComplianceControlQueryConfigResponseDto { +public class UtmComplianceQueryConfigResponseDto { private String queryDescription; private String sqlQuery; private String evaluationRule; diff --git a/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlConfigServiceImpl.java b/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlConfigServiceImpl.java deleted file mode 100644 index 3bb80bf15..000000000 --- a/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlConfigServiceImpl.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.park.utmstack.service.impl.compliance.config; - -import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; -import com.park.utmstack.repository.compliance.UtmComplianceControlConfigRepository; -import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class UtmComplianceControlConfigServiceImpl implements UtmComplianceControlConfigService { - - private final UtmComplianceControlConfigRepository repository; - - public UtmComplianceControlConfigServiceImpl(UtmComplianceControlConfigRepository repository) { - this.repository = repository; - } - - @Override - public UtmComplianceControlConfig create(UtmComplianceControlConfig config) { - return repository.save(config); - } - - @Override - public UtmComplianceControlConfig update(Long id, UtmComplianceControlConfig config) { - config.setId(id); - return repository.save(config); - } - - @Override - public void delete(Long id) { - repository.deleteById(id); - } - - @Override - public UtmComplianceControlConfig findById(Long id) { - return repository.findById(id).orElse(null); - } - - @Override - public List findAll() { - return repository.findAll(); - } -} diff --git a/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlQueryConfigServiceImpl.java b/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlQueryConfigServiceImpl.java deleted file mode 100644 index 91cfcbd2a..000000000 --- a/backend/src/main/java/com/park/utmstack/service/impl/compliance/config/UtmComplianceControlQueryConfigServiceImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.park.utmstack.service.impl.compliance.config; - -import com.park.utmstack.domain.compliance.UtmComplianceControlQueryConfig; -import com.park.utmstack.repository.compliance.UtmComplianceControlQueryConfigRepository; -import com.park.utmstack.service.compliance.config.UtmComplianceControlQueryConfigService; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class UtmComplianceControlQueryConfigServiceImpl implements UtmComplianceControlQueryConfigService { - - private final UtmComplianceControlQueryConfigRepository repository; - - public UtmComplianceControlQueryConfigServiceImpl(UtmComplianceControlQueryConfigRepository repository) { - this.repository = repository; - } - - @Override - public UtmComplianceControlQueryConfig create(UtmComplianceControlQueryConfig config) { - return repository.save(config); - } - - @Override - public List findByReportConfig(Long reportConfigId) { - return repository.findByControlConfigId(reportConfigId); - } - - @Override - public void delete(Long id) { - repository.deleteById(id); - } -} - diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlQueryConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlQueryConfigMapper.java deleted file mode 100644 index b69f6696a..000000000 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlQueryConfigMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.park.utmstack.service.mapper.compliance; - -import com.park.utmstack.domain.compliance.UtmComplianceControlQueryConfig; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlQueryConfigRequestDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlQueryConfigResponseDto; -import org.mapstruct.Mapper; -import org.mapstruct.MappingTarget; - -@Mapper(componentModel = "spring") -public interface UtmComplianceControlQueryConfigMapper { - UtmComplianceControlQueryConfig toEntity(UtmComplianceControlQueryConfigRequestDto dto); - - UtmComplianceControlQueryConfigResponseDto toResponse(UtmComplianceControlQueryConfig entity); - - void updateEntity(@MappingTarget UtmComplianceControlQueryConfig entity, UtmComplianceControlQueryConfigRequestDto dto); -} diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java new file mode 100644 index 000000000..697d21c74 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java @@ -0,0 +1,16 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; +import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigRequestDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigResponseDto; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; + +@Mapper(componentModel = "spring") +public interface UtmComplianceQueryConfigMapper { + UtmComplianceQueryConfig toEntity(UtmComplianceQueryConfigRequestDto dto); + + UtmComplianceQueryConfigResponseDto toResponse(UtmComplianceQueryConfig entity); + + void updateEntity(@MappingTarget UtmComplianceQueryConfig entity, UtmComplianceQueryConfigRequestDto dto); +} diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java index 9c1a2550b..4516c117c 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -1,6 +1,5 @@ package com.park.utmstack.web.rest.compliance.config; -import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java index ebfa82fd8..2c3159451 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java @@ -1,7 +1,6 @@ package com.park.utmstack.web.rest.compliance.config; -import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; -import com.park.utmstack.service.mapper.compliance.UtmComplianceControlQueryConfigMapper; +import com.park.utmstack.service.mapper.compliance.UtmComplianceQueryConfigMapper; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -11,11 +10,11 @@ public class UtmComplianceControlQueryConfigController { private final UtmComplianceControlConfigService service; - private final UtmComplianceControlQueryConfigMapper mapper; + private final UtmComplianceQueryConfigMapper mapper; public UtmComplianceControlQueryConfigController( UtmComplianceControlConfigService service, - UtmComplianceControlQueryConfigMapper mapper + UtmComplianceQueryConfigMapper mapper ) { this.service = service; this.mapper = mapper; diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_query_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml similarity index 96% rename from backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_query_config.xml rename to backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml index 6119c46fe..6a15cf231 100644 --- a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_query_config.xml +++ b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml @@ -5,7 +5,7 @@ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"> - + diff --git a/backend/src/main/resources/config/liquibase/master.xml b/backend/src/main/resources/config/liquibase/master.xml index 0d4d1b253..dbe0a3f7a 100644 --- a/backend/src/main/resources/config/liquibase/master.xml +++ b/backend/src/main/resources/config/liquibase/master.xml @@ -301,6 +301,6 @@ - + From 09af2ef50df357c74ea4834d98dd7b3203863a9c Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 14 Jan 2026 20:41:00 -0600 Subject: [PATCH 003/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../UtmComplianceControlConfigRepository.java | 2 - .../UtmComplianceQueryConfigRepository.java | 2 - .../UtmComplianceQueryConfigService.java | 4 - ...UtmComplianceControlConfigResponseDto.java | 1 - .../UtmComplianceQueryConfigRequestDto.java | 2 +- .../UtmComplianceQueryConfigResponseDto.java | 2 +- .../UtmComplianceControlConfigMapper.java | 7 +- .../UtmComplianceQueryConfigMapper.java | 5 +- .../UtmComplianceControlConfigResource.java | 73 ++++++++++++++----- ...omplianceControlQueryConfigController.java | 28 ------- 10 files changed, 64 insertions(+), 62 deletions(-) delete mode 100644 backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java index bb512ed19..b48ae1831 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java @@ -9,6 +9,4 @@ @Repository public interface UtmComplianceControlConfigRepository extends JpaRepository { - List findBySectionId(Long sectionId); - } diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java index 58a4100cc..238fcc2b9 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java @@ -9,7 +9,5 @@ @Repository public interface UtmComplianceQueryConfigRepository extends JpaRepository { - List findByControlConfigId(Long controlConfigId); - } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java index 739ae4fe3..d14aa974c 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java @@ -19,10 +19,6 @@ public UtmComplianceQueryConfig create(UtmComplianceQueryConfig config) { return repository.save(config); } - public List findByReportConfig(Long reportConfigId) { - return repository.findByControlConfigId(reportConfigId); - } - public void delete(Long id) { repository.deleteById(id); } diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java index 878cade26..5f44235f7 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java @@ -4,7 +4,6 @@ @Data public class UtmComplianceControlConfigResponseDto { - private Long id; private Long standardSectionId; private String controlName; private String controlSolution; diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java index 527a55cd7..871a9c9fd 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java @@ -8,5 +8,5 @@ public class UtmComplianceQueryConfigRequestDto { private String sqlQuery; private String evaluationRule; private Long indexPatternId; - private Long reportConfigId; + private Long controlConfigId; } diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java index d1e20d992..d30f659eb 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java @@ -8,5 +8,5 @@ public class UtmComplianceQueryConfigResponseDto { private String sqlQuery; private String evaluationRule; private Long indexPatternId; - private Long reportConfigId; + private Long controlConfigId; } diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java index a87816027..1ed107806 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java @@ -12,5 +12,8 @@ public interface UtmComplianceControlConfigMapper { UtmComplianceControlConfigResponseDto toResponse(UtmComplianceControlConfig entity); - void updateEntity(@MappingTarget UtmComplianceControlConfig entity, UtmComplianceControlConfigRequestDto dto); -} + void updateEntity( + @MappingTarget UtmComplianceControlConfig entity, + UtmComplianceControlConfigRequestDto dto + ); +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java index 697d21c74..2d70d3887 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java @@ -12,5 +12,8 @@ public interface UtmComplianceQueryConfigMapper { UtmComplianceQueryConfigResponseDto toResponse(UtmComplianceQueryConfig entity); - void updateEntity(@MappingTarget UtmComplianceQueryConfig entity, UtmComplianceQueryConfigRequestDto dto); + void updateEntity( + @MappingTarget UtmComplianceQueryConfig entity, + UtmComplianceQueryConfigRequestDto dto + ); } diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java index 4516c117c..caa6d5206 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -1,8 +1,13 @@ package com.park.utmstack.web.rest.compliance.config; +import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; +import com.park.utmstack.service.compliance.config.UtmComplianceQueryConfigService; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigRequestDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigResponseDto; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; +import com.park.utmstack.service.mapper.compliance.UtmComplianceQueryConfigMapper; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -10,48 +15,76 @@ @RequestMapping("/api/compliance/control") public class UtmComplianceControlConfigResource { - private final UtmComplianceControlConfigService service; - private final UtmComplianceControlConfigMapper mapper; + private final UtmComplianceControlConfigService controlService; + private final UtmComplianceQueryConfigService queryService; + private final UtmComplianceControlConfigMapper controlMapper; + private final UtmComplianceQueryConfigMapper queryMapper; public UtmComplianceControlConfigResource( - UtmComplianceControlConfigService service, - UtmComplianceControlConfigMapper mapper + UtmComplianceControlConfigService controlService, + UtmComplianceQueryConfigService queryService, + UtmComplianceControlConfigMapper controlMapper, + UtmComplianceQueryConfigMapper queryMapper ) { - this.service = service; - this.mapper = mapper; + this.controlService = controlService; + this.queryService = queryService; + this.controlMapper = controlMapper; + this.queryMapper = queryMapper; } @PostMapping - public ResponseEntity create(@RequestBody UtmComplianceControlConfigRequestDto dto) { - var entity = mapper.toEntity(dto); - var saved = service.create(entity); - return ResponseEntity.ok(mapper.toResponse(saved)); + public ResponseEntity createControl( + @RequestBody UtmComplianceControlConfigRequestDto dto + ) { + var entity = controlMapper.toEntity(dto); + var saved = controlService.create(entity); + return ResponseEntity.ok(controlMapper.toResponse(saved)); } @GetMapping("/{id}") - public ResponseEntity getById(@PathVariable Long id) { - var entity = service.findById(id); + public ResponseEntity getControl(@PathVariable Long id) { + var entity = controlService.findById(id); if (entity == null) return ResponseEntity.notFound().build(); - return ResponseEntity.ok(mapper.toResponse(entity)); + return ResponseEntity.ok(controlMapper.toResponse(entity)); } @PutMapping("/{id}") - public ResponseEntity update( + public ResponseEntity updateControl( @PathVariable Long id, @RequestBody UtmComplianceControlConfigRequestDto dto ) { - var existing = service.findById(id); + var existing = controlService.findById(id); if (existing == null) return ResponseEntity.notFound().build(); - mapper.updateEntity(existing, dto); - var updated = service.update(id, existing); + controlMapper.updateEntity(existing, dto); + var updated = controlService.update(id, existing); - return ResponseEntity.ok(mapper.toResponse(updated)); + return ResponseEntity.ok(controlMapper.toResponse(updated)); } @DeleteMapping("/{id}") - public ResponseEntity delete(@PathVariable Long id) { - service.delete(id); + public ResponseEntity deleteControl(@PathVariable Long id) { + controlService.delete(id); + return ResponseEntity.noContent().build(); + } + + @PostMapping("/{controlId}/query") + public ResponseEntity addQuery( + @PathVariable Long controlId, + @RequestBody UtmComplianceQueryConfigRequestDto dto + ) { + dto.setControlConfigId(controlId); + + var entity = queryMapper.toEntity(dto); + var saved = queryService.create(entity); + + return ResponseEntity.ok(queryMapper.toResponse(saved)); + } + + @DeleteMapping("/query/{queryId}") + public ResponseEntity deleteQuery(@PathVariable Long queryId) { + queryService.delete(queryId); return ResponseEntity.noContent().build(); } } + diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java deleted file mode 100644 index 2c3159451..000000000 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlQueryConfigController.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.park.utmstack.web.rest.compliance.config; - -import com.park.utmstack.service.mapper.compliance.UtmComplianceQueryConfigMapper; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - - -@RestController -@RequestMapping("/api/compliance/query") -public class UtmComplianceControlQueryConfigController { - - private final UtmComplianceControlConfigService service; - private final UtmComplianceQueryConfigMapper mapper; - - public UtmComplianceControlQueryConfigController( - UtmComplianceControlConfigService service, - UtmComplianceQueryConfigMapper mapper - ) { - this.service = service; - this.mapper = mapper; - } - - @DeleteMapping("/{id}") - public ResponseEntity delete(@PathVariable Long id) { - service.delete(id); - return ResponseEntity.noContent().build(); - } -} From a8e8522387e734810b8767285969351cdbb39e57 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 16 Jan 2026 13:55:42 -0600 Subject: [PATCH 004/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../domain/compliance/UtmComplianceControlConfig.java | 5 ++++- .../domain/compliance/UtmComplianceQueryConfig.java | 6 +++++- .../UtmComplianceQueryConfigRepository.java | 1 + .../config/UtmComplianceQueryConfigService.java | 6 +++++- .../UtmComplianceControlConfigRequestDto.java | 6 +++++- .../UtmComplianceControlConfigResponseDto.java | 10 ++++++++-- .../UtmComplianceQueryConfigRequestDto.java | 3 ++- .../UtmComplianceQueryConfigResponseDto.java | 4 +++- .../compliance/UtmComplianceControlConfigMapper.java | 6 +++++- .../compliance/UtmComplianceQueryConfigMapper.java | 11 ++++------- ...260112002_create_table_compliance_query_config.xml | 6 +++--- 11 files changed, 45 insertions(+), 19 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java index 26bada910..e516867e1 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java @@ -23,8 +23,11 @@ public class UtmComplianceControlConfig implements Serializable { @GeneratedValue(generator = "CustomIdentityGenerator") private Long id; + @Column(name = "standard_section_id") + private Long standardSectionId; + @ManyToOne - @JoinColumn(name = "standard_section_id", referencedColumnName = "id", insertable = false, updatable = false) + @JoinColumn(name = "standard_section_id", insertable = false, updatable = false) private UtmComplianceStandardSection section; @Column(name = "control_name", length = 50) diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java index ab315d683..37da56174 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java @@ -35,10 +35,14 @@ public class UtmComplianceQueryConfig implements Serializable { @Column(name = "evaluation_rule") private EvaluationRule evaluationRule; + @Column(name = "index_pattern_id") + private Long indexPatternId; + @ManyToOne - @JoinColumn(name = "index_pattern_id", referencedColumnName = "id") + @JoinColumn(name = "index_pattern_id", insertable = false, updatable = false) private UtmIndexPattern indexPattern; + @Column(name = "control_config_id") private Long controlConfigId; } diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java index 238fcc2b9..e583464c7 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java @@ -9,5 +9,6 @@ @Repository public interface UtmComplianceQueryConfigRepository extends JpaRepository { + List findByControlConfigId(Long controlConfigId); } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java index d14aa974c..199fa07d8 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java @@ -22,5 +22,9 @@ public UtmComplianceQueryConfig create(UtmComplianceQueryConfig config) { public void delete(Long id) { repository.deleteById(id); } -} + public List findByControlConfigId(Long controlId) { + return repository.findByControlConfigId((controlId)); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java index 4bf42a100..16a751b2f 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java @@ -1,12 +1,16 @@ package com.park.utmstack.service.dto.compliance; +import com.park.utmstack.domain.compliance.enums.ComplianceStrategy; import lombok.Data; +import java.util.List; + @Data public class UtmComplianceControlConfigRequestDto { private Long standardSectionId; private String controlName; private String controlSolution; private String controlRemediation; - private String controlStrategy; + private ComplianceStrategy controlStrategy; + private List queriesConfigs; } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java index 5f44235f7..22644e176 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java @@ -1,12 +1,18 @@ package com.park.utmstack.service.dto.compliance; +import com.park.utmstack.domain.compliance.enums.ComplianceStrategy; import lombok.Data; +import java.util.List; + @Data public class UtmComplianceControlConfigResponseDto { + private Long id; private Long standardSectionId; private String controlName; private String controlSolution; private String controlRemediation; - private String controlStrategy; -} \ No newline at end of file + private ComplianceStrategy controlStrategy; + + private List queriesConfigs; +} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java index 871a9c9fd..84d32d510 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java @@ -1,12 +1,13 @@ package com.park.utmstack.service.dto.compliance; +import com.park.utmstack.domain.compliance.enums.EvaluationRule; import lombok.Data; @Data public class UtmComplianceQueryConfigRequestDto { private String queryDescription; private String sqlQuery; - private String evaluationRule; + private EvaluationRule evaluationRule; private Long indexPatternId; private Long controlConfigId; } diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java index d30f659eb..2bc1bbd40 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java @@ -1,12 +1,14 @@ package com.park.utmstack.service.dto.compliance; +import com.park.utmstack.domain.compliance.enums.EvaluationRule; import lombok.Data; @Data public class UtmComplianceQueryConfigResponseDto { + private Long id; private String queryDescription; private String sqlQuery; - private String evaluationRule; + private EvaluationRule evaluationRule; private Long indexPatternId; private Long controlConfigId; } diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java index 1ed107806..50183fdad 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java @@ -4,14 +4,18 @@ import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; -@Mapper(componentModel = "spring") +@Mapper(componentModel = "spring", uses = UtmComplianceQueryConfigMapper.class) public interface UtmComplianceControlConfigMapper { + + @Mapping(source = "standardSectionId", target = "standardSectionId") UtmComplianceControlConfig toEntity(UtmComplianceControlConfigRequestDto dto); UtmComplianceControlConfigResponseDto toResponse(UtmComplianceControlConfig entity); + @Mapping(source = "standardSectionId", target = "standardSectionId") void updateEntity( @MappingTarget UtmComplianceControlConfig entity, UtmComplianceControlConfigRequestDto dto diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java index 2d70d3887..0f0b88c27 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java @@ -4,16 +4,13 @@ import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigRequestDto; import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigResponseDto; import org.mapstruct.Mapper; -import org.mapstruct.MappingTarget; +import org.mapstruct.Mapping; @Mapper(componentModel = "spring") public interface UtmComplianceQueryConfigMapper { + + @Mapping(source = "indexPatternId", target = "indexPatternId") UtmComplianceQueryConfig toEntity(UtmComplianceQueryConfigRequestDto dto); UtmComplianceQueryConfigResponseDto toResponse(UtmComplianceQueryConfig entity); - - void updateEntity( - @MappingTarget UtmComplianceQueryConfig entity, - UtmComplianceQueryConfigRequestDto dto - ); -} +} \ No newline at end of file diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml index 6a15cf231..080ebe6b8 100644 --- a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml +++ b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml @@ -26,14 +26,14 @@ - + + tableName="utm_compliance_query_config"> From 3442ae31770fd6b1edc30ec0dd59f82ba6d100e6 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 16 Jan 2026 14:04:28 -0600 Subject: [PATCH 005/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../UtmComplianceControlConfigResource.java | 56 ++++++++----------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java index caa6d5206..e73fdf54e 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -1,13 +1,9 @@ package com.park.utmstack.web.rest.compliance.config; import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; -import com.park.utmstack.service.compliance.config.UtmComplianceQueryConfigService; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigRequestDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigResponseDto; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; -import com.park.utmstack.service.mapper.compliance.UtmComplianceQueryConfigMapper; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -16,20 +12,14 @@ public class UtmComplianceControlConfigResource { private final UtmComplianceControlConfigService controlService; - private final UtmComplianceQueryConfigService queryService; private final UtmComplianceControlConfigMapper controlMapper; - private final UtmComplianceQueryConfigMapper queryMapper; public UtmComplianceControlConfigResource( UtmComplianceControlConfigService controlService, - UtmComplianceQueryConfigService queryService, - UtmComplianceControlConfigMapper controlMapper, - UtmComplianceQueryConfigMapper queryMapper + UtmComplianceControlConfigMapper controlMapper ) { this.controlService = controlService; - this.queryService = queryService; this.controlMapper = controlMapper; - this.queryMapper = queryMapper; } @PostMapping @@ -37,14 +27,24 @@ public ResponseEntity createControl( @RequestBody UtmComplianceControlConfigRequestDto dto ) { var entity = controlMapper.toEntity(dto); + + if (entity.getQueriesConfigs() != null) { + entity.getQueriesConfigs().forEach(q -> { + q.setControlConfigId(entity.getId()); + }); + } + var saved = controlService.create(entity); + return ResponseEntity.ok(controlMapper.toResponse(saved)); } @GetMapping("/{id}") public ResponseEntity getControl(@PathVariable Long id) { var entity = controlService.findById(id); - if (entity == null) return ResponseEntity.notFound().build(); + if (entity == null) { + return ResponseEntity.notFound().build(); + } return ResponseEntity.ok(controlMapper.toResponse(entity)); } @@ -54,11 +54,19 @@ public ResponseEntity updateControl( @RequestBody UtmComplianceControlConfigRequestDto dto ) { var existing = controlService.findById(id); - if (existing == null) return ResponseEntity.notFound().build(); + if (existing == null) { + return ResponseEntity.notFound().build(); + } controlMapper.updateEntity(existing, dto); - var updated = controlService.update(id, existing); + if (existing.getQueriesConfigs() != null) { + existing.getQueriesConfigs().forEach(q -> { + q.setControlConfigId(id); + }); + } + + var updated = controlService.update(id, existing); return ResponseEntity.ok(controlMapper.toResponse(updated)); } @@ -67,24 +75,4 @@ public ResponseEntity deleteControl(@PathVariable Long id) { controlService.delete(id); return ResponseEntity.noContent().build(); } - - @PostMapping("/{controlId}/query") - public ResponseEntity addQuery( - @PathVariable Long controlId, - @RequestBody UtmComplianceQueryConfigRequestDto dto - ) { - dto.setControlConfigId(controlId); - - var entity = queryMapper.toEntity(dto); - var saved = queryService.create(entity); - - return ResponseEntity.ok(queryMapper.toResponse(saved)); - } - - @DeleteMapping("/query/{queryId}") - public ResponseEntity deleteQuery(@PathVariable Long queryId) { - queryService.delete(queryId); - return ResponseEntity.noContent().build(); - } } - From a38261ae50a9e0724686a4cb8f36c4d76d89dcf9 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 16 Jan 2026 17:02:32 -0600 Subject: [PATCH 006/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../com/park/utmstack/config/Constants.java | 2 +- .../UtmComplianceControlConfig.java | 19 ++++-- .../compliance/UtmComplianceQueryConfig.java | 20 ++++-- .../UtmComplianceControlConfigService.java | 61 ++++++++++++++++--- .../UtmComplianceControlConfigRequestDto.java | 1 + ...UtmComplianceControlConfigResponseDto.java | 1 - .../UtmComplianceQueryConfigRequestDto.java | 1 + .../UtmComplianceControlConfigResource.java | 30 ++------- 8 files changed, 89 insertions(+), 46 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/config/Constants.java b/backend/src/main/java/com/park/utmstack/config/Constants.java index 96d7535d0..c7c0e0e79 100644 --- a/backend/src/main/java/com/park/utmstack/config/Constants.java +++ b/backend/src/main/java/com/park/utmstack/config/Constants.java @@ -164,7 +164,7 @@ public final class Constants { public static final List API_ENDPOINT_IGNORE = Collections.emptyList(); // Application version file - public static final String APP_VERSION_FILE = "/updates/version.json"; + public static final String APP_VERSION_FILE = "/Users/elena/Documents/Work/UTM Stack/version.json"; public static final String ADMIN_EMAIL = "admin@localhost"; diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java index e516867e1..a9a880bd6 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java @@ -7,6 +7,7 @@ import javax.persistence.*; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; @Getter @@ -27,10 +28,15 @@ public class UtmComplianceControlConfig implements Serializable { private Long standardSectionId; @ManyToOne - @JoinColumn(name = "standard_section_id", insertable = false, updatable = false) + @JoinColumn(name = "standard_section_id", + insertable = false, + updatable = false + ) private UtmComplianceStandardSection section; - @Column(name = "control_name", length = 50) + @Column(name = "control_name", + length = 50 + ) private String controlName; @Column(name = "control_solution") @@ -43,7 +49,10 @@ public class UtmComplianceControlConfig implements Serializable { @Column(name = "control_strategy") private ComplianceStrategy controlStrategy; - @OneToMany(cascade = CascadeType.ALL) - @JoinColumn(name = "control_config_id") - private List queriesConfigs; + @OneToMany( + mappedBy = "controlConfig", + cascade = CascadeType.ALL, + orphanRemoval = true + ) + private List queriesConfigs = new ArrayList<>(); } diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java index 37da56174..1d0cec61f 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java @@ -25,10 +25,14 @@ public class UtmComplianceQueryConfig implements Serializable { @GeneratedValue(generator = "CustomIdentityGenerator") private Long id; - @Column(name = "query_description", columnDefinition = "TEXT") + @Column(name = "query_description", + columnDefinition = "TEXT" + ) private String queryDescription; - @Column(name = "sql_query", columnDefinition = "TEXT") + @Column(name = "sql_query", + columnDefinition = "TEXT" + ) private String sqlQuery; @Enumerated(EnumType.STRING) @@ -39,10 +43,18 @@ public class UtmComplianceQueryConfig implements Serializable { private Long indexPatternId; @ManyToOne - @JoinColumn(name = "index_pattern_id", insertable = false, updatable = false) + @JoinColumn(name = "index_pattern_id", + insertable = false, + updatable = false + ) private UtmIndexPattern indexPattern; - @Column(name = "control_config_id") private Long controlConfigId; + + @ManyToOne @JoinColumn(name = "control_config_id", + insertable = false, + updatable = false + ) + private UtmComplianceControlConfig controlConfig; } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 80ab71182..049646377 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -2,28 +2,71 @@ import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; import com.park.utmstack.repository.compliance.UtmComplianceControlConfigRepository; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigRequestDto; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; +import com.park.utmstack.service.mapper.compliance.UtmComplianceQueryConfigMapper; import org.springframework.stereotype.Service; +import javax.transaction.Transactional; +import java.util.ArrayList; import java.util.List; @Service public class UtmComplianceControlConfigService { private final UtmComplianceControlConfigRepository repository; + private final UtmComplianceControlConfigMapper mapper; + private final UtmComplianceQueryConfigMapper queryMapper; - public UtmComplianceControlConfigService(UtmComplianceControlConfigRepository repository) { + public UtmComplianceControlConfigService(UtmComplianceControlConfigRepository repository, + UtmComplianceControlConfigMapper mapper, + UtmComplianceQueryConfigMapper queryMapper) { this.repository = repository; + this.mapper = mapper; + this.queryMapper = queryMapper; } - - public UtmComplianceControlConfig create(UtmComplianceControlConfig config) { - return repository.save(config); + + @Transactional + public UtmComplianceControlConfigResponseDto create(UtmComplianceControlConfigRequestDto dto) { + UtmComplianceControlConfig entity = mapper.toEntity(dto); + entity.setQueriesConfigs(new ArrayList<>()); + + entity = repository.save(entity); + + for (var qdto : dto.getQueriesConfigs()) { + var q = queryMapper.toEntity(qdto); + q.setControlConfigId(entity.getId()); + entity.getQueriesConfigs().add(q); + } + + entity = repository.save(entity); + + return mapper.toResponse(entity); } - - public UtmComplianceControlConfig update(Long id, UtmComplianceControlConfig config) { - config.setId(id); - return repository.save(config); + + + @Transactional + public UtmComplianceControlConfigResponseDto update(Long id, UtmComplianceControlConfigRequestDto dto) { + + UtmComplianceControlConfig entity = repository.findById(id) + .orElseThrow(() -> new RuntimeException("Control not found")); + + mapper.updateEntity(entity, dto); + entity.getQueriesConfigs().clear(); + + for (var qdto : dto.getQueriesConfigs()) { + var q = queryMapper.toEntity(qdto); + q.setControlConfigId(id); + entity.getQueriesConfigs().add(q); + } + + entity = repository.save(entity); + + return mapper.toResponse(entity); } - + public void delete(Long id) { repository.deleteById(id); } diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java index 16a751b2f..9a000a05b 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java @@ -7,6 +7,7 @@ @Data public class UtmComplianceControlConfigRequestDto { + private Long id; private Long standardSectionId; private String controlName; private String controlSolution; diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java index 22644e176..80984717b 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java @@ -13,6 +13,5 @@ public class UtmComplianceControlConfigResponseDto { private String controlSolution; private String controlRemediation; private ComplianceStrategy controlStrategy; - private List queriesConfigs; } diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java index 84d32d510..8aab79a6e 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java @@ -5,6 +5,7 @@ @Data public class UtmComplianceQueryConfigRequestDto { + private Long id; private String queryDescription; private String sqlQuery; private EvaluationRule evaluationRule; diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java index e73fdf54e..591b9c0b3 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -26,17 +26,8 @@ public UtmComplianceControlConfigResource( public ResponseEntity createControl( @RequestBody UtmComplianceControlConfigRequestDto dto ) { - var entity = controlMapper.toEntity(dto); - - if (entity.getQueriesConfigs() != null) { - entity.getQueriesConfigs().forEach(q -> { - q.setControlConfigId(entity.getId()); - }); - } - - var saved = controlService.create(entity); - - return ResponseEntity.ok(controlMapper.toResponse(saved)); + var created = controlService.create(dto); + return ResponseEntity.ok(created); } @GetMapping("/{id}") @@ -53,21 +44,8 @@ public ResponseEntity updateControl( @PathVariable Long id, @RequestBody UtmComplianceControlConfigRequestDto dto ) { - var existing = controlService.findById(id); - if (existing == null) { - return ResponseEntity.notFound().build(); - } - - controlMapper.updateEntity(existing, dto); - - if (existing.getQueriesConfigs() != null) { - existing.getQueriesConfigs().forEach(q -> { - q.setControlConfigId(id); - }); - } - - var updated = controlService.update(id, existing); - return ResponseEntity.ok(controlMapper.toResponse(updated)); + var updated = controlService.update(id, dto); + return ResponseEntity.ok(updated); } @DeleteMapping("/{id}") From bab848a0c4c5ec7b9183e8ac49b221dce65845d8 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 16 Jan 2026 18:03:35 -0600 Subject: [PATCH 007/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../com/park/utmstack/config/Constants.java | 2 +- .../UtmComplianceControlConfigService.java | 12 +++++------- ....java => UtmComplianceControlConfigDto.java} | 4 ++-- .../UtmComplianceControlConfigResponseDto.java | 17 ----------------- ...to.java => UtmComplianceQueryConfigDto.java} | 2 +- .../UtmComplianceQueryConfigResponseDto.java | 14 -------------- .../UtmComplianceControlConfigMapper.java | 14 +++++--------- .../UtmComplianceQueryConfigMapper.java | 8 +++----- .../UtmComplianceControlConfigResource.java | 15 +++++++-------- 9 files changed, 24 insertions(+), 64 deletions(-) rename backend/src/main/java/com/park/utmstack/service/dto/compliance/{UtmComplianceControlConfigRequestDto.java => UtmComplianceControlConfigDto.java} (76%) delete mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java rename backend/src/main/java/com/park/utmstack/service/dto/compliance/{UtmComplianceQueryConfigRequestDto.java => UtmComplianceQueryConfigDto.java} (87%) delete mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java diff --git a/backend/src/main/java/com/park/utmstack/config/Constants.java b/backend/src/main/java/com/park/utmstack/config/Constants.java index c7c0e0e79..f4651ee14 100644 --- a/backend/src/main/java/com/park/utmstack/config/Constants.java +++ b/backend/src/main/java/com/park/utmstack/config/Constants.java @@ -164,7 +164,7 @@ public final class Constants { public static final List API_ENDPOINT_IGNORE = Collections.emptyList(); // Application version file - public static final String APP_VERSION_FILE = "/Users/elena/Documents/Work/UTM Stack/version.json"; + public static final String APP_VERSION_FILE = "/Users/elena/Documents/Work/UTM Stack/version.json"; //TODO: ELENA public static final String ADMIN_EMAIL = "admin@localhost"; diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 049646377..14febd6ce 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -2,9 +2,7 @@ import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; import com.park.utmstack.repository.compliance.UtmComplianceControlConfigRepository; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigRequestDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; import com.park.utmstack.service.mapper.compliance.UtmComplianceQueryConfigMapper; import org.springframework.stereotype.Service; @@ -29,7 +27,7 @@ public UtmComplianceControlConfigService(UtmComplianceControlConfigRepository re } @Transactional - public UtmComplianceControlConfigResponseDto create(UtmComplianceControlConfigRequestDto dto) { + public UtmComplianceControlConfigDto create(UtmComplianceControlConfigDto dto) { UtmComplianceControlConfig entity = mapper.toEntity(dto); entity.setQueriesConfigs(new ArrayList<>()); @@ -43,12 +41,12 @@ public UtmComplianceControlConfigResponseDto create(UtmComplianceControlConfigRe entity = repository.save(entity); - return mapper.toResponse(entity); + return mapper.toDto(entity); } @Transactional - public UtmComplianceControlConfigResponseDto update(Long id, UtmComplianceControlConfigRequestDto dto) { + public UtmComplianceControlConfigDto update(Long id, UtmComplianceControlConfigDto dto) { UtmComplianceControlConfig entity = repository.findById(id) .orElseThrow(() -> new RuntimeException("Control not found")); @@ -64,7 +62,7 @@ public UtmComplianceControlConfigResponseDto update(Long id, UtmComplianceContro entity = repository.save(entity); - return mapper.toResponse(entity); + return mapper.toDto(entity); } public void delete(Long id) { diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java similarity index 76% rename from backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java rename to backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java index 9a000a05b..533fb9d77 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigRequestDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java @@ -6,12 +6,12 @@ import java.util.List; @Data -public class UtmComplianceControlConfigRequestDto { +public class UtmComplianceControlConfigDto { private Long id; private Long standardSectionId; private String controlName; private String controlSolution; private String controlRemediation; private ComplianceStrategy controlStrategy; - private List queriesConfigs; + private List queriesConfigs; } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java deleted file mode 100644 index 80984717b..000000000 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigResponseDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.park.utmstack.service.dto.compliance; - -import com.park.utmstack.domain.compliance.enums.ComplianceStrategy; -import lombok.Data; - -import java.util.List; - -@Data -public class UtmComplianceControlConfigResponseDto { - private Long id; - private Long standardSectionId; - private String controlName; - private String controlSolution; - private String controlRemediation; - private ComplianceStrategy controlStrategy; - private List queriesConfigs; -} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java similarity index 87% rename from backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java rename to backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java index 8aab79a6e..33e93f6a4 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigRequestDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java @@ -4,7 +4,7 @@ import lombok.Data; @Data -public class UtmComplianceQueryConfigRequestDto { +public class UtmComplianceQueryConfigDto { private Long id; private String queryDescription; private String sqlQuery; diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java deleted file mode 100644 index 2bc1bbd40..000000000 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigResponseDto.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.park.utmstack.service.dto.compliance; - -import com.park.utmstack.domain.compliance.enums.EvaluationRule; -import lombok.Data; - -@Data -public class UtmComplianceQueryConfigResponseDto { - private Long id; - private String queryDescription; - private String sqlQuery; - private EvaluationRule evaluationRule; - private Long indexPatternId; - private Long controlConfigId; -} diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java index 50183fdad..10f6002f0 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java @@ -1,8 +1,7 @@ package com.park.utmstack.service.mapper.compliance; import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.MappingTarget; @@ -10,14 +9,11 @@ @Mapper(componentModel = "spring", uses = UtmComplianceQueryConfigMapper.class) public interface UtmComplianceControlConfigMapper { - @Mapping(source = "standardSectionId", target = "standardSectionId") - UtmComplianceControlConfig toEntity(UtmComplianceControlConfigRequestDto dto); + UtmComplianceControlConfig toEntity(UtmComplianceControlConfigDto dto); - UtmComplianceControlConfigResponseDto toResponse(UtmComplianceControlConfig entity); + UtmComplianceControlConfigDto toDto(UtmComplianceControlConfig entity); - @Mapping(source = "standardSectionId", target = "standardSectionId") - void updateEntity( - @MappingTarget UtmComplianceControlConfig entity, - UtmComplianceControlConfigRequestDto dto + @Mapping(target = "id", ignore = true) + void updateEntity(@MappingTarget UtmComplianceControlConfig entity, UtmComplianceControlConfigDto dto ); } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java index 0f0b88c27..450f91e3c 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java @@ -1,16 +1,14 @@ package com.park.utmstack.service.mapper.compliance; import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; -import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigRequestDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigResponseDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigDto; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @Mapper(componentModel = "spring") public interface UtmComplianceQueryConfigMapper { - @Mapping(source = "indexPatternId", target = "indexPatternId") - UtmComplianceQueryConfig toEntity(UtmComplianceQueryConfigRequestDto dto); + UtmComplianceQueryConfig toEntity(UtmComplianceQueryConfigDto dto); - UtmComplianceQueryConfigResponseDto toResponse(UtmComplianceQueryConfig entity); + UtmComplianceQueryConfigDto toDto(UtmComplianceQueryConfig entity); } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java index 591b9c0b3..a917f5eb3 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -1,8 +1,7 @@ package com.park.utmstack.web.rest.compliance.config; import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigRequestDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigResponseDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -23,26 +22,26 @@ public UtmComplianceControlConfigResource( } @PostMapping - public ResponseEntity createControl( - @RequestBody UtmComplianceControlConfigRequestDto dto + public ResponseEntity createControl( + @RequestBody UtmComplianceControlConfigDto dto ) { var created = controlService.create(dto); return ResponseEntity.ok(created); } @GetMapping("/{id}") - public ResponseEntity getControl(@PathVariable Long id) { + public ResponseEntity getControl(@PathVariable Long id) { var entity = controlService.findById(id); if (entity == null) { return ResponseEntity.notFound().build(); } - return ResponseEntity.ok(controlMapper.toResponse(entity)); + return ResponseEntity.ok(controlMapper.toDto(entity)); } @PutMapping("/{id}") - public ResponseEntity updateControl( + public ResponseEntity updateControl( @PathVariable Long id, - @RequestBody UtmComplianceControlConfigRequestDto dto + @RequestBody UtmComplianceControlConfigDto dto ) { var updated = controlService.update(id, dto); return ResponseEntity.ok(updated); From f8d98c75916ad25c44a305239d48c08841f0b9ce Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 16 Jan 2026 18:04:39 -0600 Subject: [PATCH 008/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- backend/src/main/java/com/park/utmstack/config/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/com/park/utmstack/config/Constants.java b/backend/src/main/java/com/park/utmstack/config/Constants.java index f4651ee14..96d7535d0 100644 --- a/backend/src/main/java/com/park/utmstack/config/Constants.java +++ b/backend/src/main/java/com/park/utmstack/config/Constants.java @@ -164,7 +164,7 @@ public final class Constants { public static final List API_ENDPOINT_IGNORE = Collections.emptyList(); // Application version file - public static final String APP_VERSION_FILE = "/Users/elena/Documents/Work/UTM Stack/version.json"; //TODO: ELENA + public static final String APP_VERSION_FILE = "/updates/version.json"; public static final String ADMIN_EMAIL = "admin@localhost"; From 1f96401856946ab330b62d0f145a7681107ba894 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Mon, 19 Jan 2026 13:04:53 -0600 Subject: [PATCH 009/135] =?UTF-8?q?feat:=20Add=20new=20ControlConfig=20cre?= =?UTF-8?q?ation=20component=20for=20SQL=E2=80=91based=20compliance=20eval?= =?UTF-8?q?uation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/app/compliance/compliance-routing.module.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/compliance/compliance-routing.module.ts b/frontend/src/app/compliance/compliance-routing.module.ts index 879e5c581..d236323fc 100644 --- a/frontend/src/app/compliance/compliance-routing.module.ts +++ b/frontend/src/app/compliance/compliance-routing.module.ts @@ -4,11 +4,11 @@ import {UserRouteAccessService} from '../core/auth/user-route-access-service'; import {ADMIN_ROLE, USER_ROLE} from '../shared/constants/global.constant'; import {ComplianceCustomViewComponent} from './compliance-custom-view/compliance-custom-view.component'; import {CpStandardManagementComponent} from './compliance-management/cp-standard-management/cp-standard-management.component'; +import {ComplianceReportViewerComponent} from './compliance-report-viewer/compliance-report-viewer.component'; +import { CompliancePrintViewComponent } from './compliance-reports-view/components/compliance-print-view/compliance-print-view.component'; import {ComplianceResultViewComponent} from './compliance-result-view/compliance-result-view.component'; import {ComplianceScheduleComponent} from './compliance-schedule/compliance-schedule.component'; import {ComplianceTemplatesComponent} from './compliance-templates/compliance-templates.component'; -import {ComplianceReportViewerComponent} from "./compliance-report-viewer/compliance-report-viewer.component"; -import { CompliancePrintViewComponent } from './compliance-reports-view/components/compliance-print-view/compliance-print-view.component'; const routes: Routes = [ {path: '', redirectTo: 'templates'}, From d5a4c554c8d7d6d70d82eab9417796d35e3a48d3 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 21 Jan 2026 12:18:28 -0600 Subject: [PATCH 010/135] =?UTF-8?q?feat:=20Add=20new=20ControlConfig=20cre?= =?UTF-8?q?ation=20component=20for=20SQL=E2=80=91based=20compliance=20eval?= =?UTF-8?q?uation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Conflicts: # frontend/src/environments/environment.ts --- .../cp-standard-management.component.ts | 7 +- .../shared/compliance-shared.module.ts | 19 ++- .../utm-compliance-query-form.component.html | 53 +++++++ .../utm-compliance-query-form.component.ts | 87 +++++++++++ .../utm-compliance-query-list.component.html | 44 ++++++ .../utm-compliance-query-list.component.scss | 7 + .../utm-compliance-query-list.component.ts | 35 +++++ ...iance-control-config-create.component.html | 115 ++++++++++++++ ...iance-control-config-create.component.scss | 54 +++++++ ...pliance-control-config-create.component.ts | 142 ++++++++++++++++++ .../enums/compliance-evaluation-rule.enum.ts | 6 + .../shared/enums/compliance-strategy.enum.ts | 4 + .../type/compliance-query-config.type.ts | 11 ++ .../type/compliance-report-config.type.ts | 26 ++++ .../log-analyzer-tabs.component.html | 2 +- .../log-analyzer-tabs.component.ts | 2 +- .../log-analyzer-routing.module.ts | 2 +- .../log-analyzer-query-list.component.ts | 2 +- .../services/log-analyzer-query.service.ts | 2 +- frontend/src/environments/environment.ts | 4 +- 20 files changed, 612 insertions(+), 12 deletions(-) create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.scss create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts create mode 100644 frontend/src/app/compliance/shared/enums/compliance-evaluation-rule.enum.ts create mode 100644 frontend/src/app/compliance/shared/enums/compliance-strategy.enum.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-query-config.type.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-report-config.type.ts diff --git a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts index 8e7aba5de..9d055aa63 100644 --- a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts +++ b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts @@ -4,6 +4,10 @@ import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; import {ADMIN_ROLE} from '../../../shared/constants/global.constant'; import {ActionInitParamsEnum, ActionInitParamsValueEnum} from '../../../shared/enums/action-init-params.enum'; import {CpStandardBehavior} from '../../shared/behavior/cp-standard.behavior'; +import { + UtmComplianceControlConfigCreateComponent +} from '../../shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component'; + import {UtmComplianceCreateComponent} from '../../shared/components/utm-compliance-create/utm-compliance-create.component'; import {ComplianceStandardType} from '../../shared/type/compliance-standard.type'; import {UtmCpExportComponent} from '../utm-cp-export/utm-cp-export.component'; @@ -48,6 +52,7 @@ export class CpStandardManagementComponent implements OnInit { } newCompliance() { - this.modalService.open(UtmComplianceCreateComponent, {centered: true}); + //this.modalService.open(UtmComplianceCreateComponent, {centered: true}); + this.modalService.open(UtmComplianceControlConfigCreateComponent, {centered: true, size: 'lg'}); } } diff --git a/frontend/src/app/compliance/shared/compliance-shared.module.ts b/frontend/src/app/compliance/shared/compliance-shared.module.ts index b134a5a00..b7377f7c0 100644 --- a/frontend/src/app/compliance/shared/compliance-shared.module.ts +++ b/frontend/src/app/compliance/shared/compliance-shared.module.ts @@ -20,6 +20,15 @@ import { ComplianceTimeWindowsComponent } from '../compliance-reports-view/components/compliance-time-window/compliance-time-windows.component'; import {ReportApplyNoteComponent} from './components/report-apply-note/report-apply-note.component'; +import { + UtmComplianceQueryFormComponent +} from './components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component'; +import { + UtmComplianceQueryListComponent +} from './components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component'; +import { + UtmComplianceControlConfigCreateComponent +} from './components/utm-compliance-control-config-create/utm-compliance-control-config-create.component'; import {UtmComplianceCreateComponent} from './components/utm-compliance-create/utm-compliance-create.component'; import { UtmComplianceScheduleCreateComponent @@ -35,8 +44,6 @@ import {UtmCpStandardSectionCreateComponent} from './components/utm-cp-standard- import {UtmCpStandardSelectComponent} from './components/utm-cp-standard-select/utm-cp-standard-select.component'; import {UtmReportInfoViewComponent} from './components/utm-report-info-view/utm-report-info-view.component'; import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/utm-save-as-compliance.component'; - - @NgModule({ declarations: [ UtmSaveAsComplianceComponent, @@ -55,7 +62,10 @@ import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/ ComplianceReportsViewComponent, ComplianceReportDetailComponent, ComplianceTimeWindowsComponent, - CompliancePrintViewComponent + CompliancePrintViewComponent, + UtmComplianceControlConfigCreateComponent, + UtmComplianceQueryFormComponent, + UtmComplianceQueryListComponent ], imports: [ CommonModule, @@ -76,7 +86,8 @@ import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/ UtmCpStandardSectionCreateComponent, UtmComplianceCreateComponent, UtmComplianceScheduleCreateComponent, - UtmComplianceScheduleDeleteComponent + UtmComplianceScheduleDeleteComponent, + UtmComplianceControlConfigCreateComponent ], exports: [ UtmSaveAsComplianceComponent, diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html new file mode 100644 index 000000000..140400431 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html @@ -0,0 +1,53 @@ +
+
+ + +
+ +
+ + +
+ +
+ + + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + +
+
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts new file mode 100644 index 000000000..d760bc338 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts @@ -0,0 +1,87 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import {UtmIndexPattern} from '../../../../../shared/types/index-pattern/utm-index-pattern'; +import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; +import {HttpResponse} from "@angular/common/http"; +import {IndexPatternService} from "../../../../../shared/services/elasticsearch/index-pattern.service"; + +@Component({ + selector: 'app-utm-compliance-query-form', + templateUrl: './utm-compliance-query-form.component.html' +}) +export class UtmComplianceQueryFormComponent implements OnInit { + + @Input() query: UtmComplianceQueryConfigType = null; + + @Output() save = new EventEmitter(); + @Output() cancel = new EventEmitter(); + + form: FormGroup; + pattern: UtmIndexPattern; + patterns: UtmIndexPattern[]; + indexPatternList = []; + + constructor(private fb: FormBuilder, + private indexPatternService: IndexPatternService) {} + + ngOnInit() { + this.getIndexPatterns('init'); + const q = this.query || {}; + + this.form = this.fb.group({ + id: [q.id || null], + name: [q.name || '', Validators.required], + queryDescription: [q.queryDescription || '', Validators.required], + sqlQuery: [q.sqlQuery || '', Validators.required], + evaluationRule: [q.evaluationRule || null, Validators.required], + indexPatternId: [q.indexPatternId || null, Validators.required], + controlConfigId: [q.controlConfigId || null] + }); + } + + submit() { + if (this.form.invalid) { + return; + } + this.save.emit(this.form.value); + } + + cancelEdit() { + this.cancel.emit(); + } + + //TODO: ELENA revisar de aqui para abajo + onIndexPatternChange($event: any) { + this.pattern = $event; + //this.indexPatternChange.emit($event); + } + + getIndexPatterns(init?: string) { + const req = { + page: 0, + size: 1000, + sort: 'id,asc', + 'isActive.equals': true, + }; + this.indexPatternService.query(req).subscribe( + (res: HttpResponse) => this.onSuccess(res.body, res.headers, init), + (res: HttpResponse) => this.onError(res.body) + ); + } + + private onSuccess(data, headers, init) { + this.patterns = data; + this.indexPatternList = this.getListPatterns(); + if (init) { + this.pattern = this.patterns[0]; + } + } + + getListPatterns(){ + return this.patterns.map(pattern => ({ id: pattern.id, name: pattern.pattern, selected: this.pattern.id == pattern.id })); + } + + private onError(error) { + // this.alertService.error(error.error, error.message, null); + } +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html new file mode 100644 index 000000000..70bfa2f96 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html @@ -0,0 +1,44 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescriptionSQLRuleIndex PatternActions
{{ q.name }}{{ q.queryDescription }}{{ q.sqlQuery }}{{ q.evaluationRule }}{{ q.indexPatternId }} + + +
+ +
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss new file mode 100644 index 000000000..e24d001bf --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss @@ -0,0 +1,7 @@ +.query-list-container { + width: 100%; +} + +.table td { + vertical-align: middle; +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts new file mode 100644 index 000000000..4c6dcb337 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts @@ -0,0 +1,35 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; + +@Component({ + selector: 'app-utm-compliance-query-list', + templateUrl: './utm-compliance-query-list.component.html', + styleUrls: ['./utm-compliance-query-list.component.scss'] +}) +export class UtmComplianceQueryListComponent { + + @Input() queries: UtmComplianceQueryConfigType[] = []; + + @Output() add = new EventEmitter(); + @Output() edit = new EventEmitter<{ index: number, query: UtmComplianceQueryConfigType }>(); + @Output() delete = new EventEmitter(); + + editingIndex: number = null; + + startEdit(index: number) { + this.editingIndex = index; + } + + finishEdit(query: UtmComplianceQueryConfigType) { + this.edit.emit({ index: this.editingIndex, query }); + this.editingIndex = null; + } + + cancelEdit() { + this.editingIndex = null; + } + + remove(index: number) { + this.delete.emit(index); + } +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html new file mode 100644 index 000000000..06a29fc89 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html @@ -0,0 +1,115 @@ + +
+
+
+
+ + Standard & Section + +
+ +
+
+ +
+ + View select + +
+ +
+
+
+
+
+
+
+ + + +
+
+ + + +
+
+ + +
+ + Report name is required. + + + Report name must be at least 10 characters long. + + + Report name must not exceed 200 characters. + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + + +
+
+
+
+ + +
+
+ + + + +
+
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.scss new file mode 100644 index 000000000..38365f459 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.scss @@ -0,0 +1,54 @@ +@import '../../../../../assets/styles/theme'; +@import '../../../../../assets/styles/var'; + +.step-container { + display: flex; + align-items: center; + justify-content: space-around; + width: 100%; + position: relative; + + .step { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 1; + + .round-indicator { + width: 30px; + height: 30px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + + i { + font-size: 11px; + } + } + + .step-active { + background-color: $blue-scroll; + } + + .step-inactive { + background-color: $grey-color; + } + + .step-success { + background-color: $success-color !important; + } + } + + .step-link { + height: 1px; + background-color: #7777; + width: 50%; + top: 33px; + position: absolute; + z-index: 0; + } + +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts new file mode 100644 index 000000000..9aae9158d --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts @@ -0,0 +1,142 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {FormArray, FormBuilder, FormGroup, Validators} from '@angular/forms'; +import {NgbActiveModal, NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {UtmToastService} from '../../../../shared/alert/utm-toast.service'; +import {FILTER_OPERATORS} from '../../../../shared/constants/filter-operators.const'; +import {ElasticOperatorsEnum} from '../../../../shared/enums/elastic-operators.enum'; +import {ElasticFilterType} from '../../../../shared/types/filter/elastic-filter.type'; +import {OperatorsType} from '../../../../shared/types/filter/operators.type'; +import {CpReportBehavior} from '../../behavior/cp-report.behavior'; +import {ComplianceStrategyEnum} from '../../enums/compliance-strategy.enum'; +import {ComplianceTypeEnum} from '../../enums/compliance-type.enum'; +import {CpReportsService} from '../../services/cp-reports.service'; +import {ComplianceReportConfigType} from '../../type/compliance-report-config.type'; +import {ComplianceReportType} from '../../type/compliance-report.type'; + +@Component({ + selector: 'app-utm-compliance-control-config-create', + templateUrl: './utm-compliance-control-config-create.component.html', + styleUrls: ['./utm-compliance-control-config-create.component.scss'] +}) +export class UtmComplianceControlConfigCreateComponent implements OnInit { + @Input() report: ComplianceReportConfigType; + @Output() reportCreated = new EventEmitter(); + step = 2; + stepCompleted: number[] = []; + creating = false; + viewSection = false; + standardSectionId: number; + operators: OperatorsType[] = FILTER_OPERATORS; + operatorEnum = ElasticOperatorsEnum; + solution = ''; + name: string; + complianceForm: FormGroup; + strategies = []; + + + constructor(private cpReportsService: CpReportsService, + public activeModal: NgbActiveModal, + private cpReportBehavior: CpReportBehavior, + private utmToastService: UtmToastService, + public modalService: NgbModal, + private fb: FormBuilder) { + } + + ngOnInit() { + this.complianceForm = this.fb.group({ + reportName: [this.report ? this.report.configReportName : '' , + [Validators.required, Validators.minLength(10), Validators.maxLength(200)]], + solution: [this.report ? this.report.configSolution : '', [Validators.maxLength(2000)]], + remediation: [this.report && this.report.configRemediation ? this.report.configRemediation : '', [Validators.maxLength(2000)]], + strategy: [this.report ? this.report.strategy as ComplianceStrategyEnum : null, [Validators.required]], + queriesConfigs: this.fb.array([]) + }); + + this.strategies = Object.keys(ComplianceStrategyEnum).map( + key => ({ + id: key as ComplianceStrategyEnum, + strategy: ComplianceStrategyEnum[key as keyof typeof ComplianceStrategyEnum] + }) + ); + + if (this.report) { + this.viewSection = true; + this.standardSectionId = this.report.standardSectionId; + } + } + + backStep() { + this.step -= 1; + this.stepCompleted.pop(); + } + + nextStep() { + this.stepCompleted.push(this.step); + this.step += 1; + } + + isCompleted(step: number) { + return this.stepCompleted.findIndex(value => value === step) !== -1; + } + + onStandardChange($event: number) { + this.viewSection = true; + } + + onStandardSectionChange($event: number) { + this.standardSectionId = $event; + } + + getFilterLabel(filter: ElasticFilterType): string { + return filter.field + ' ' + + this.extractOperator(filter.operator) + ' ' + + (filter.value ? filter.value.toString().replace(',', ' and ') : ''); + } + + extractOperator(operator: string): string { + const index = this.operators.findIndex(value => value.operator === operator); + return this.operators[index].name; + } + + + createCompliance() { + this.creating = true; + const reportCompliance: ComplianceReportType = { + configReportEditable: true, + configSolution: this.complianceForm.controls.solution.value.replace(/\r?\n/g, '
'), + configRemediation: this.complianceForm.controls.remediation.value.replace(/\r?\n/g, '
'), + configType: ComplianceTypeEnum.TEMPLATE, + standardSectionId: this.standardSectionId, + configReportName: this.complianceForm.controls.reportName.value, + }; + if (this.report) { + reportCompliance.id = this.report.id; + this.cpReportsService.update(reportCompliance).subscribe(() => { + this.utmToastService.showSuccessBottom('Compliance report edited successfully'); + this.activeModal.close(); + this.reportCreated.emit('edited'); + }, error1 => { + this.creating = false; + this.utmToastService.showError('Error', 'Error editing compliance report'); + }); + } else { + this.cpReportsService.create(reportCompliance).subscribe(() => { + this.utmToastService.showSuccessBottom('Compliance report created successfully'); + this.activeModal.close(); + this.cpReportBehavior.$reportUpdate.next('update'); + this.reportCreated.emit('created'); + }, error1 => { + this.creating = false; + this.utmToastService.showError('Error', 'Error creating compliance report'); + }); + } + } + + get queriesConfigs(): FormArray { + return this.complianceForm.get('queriesConfigs') as FormArray; + } + + get queriesList() { + return this.queriesConfigs.controls.map(c => c.value); + } +} diff --git a/frontend/src/app/compliance/shared/enums/compliance-evaluation-rule.enum.ts b/frontend/src/app/compliance/shared/enums/compliance-evaluation-rule.enum.ts new file mode 100644 index 000000000..913244657 --- /dev/null +++ b/frontend/src/app/compliance/shared/enums/compliance-evaluation-rule.enum.ts @@ -0,0 +1,6 @@ +export enum ComplianceEvaluationRuleEnum { + NO_HITS_ALLOWED = 'NO_HITS_ALLOWED', + MIN_HITS_REQUIRED = 'MIN_HITS_REQUIRED', + THRESHOLD_MAX = 'THRESHOLD_MAX', + MATCH_FIELD_VALUE = 'MATCH_FIELD_VALUE' +} diff --git a/frontend/src/app/compliance/shared/enums/compliance-strategy.enum.ts b/frontend/src/app/compliance/shared/enums/compliance-strategy.enum.ts new file mode 100644 index 000000000..40d2b5044 --- /dev/null +++ b/frontend/src/app/compliance/shared/enums/compliance-strategy.enum.ts @@ -0,0 +1,4 @@ +export enum ComplianceStrategyEnum { + ALL = 'ALL', + ANY = 'ANY', +} diff --git a/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts b/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts new file mode 100644 index 000000000..35148d53b --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts @@ -0,0 +1,11 @@ +import {ComplianceEvaluationRuleEnum} from '../enums/compliance-evaluation-rule.enum'; + +export class UtmComplianceQueryConfigType { + id?: number; + name?: string; + queryDescription?: string; + sqlQuery?: string; + evaluationRule?: ComplianceEvaluationRuleEnum; + indexPatternId?: number; + controlConfigId?: number; +} diff --git a/frontend/src/app/compliance/shared/type/compliance-report-config.type.ts b/frontend/src/app/compliance/shared/type/compliance-report-config.type.ts new file mode 100644 index 000000000..783c600f6 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-report-config.type.ts @@ -0,0 +1,26 @@ +import {UtmDashboardVisualizationType} from '../../../shared/chart/types/dashboard/utm-dashboard-visualization.type'; +import {UtmDashboardType} from '../../../shared/chart/types/dashboard/utm-dashboard.type'; +import {UtmFieldType} from '../../../shared/types/table/utm-field.type'; +import {ComplianceStrategyEnum} from '../enums/compliance-strategy.enum'; +import {UtmComplianceQueryConfigType} from './compliance-query-config.type'; +import {ComplianceStandardSectionType} from './compliance-standard-section.type'; + + +export class ComplianceReportConfigType { + id?: number; + section?: ComplianceStandardSectionType; + standardSectionId?: number; + configReportName?: string; + configSolution?: string; + configRemediation?: string; + strategy?: ComplianceStrategyEnum; + queriesConfigs?: UtmComplianceQueryConfigType[]; + + columns?: UtmFieldType[]; + dashboardId?: number; + associatedDashboard?: UtmDashboardType; + selected?: boolean; + visualization?: any; + status?: string; + dashboard?: UtmDashboardVisualizationType[]; +} diff --git a/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.html b/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.html index 238746a91..02473a4d8 100644 --- a/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.html +++ b/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.html @@ -5,7 +5,7 @@
Log analyzer
-
diff --git a/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.ts b/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.ts index 1e1cb3406..78bbaa640 100644 --- a/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.ts +++ b/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.ts @@ -72,7 +72,7 @@ export class LogAnalyzerTabsComponent implements OnInit, OnDestroy { this.router.events.pipe( filter(event => event instanceof NavigationStart), tap((event: NavigationStart) => { - if (event.url !== '/discover/log-analyzer-queries' && !event.url.includes('/discover/log-analyzer')) { + if (event.url !== '/discover/log-analyzer-query-config' && !event.url.includes('/discover/log-analyzer')) { this.tabService.closeAllTabs(); } }), diff --git a/frontend/src/app/log-analyzer/log-analyzer-routing.module.ts b/frontend/src/app/log-analyzer/log-analyzer-routing.module.ts index aa13b556c..e33f6a383 100644 --- a/frontend/src/app/log-analyzer/log-analyzer-routing.module.ts +++ b/frontend/src/app/log-analyzer/log-analyzer-routing.module.ts @@ -14,7 +14,7 @@ const routes: Routes = [ data: {authorities: [ADMIN_ROLE, USER_ROLE]} }, { - path: 'log-analyzer-queries', + path: 'log-analyzer-query-config', component: LogAnalyzerQueryListComponent, canActivate: [UserRouteAccessService], data: {authorities: [ADMIN_ROLE, USER_ROLE]} diff --git a/frontend/src/app/log-analyzer/queries/log-analyzer-query-list/log-analyzer-query-list.component.ts b/frontend/src/app/log-analyzer/queries/log-analyzer-query-list/log-analyzer-query-list.component.ts index cc011e6bf..2cb12edf2 100644 --- a/frontend/src/app/log-analyzer/queries/log-analyzer-query-list/log-analyzer-query-list.component.ts +++ b/frontend/src/app/log-analyzer/queries/log-analyzer-query-list/log-analyzer-query-list.component.ts @@ -58,7 +58,7 @@ export class LogAnalyzerQueryListComponent implements OnInit, OnDestroy { this.router.events.pipe( filter(event => event instanceof NavigationStart), tap((event: NavigationStart) => { - if (event.url !== '/discover/log-analyzer-queries' && !event.url.includes('/discover/log-analyzer')) { + if (event.url !== '/discover/log-analyzer-query-config' && !event.url.includes('/discover/log-analyzer')) { this.tabService.closeAllTabs(); } }), diff --git a/frontend/src/app/log-analyzer/shared/services/log-analyzer-query.service.ts b/frontend/src/app/log-analyzer/shared/services/log-analyzer-query.service.ts index cc17c5501..87506e232 100644 --- a/frontend/src/app/log-analyzer/shared/services/log-analyzer-query.service.ts +++ b/frontend/src/app/log-analyzer/shared/services/log-analyzer-query.service.ts @@ -10,7 +10,7 @@ import {LogAnalyzerQueryType} from '../type/log-analyzer-query.type'; }) export class LogAnalyzerQueryService { - public resourceUrl = SERVER_API_URL + 'api/log-analyzer/queries'; + public resourceUrl = SERVER_API_URL + 'api/log-analyzer/query-config'; constructor(private http: HttpClient) { } diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts index c14489291..a9c376b4f 100644 --- a/frontend/src/environments/environment.ts +++ b/frontend/src/environments/environment.ts @@ -4,8 +4,8 @@ export const environment = { production: false, - SERVER_API_URL: 'https://192.168.1.18/', - //SERVER_API_URL: 'http://localhost:8080/', + //SERVER_API_URL: 'https://192.168.1.18/', + SERVER_API_URL: 'http://localhost:8080/', SERVER_API_CONTEXT: '', SESSION_AUTH_TOKEN: window.location.host.split(':')[0].toLocaleUpperCase(), WEBSOCKET_URL: '//localhost:8080', From 4cfd7351b6f06f90e90a54fd3e117c0cfd2b3351 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 23 Jan 2026 19:28:58 -0600 Subject: [PATCH 011/135] =?UTF-8?q?feat:=20Add=20new=20ControlConfig=20cre?= =?UTF-8?q?ation=20component=20for=20SQL=E2=80=91based=20compliance=20eval?= =?UTF-8?q?uation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared/compliance-shared.module.ts | 4 +- .../utm-compliance-query-form.component.css | 8 ++ .../utm-compliance-query-form.component.html | 114 +++++++++++++----- .../utm-compliance-query-form.component.ts | 82 ++++++------- .../utm-compliance-query-list.component.html | 88 ++++++++------ .../utm-compliance-query-list.component.scss | 4 + .../utm-compliance-query-list.component.ts | 84 ++++++++++++- ...iance-control-config-create.component.html | 9 +- ...pliance-control-config-create.component.ts | 2 +- .../code-editor/code-editor.component.ts | 109 +++++++++++------ 10 files changed, 346 insertions(+), 158 deletions(-) create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css diff --git a/frontend/src/app/compliance/shared/compliance-shared.module.ts b/frontend/src/app/compliance/shared/compliance-shared.module.ts index b7377f7c0..98aff71cf 100644 --- a/frontend/src/app/compliance/shared/compliance-shared.module.ts +++ b/frontend/src/app/compliance/shared/compliance-shared.module.ts @@ -44,6 +44,7 @@ import {UtmCpStandardSectionCreateComponent} from './components/utm-cp-standard- import {UtmCpStandardSelectComponent} from './components/utm-cp-standard-select/utm-cp-standard-select.component'; import {UtmReportInfoViewComponent} from './components/utm-report-info-view/utm-report-info-view.component'; import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/utm-save-as-compliance.component'; +import {GraphicBuilderSharedModule} from "../../graphic-builder/shared/graphic-builder-shared.module"; @NgModule({ declarations: [ UtmSaveAsComplianceComponent, @@ -75,7 +76,8 @@ import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/ ReactiveFormsModule, NgbModule, UtmDashboardSharedModule, - NgxJsonViewerModule + NgxJsonViewerModule, + GraphicBuilderSharedModule ], schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA], entryComponents: [ diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css new file mode 100644 index 000000000..679518bbd --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css @@ -0,0 +1,8 @@ +.editor-container { + height: 80px; +} + +.execution-info { + padding: 12px 0; + border-bottom: 1px solid #e0e6ed; +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html index 140400431..230bca31c 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html @@ -1,52 +1,100 @@
- - + + +
+ + Query name is required. + + + Query name must be at least 10 characters long. + + + Query name must not exceed 200 characters. + +
- - + + +
+ + Query description is required. + + + Query description must not exceed 2000 characters. + +
- - - +
+ + +
+
+ + {{ errorMessage || 'SQL Query is required.'}} + +
-
- - - -
+
+
+ + + +
+ + Evaluation Rule is required. + +
+
-
- - - +
+ + + +
+ + Index Pattern is required. + +
+
- -
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts index d760bc338..954062729 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts @@ -1,87 +1,75 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import {ConsoleOptions} from '../../../../../shared/components/code-editor/code-editor.component'; +import {ALERT_INDEX_PATTERN, LOG_INDEX_PATTERN} from '../../../../../shared/constants/main-index-pattern.constant'; +import {SqlValidationService} from '../../../../../shared/services/code-editor/sql-validation.service'; +import {LocalFieldService} from '../../../../../shared/services/elasticsearch/local-field.service'; import {UtmIndexPattern} from '../../../../../shared/types/index-pattern/utm-index-pattern'; +import {ComplianceEvaluationRuleEnum} from '../../../enums/compliance-evaluation-rule.enum'; import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; -import {HttpResponse} from "@angular/common/http"; -import {IndexPatternService} from "../../../../../shared/services/elasticsearch/index-pattern.service"; @Component({ selector: 'app-utm-compliance-query-form', - templateUrl: './utm-compliance-query-form.component.html' + templateUrl: './utm-compliance-query-form.component.html', + styleUrls: ['./utm-compliance-query-form.component.css'] }) export class UtmComplianceQueryFormComponent implements OnInit { @Input() query: UtmComplianceQueryConfigType = null; - + @Input() indexPatterns: UtmIndexPattern[] = []; + @Input() indexPatternNames: string[] = []; + @Input() formBuilder: FormBuilder; @Output() save = new EventEmitter(); @Output() cancel = new EventEmitter(); form: FormGroup; - pattern: UtmIndexPattern; - patterns: UtmIndexPattern[]; - indexPatternList = []; + evaluationRules = Object.values(ComplianceEvaluationRuleEnum); + + codeEditorOptions: ConsoleOptions = {lineNumbers: 'off'}; + errorMessage = ''; constructor(private fb: FormBuilder, - private indexPatternService: IndexPatternService) {} + private sqlValidationService: SqlValidationService, + private localFieldService: LocalFieldService) {} ngOnInit() { - this.getIndexPatterns('init'); const q = this.query || {}; this.form = this.fb.group({ id: [q.id || null], - name: [q.name || '', Validators.required], - queryDescription: [q.queryDescription || '', Validators.required], - sqlQuery: [q.sqlQuery || '', Validators.required], - evaluationRule: [q.evaluationRule || null, Validators.required], - indexPatternId: [q.indexPatternId || null, Validators.required], + name: [q.name || '', [Validators.required, Validators.minLength(10), Validators.maxLength(200)]], + queryDescription: [q.queryDescription || '', [Validators.required, Validators.maxLength(2000)]], + sqlQuery: [q.sqlQuery || '', [Validators.required]], + evaluationRule: [q.evaluationRule || null, [Validators.required]], + indexPatternId: [q.indexPatternId || null, [Validators.required]], controlConfigId: [q.controlConfigId || null] }); + } submit() { if (this.form.invalid) { return; } + + const sql = this.form.get('sqlQuery').value; + this.errorMessage = this.sqlValidationService.validateSqlQuery(sql); + if (this.errorMessage) { + return; + } + this.save.emit(this.form.value); + this.form.reset(); } cancelEdit() { this.cancel.emit(); } - //TODO: ELENA revisar de aqui para abajo - onIndexPatternChange($event: any) { - this.pattern = $event; - //this.indexPatternChange.emit($event); - } - - getIndexPatterns(init?: string) { - const req = { - page: 0, - size: 1000, - sort: 'id,asc', - 'isActive.equals': true, - }; - this.indexPatternService.query(req).subscribe( - (res: HttpResponse) => this.onSuccess(res.body, res.headers, init), - (res: HttpResponse) => this.onError(res.body) - ); - } - - private onSuccess(data, headers, init) { - this.patterns = data; - this.indexPatternList = this.getListPatterns(); - if (init) { - this.pattern = this.patterns[0]; - } - } - - getListPatterns(){ - return this.patterns.map(pattern => ({ id: pattern.id, name: pattern.pattern, selected: this.pattern.id == pattern.id })); - } - - private onError(error) { - // this.alertService.error(error.error, error.message, null); + loadFieldNames() { + return [ + ...this.localFieldService.getPatternStoredFields(ALERT_INDEX_PATTERN).map(f => f.name), + ...this.localFieldService.getPatternStoredFields(LOG_INDEX_PATTERN).map(f => f.name) + ]; } } diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html index 70bfa2f96..8feb1bfaf 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html @@ -1,44 +1,62 @@
- + - - + - - - - - - - - - - - - +
+
NameDescriptionSQLRuleIndex PatternActions
+ + + + + + + + + - - - - - - - + + + + + + + - - - -
Query NameSQL QueryEvaluation RuleIndex PatternActions
{{ q.name }}{{ q.queryDescription }}{{ q.sqlQuery }}{{ q.evaluationRule }}{{ q.indexPatternId }}
{{ q.name }}{{ q.sqlQuery }}{{ q.evaluationRule }}{{ getIndexPatternName(q.indexPatternId) }} - - -
+ +
+ + + +
+ + + + + + + + + + + +
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss index e24d001bf..78776b420 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss @@ -5,3 +5,7 @@ .table td { vertical-align: middle; } + +.query-container { + overflow: auto; +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts index 4c6dcb337..312f39cd5 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts @@ -1,35 +1,109 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import {HttpResponse} from '@angular/common/http'; +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {IndexPatternService} from '../../../../../shared/services/elasticsearch/index-pattern.service'; +import {UtmIndexPattern} from '../../../../../shared/types/index-pattern/utm-index-pattern'; import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; + @Component({ selector: 'app-utm-compliance-query-list', templateUrl: './utm-compliance-query-list.component.html', styleUrls: ['./utm-compliance-query-list.component.scss'] }) -export class UtmComplianceQueryListComponent { +export class UtmComplianceQueryListComponent implements OnInit { - @Input() queries: UtmComplianceQueryConfigType[] = []; + queries: UtmComplianceQueryConfigType[] = []; @Output() add = new EventEmitter(); @Output() edit = new EventEmitter<{ index: number, query: UtmComplianceQueryConfigType }>(); @Output() delete = new EventEmitter(); + pattern: UtmIndexPattern; + patterns: UtmIndexPattern[]; + indexPatternNames = []; + editingIndex: number = null; + ngOnInit() { + this.getIndexPatterns(); + } + + constructor(private indexPatternService: IndexPatternService) { + + } + startEdit(index: number) { this.editingIndex = index; } finishEdit(query: UtmComplianceQueryConfigType) { - this.edit.emit({ index: this.editingIndex, query }); + if (this.editingIndex !== null && this.queries) { + this.queries[this.editingIndex] = query; + } + this.editingIndex = null; } + cancelEdit() { this.editingIndex = null; } remove(index: number) { - this.delete.emit(index); + this.queries = this.queries.filter((_, i) => i !== index); + } + + onQueryAdd(query: UtmComplianceQueryConfigType): void { + this.queries = [...this.queries, query]; } + + //TODO: ELENA revisar de aqui para abajo + onIndexPatternChange($event: any) { + this.pattern = $event; + //this.indexPatternChange.emit($event); + } + + getIndexPatterns() { + const req = { + page: 0, + size: 1000, + sort: 'id,asc', + 'isActive.equals': true, + }; + this.indexPatternService.query(req).subscribe( + (res: HttpResponse) => this.onSuccess(res.body, res.headers), + (res: HttpResponse) => this.onError(res.body) + ); + } + + private onSuccess(data, headers) { + this.patterns = data; + this.indexPatternNames = this.getListPatterns().map(f => f.name); + } + + getListPatterns() { + return (this.patterns || []) + .filter(pattern => pattern && pattern.id != null) + .map(pattern => ({ + id: pattern.id, + name: pattern.pattern, + })); + } + + private onError(error) { + // this.alertService.error(error.error, error.message, null); + } + + + //TODO: ELENA revisar si puedo reutilizar los nombres + getIndexPatternName(id: number) { + if (!this.patterns || !id) { + return ''; + } + + const pattern = this.patterns.find(p => p.id === id); + return pattern ? pattern.pattern : ''; + } + + } diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html index 06a29fc89..f5fc1b010 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html @@ -4,7 +4,7 @@
- Standard & Section + Report Configuration
@@ -14,7 +14,7 @@
- View select + Queries Configuration
@@ -80,6 +80,11 @@ [loading]="!strategies" class="w-50"> +
+ + Strategy is required. + +
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts index 9aae9158d..6cda4bfcb 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts @@ -21,7 +21,7 @@ import {ComplianceReportType} from '../../type/compliance-report.type'; export class UtmComplianceControlConfigCreateComponent implements OnInit { @Input() report: ComplianceReportConfigType; @Output() reportCreated = new EventEmitter(); - step = 2; + step = 1; stepCompleted: number[] = []; creating = false; viewSection = false; diff --git a/frontend/src/app/shared/components/code-editor/code-editor.component.ts b/frontend/src/app/shared/components/code-editor/code-editor.component.ts index c24804b6e..aae529575 100644 --- a/frontend/src/app/shared/components/code-editor/code-editor.component.ts +++ b/frontend/src/app/shared/components/code-editor/code-editor.component.ts @@ -24,7 +24,8 @@ export interface ConsoleOptions { cursorSmoothCaretAnimation?: 'off' | 'on'; } -const SQL_KEYWORDS = ['CREATE', 'DROP', 'ALTER', 'TRUNCATE', +const SQL_KEYWORDS = [ + 'CREATE', 'DROP', 'ALTER', 'TRUNCATE', 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'COMMIT', 'ROLLBACK', 'AND', 'OR', 'NOT', 'BETWEEN', 'IN', 'LIKE', 'EXISTS', @@ -52,35 +53,36 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces @Input() showFullEditor = true; @Input() showSuggestions = false; @Input() consoleOptions?: ConsoleOptions; - @Output() execute = new EventEmitter(); - @Output() clearData = new EventEmitter(); @Input() queryError: string | null = null; @Input() customKeywords: string[] = []; + @Output() execute = new EventEmitter(); + @Output() clearData = new EventEmitter(); + sqlQuery = ''; errorMessage = ''; successMessage = ''; + + private editorInstance?: monaco.editor.IStandaloneCodeEditor; + private completionProvider?: monaco.IDisposable; + + private onChange = (_: any) => {}; + private onTouched = () => {}; + private updatingFromOutside = false; + readonly defaultOptions: ConsoleOptions = { value: this.sqlQuery, language: 'sql', theme: 'myCustomTheme', - minimap: { - enabled: false - }, + minimap: { enabled: false }, renderLineHighlight: 'none', - scrollbar: { - vertical: 'auto', - horizontal: 'hidden' - }, + scrollbar: { vertical: 'auto', horizontal: 'hidden' }, overviewRulerLanes: 0, wordWrap: 'on', automaticLayout: true, lineNumbers: 'on', cursorSmoothCaretAnimation: 'off' }; - private completionProvider?: monaco.IDisposable; - private onChange = (_: any) => {}; - private onTouched = () => {}; constructor(private sqlValidationService: SqlValidationService) {} @@ -95,7 +97,16 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces } } - onEditorInit(editorInstance: monaco.editor.IStandaloneCodeEditor) { + // ⭐ Se llama cuando Monaco inicializa el editor + onEditorInit(editor: monaco.editor.IStandaloneCodeEditor) { + this.editorInstance = editor; + + // Si el formulario ya tenía un valor, lo mostramos + if (this.sqlQuery) { + editor.setValue(this.sqlQuery); + } + + // Autocompletado this.completionProvider = monaco.languages.registerCompletionItemProvider('sql', { provideCompletionItems: () => { const allKeywords = Array.from(new Set([ @@ -103,24 +114,65 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces ...(this.customKeywords || []) ])); - const suggestions: monaco.languages.CompletionItem[] = allKeywords.map(k => ({ + const suggestions = allKeywords.map(k => ({ label: k, kind: monaco.languages.CompletionItemKind.Text, - insertText: k, + insertText: k })); return { suggestions }; } }); - editorInstance.onDidChangeModelContent(() => { - const val = editorInstance.getValue(); + // ⭐ Captura cambios del usuario + editor.onDidChangeModelContent(() => { + if (this.updatingFromOutside) { + return; + } + + const val = editor.getValue(); this.sqlQuery = val; this.onChange(val); this.onTouched(); }); } + // ⭐ ControlValueAccessor: Angular escribe valores aquí + writeValue(value: any): void { + this.updatingFromOutside = true; + + this.sqlQuery = value || ''; + + if (this.editorInstance) { + this.editorInstance.setValue(this.sqlQuery); + } + + this.updatingFromOutside = false; + } + + registerOnChange(fn: any): void { + this.onChange = fn; + } + + registerOnTouched(fn: any): void { + this.onTouched = fn; + } + + setDisabledState?(isDisabled: boolean): void { + if (this.editorInstance) { + this.editorInstance.updateOptions({ readOnly: isDisabled }); + } + } + + onEditorInput(value: string) { + this.onChange(value); + this.onTouched(); + } + + // ------------------------- + // Funciones adicionales + // ------------------------- + executeQuery(): void { this.clearMessages(); this.errorMessage = this.sqlValidationService.validateSqlQuery(this.sqlQuery); @@ -140,11 +192,16 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces this.sqlQuery = ''; this.clearMessages(); this.clearData.emit(); + this.onChange(''); } formatQuery(): void { this.clearMessages(); this.sqlQuery = this.formatSql(this.sqlQuery); + if (this.editorInstance) { + this.editorInstance.setValue(this.sqlQuery); + } + this.onChange(this.sqlQuery); } private formatSql(sql: string): string { @@ -168,20 +225,4 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces this.errorMessage = ''; this.successMessage = ''; } - - writeValue(value: any): void { - this.sqlQuery = value || ''; - } - - registerOnChange(fn: any): void { - this.onChange = fn; - } - - registerOnTouched(fn: any): void { - this.onTouched = fn; - } - - setDisabledState?(isDisabled: boolean): void { - // Optional: handle disabled state - } } From a2d07e2dc93ea5d7770e3f78a27bb7df3f0a4901 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Sun, 25 Jan 2026 14:24:53 -0600 Subject: [PATCH 012/135] =?UTF-8?q?feat:=20Add=20new=20ControlConfig=20cre?= =?UTF-8?q?ation=20component=20for=20SQL=E2=80=91based=20compliance=20eval?= =?UTF-8?q?uation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utm-compliance-query-form.component.css | 5 -- .../utm-compliance-query-form.component.html | 10 +-- .../utm-compliance-query-form.component.ts | 7 +- .../utm-compliance-query-list.component.html | 15 ++-- .../utm-compliance-query-list.component.ts | 57 ++++++-------- ...iance-control-config-create.component.html | 5 +- ...pliance-control-config-create.component.ts | 67 ++++++++--------- .../services/cp-reports-config.service.ts | 74 +++++++++++++++++++ .../type/compliance-query-config.type.ts | 2 +- .../type/compliance-report-config.type.ts | 8 +- 10 files changed, 150 insertions(+), 100 deletions(-) create mode 100644 frontend/src/app/compliance/shared/services/cp-reports-config.service.ts diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css index 679518bbd..f37095e5c 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css @@ -1,8 +1,3 @@ .editor-container { height: 80px; } - -.execution-info { - padding: 12px 0; - border-bottom: 1px solid #e0e6ed; -} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html index 230bca31c..56a7dd4f2 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html @@ -1,15 +1,15 @@
- -
- + +
+ Query name is required. - + Query name must be at least 10 characters long. - + Query name must not exceed 200 characters.
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts index 954062729..5ac49d4b0 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts @@ -18,8 +18,7 @@ export class UtmComplianceQueryFormComponent implements OnInit { @Input() query: UtmComplianceQueryConfigType = null; @Input() indexPatterns: UtmIndexPattern[] = []; @Input() indexPatternNames: string[] = []; - @Input() formBuilder: FormBuilder; - @Output() save = new EventEmitter(); + @Output() add = new EventEmitter(); @Output() cancel = new EventEmitter(); form: FormGroup; @@ -37,7 +36,7 @@ export class UtmComplianceQueryFormComponent implements OnInit { this.form = this.fb.group({ id: [q.id || null], - name: [q.name || '', [Validators.required, Validators.minLength(10), Validators.maxLength(200)]], + queryName: [q.queryName || '', [Validators.required, Validators.minLength(10), Validators.maxLength(200)]], queryDescription: [q.queryDescription || '', [Validators.required, Validators.maxLength(2000)]], sqlQuery: [q.sqlQuery || '', [Validators.required]], evaluationRule: [q.evaluationRule || null, [Validators.required]], @@ -58,7 +57,7 @@ export class UtmComplianceQueryFormComponent implements OnInit { return; } - this.save.emit(this.form.value); + this.add.emit(this.form.value); this.form.reset(); } diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html index 8feb1bfaf..9349b00e7 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html @@ -1,13 +1,13 @@
@@ -28,8 +28,12 @@ - {{ q.name }} - {{ q.sqlQuery }} + + {{ q.queryName | slice:0:30 }}{{ q.queryName.length > 30 ? '…' : '' }} + + + {{ q.sqlQuery | slice:0:30 }}{{ q.sqlQuery.length > 30 ? '…' : '' }} + {{ q.evaluationRule }} {{ getIndexPatternName(q.indexPatternId) }} @@ -40,7 +44,7 @@ ngbTooltip="Edit visualization" tooltipClass="utm-tooltip-top"> -
-
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts index 312f39cd5..38df0f523 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts @@ -11,56 +11,51 @@ import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-confi styleUrls: ['./utm-compliance-query-list.component.scss'] }) export class UtmComplianceQueryListComponent implements OnInit { + // tslint:disable-next-line:variable-name + private _queries: UtmComplianceQueryConfigType[] = []; + @Input() set queries(value: UtmComplianceQueryConfigType[]) { + this._queries = value || []; + } - queries: UtmComplianceQueryConfigType[] = []; + get queries() { + return this._queries; + } - @Output() add = new EventEmitter(); - @Output() edit = new EventEmitter<{ index: number, query: UtmComplianceQueryConfigType }>(); - @Output() delete = new EventEmitter(); + @Output() add = new EventEmitter<{ + query: UtmComplianceQueryConfigType; + index: number | null; + }>(); + @Output() remove = new EventEmitter(); - pattern: UtmIndexPattern; patterns: UtmIndexPattern[]; indexPatternNames = []; - editingIndex: number = null; + constructor(private indexPatternService: IndexPatternService) {} + ngOnInit() { this.getIndexPatterns(); } - constructor(private indexPatternService: IndexPatternService) { - - } - startEdit(index: number) { this.editingIndex = index; } - finishEdit(query: UtmComplianceQueryConfigType) { - if (this.editingIndex !== null && this.queries) { - this.queries[this.editingIndex] = query; - } - - this.editingIndex = null; - } - - cancelEdit() { this.editingIndex = null; } - remove(index: number) { - this.queries = this.queries.filter((_, i) => i !== index); - } - onQueryAdd(query: UtmComplianceQueryConfigType): void { - this.queries = [...this.queries, query]; + this.add.emit({ + query, + index: this.editingIndex + }); + + this.editingIndex = null; } - //TODO: ELENA revisar de aqui para abajo - onIndexPatternChange($event: any) { - this.pattern = $event; - //this.indexPatternChange.emit($event); + onRemove(index: number) { + this.remove.emit(index); } getIndexPatterns() { @@ -91,11 +86,9 @@ export class UtmComplianceQueryListComponent implements OnInit { } private onError(error) { - // this.alertService.error(error.error, error.message, null); + //this.alertService.error(error.error, error.message, null); } - - //TODO: ELENA revisar si puedo reutilizar los nombres getIndexPatternName(id: number) { if (!this.patterns || !id) { return ''; @@ -104,6 +97,4 @@ export class UtmComplianceQueryListComponent implements OnInit { const pattern = this.patterns.find(p => p.id === id); return pattern ? pattern.pattern : ''; } - - } diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html index f5fc1b010..cc9ef8bb1 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html @@ -92,8 +92,7 @@ + (remove)="onQueryRemove($event)">
@@ -111,7 +110,7 @@
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts index 95e02c26d..1ce10b090 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts @@ -4,9 +4,9 @@ import {NgbActiveModal, NgbModal} from '@ng-bootstrap/ng-bootstrap'; import {UtmToastService} from '../../../../shared/alert/utm-toast.service'; import {CpReportBehavior} from '../../behavior/cp-report.behavior'; import {ComplianceStrategyEnum} from '../../enums/compliance-strategy.enum'; -import {CpReportsConfigService} from '../../services/cp-reports-config.service'; +import {CpControlConfigService} from '../../services/cp-control-config.service'; +import {ComplianceControlConfigType} from '../../type/compliance-control-config.type'; import {UtmComplianceQueryConfigType} from '../../type/compliance-query-config.type'; -import {ComplianceReportConfigType} from '../../type/compliance-report-config.type'; @Component({ selector: 'app-utm-compliance-control-config-create', @@ -14,8 +14,8 @@ import {ComplianceReportConfigType} from '../../type/compliance-report-config.ty styleUrls: ['./utm-compliance-control-config-create.component.scss'] }) export class UtmComplianceControlConfigCreateComponent implements OnInit { - @Input() report: ComplianceReportConfigType; - @Output() reportCreated = new EventEmitter(); + @Input() control: ComplianceControlConfigType; + @Output() controlCreated = new EventEmitter(); step = 1; stepCompleted: number[] = []; @@ -26,7 +26,7 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { standardSectionId: number; strategies = []; - constructor(private cpReportsConfigService: CpReportsConfigService, + constructor(private cpControlConfigService: CpControlConfigService, public activeModal: NgbActiveModal, private cpReportBehavior: CpReportBehavior, private utmToastService: UtmToastService, @@ -36,11 +36,11 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { ngOnInit() { this.complianceForm = this.fb.group({ - reportName: [this.report ? this.report.configReportName : '' , + controlName: [this.control ? this.control.controlName : '' , [Validators.required, Validators.minLength(10), Validators.maxLength(200)]], - solution: [this.report ? this.report.configSolution : '', [Validators.maxLength(2000)]], - remediation: [this.report && this.report.configRemediation ? this.report.configRemediation : '', [Validators.maxLength(2000)]], - strategy: [this.report ? this.report.configStrategy as ComplianceStrategyEnum : null, [Validators.required]], + solution: [this.control ? this.control.controlSolution : '', [Validators.maxLength(2000)]], + remediation: [this.control && this.control.controlRemediation ? this.control.controlRemediation : '', [Validators.maxLength(2000)]], + strategy: [this.control ? this.control.controlStrategy as ComplianceStrategyEnum : null, [Validators.required]], queriesConfigs: this.fb.array([], Validators.minLength(1)) }); @@ -51,9 +51,9 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { }) ); - if (this.report) { + if (this.control) { this.viewSection = true; - this.standardSectionId = this.report.standardSectionId; + this.standardSectionId = this.control.standardSectionId; } } @@ -81,32 +81,32 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { createCompliance() { this.creating = true; - const reportConfigCompliance: ComplianceReportConfigType = { + const controlConfigCompliance: ComplianceControlConfigType = { standardSectionId: this.standardSectionId, - configReportName: this.complianceForm.controls.reportName.value, - configSolution: this.complianceForm.controls.solution.value.replace(/\r?\n/g, '
'), - configRemediation: this.complianceForm.controls.remediation.value.replace(/\r?\n/g, '
'), - configStrategy: this.complianceForm.controls.strategy.value, + controlName: this.complianceForm.controls.controlName.value, + controlSolution: this.complianceForm.controls.solution.value.replace(/\r?\n/g, '
'), + controlRemediation: this.complianceForm.controls.remediation.value.replace(/\r?\n/g, '
'), + controlStrategy: this.complianceForm.controls.strategy.value, queriesConfigs: this.queriesList }; //Edit - if (this.report) { - reportConfigCompliance.id = this.report.id; - this.cpReportsConfigService.update(reportConfigCompliance).subscribe(() => { + if (this.control) { + controlConfigCompliance.id = this.control.id; + this.cpControlConfigService.update(controlConfigCompliance).subscribe(() => { this.utmToastService.showSuccessBottom('Compliance report edited successfully'); this.activeModal.close(); - this.reportCreated.emit('edited'); + this.controlCreated.emit('edited'); }, error1 => { this.creating = false; this.utmToastService.showError('Error', 'Error editing compliance report'); }); } else { - this.cpReportsConfigService.create(reportConfigCompliance).subscribe(() => { + this.cpControlConfigService.create(controlConfigCompliance).subscribe(() => { this.utmToastService.showSuccessBottom('Compliance report created successfully'); this.activeModal.close(); this.cpReportBehavior.$reportUpdate.next('update'); - this.reportCreated.emit('created'); + this.controlCreated.emit('created'); }, error1 => { this.creating = false; this.utmToastService.showError('Error', 'Error creating compliance report'); diff --git a/frontend/src/app/compliance/shared/services/cp-reports-config.service.ts b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts similarity index 60% rename from frontend/src/app/compliance/shared/services/cp-reports-config.service.ts rename to frontend/src/app/compliance/shared/services/cp-control-config.service.ts index e975c0e95..e6cf8fa9e 100644 --- a/frontend/src/app/compliance/shared/services/cp-reports-config.service.ts +++ b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts @@ -4,7 +4,7 @@ import {BehaviorSubject, Observable} from 'rxjs'; import {SERVER_API_URL} from '../../../app.constants'; import {RefreshDataService} from '../../../shared/services/util/refresh-data.service'; import {createRequestOption} from '../../../shared/util/request-util'; -import {ComplianceReportConfigType} from '../type/compliance-report-config.type'; +import {ComplianceControlConfigType} from '../type/compliance-control-config.type'; import {ComplianceReportType} from '../type/compliance-report.type'; export interface ReportParams { @@ -16,7 +16,7 @@ export interface ReportParams { @Injectable({ providedIn: 'root' }) -export class CpReportsConfigService extends RefreshDataService<{ sectionId: number, +export class CpControlConfigService extends RefreshDataService<{ sectionId: number, loading: boolean, reportSelected: number, page?: number }, HttpResponse> { private resourceUrl = SERVER_API_URL + 'api/compliance/control-config'; @@ -27,37 +27,37 @@ export class CpReportsConfigService extends RefreshDataService<{ sectionId: numb super(); } - create(report: ComplianceReportConfigType): Observable> { - return this.http.post(this.resourceUrl, report, {observe: 'response'}); + create(control: ComplianceControlConfigType): Observable> { + return this.http.post(this.resourceUrl, control, {observe: 'response'}); } import(reports: { override: boolean - reports: ComplianceReportConfigType[] + reports: ComplianceControlConfigType[] }): Observable> { - return this.http.post(this.resourceUrl + '/import', reports, {observe: 'response'}); + return this.http.post(this.resourceUrl + '/import', reports, {observe: 'response'}); } - update(report: ComplianceReportConfigType): Observable> { - return this.http.put(this.resourceUrl, report, {observe: 'response'}); + update(control: ComplianceControlConfigType): Observable> { + return this.http.put(this.resourceUrl, control, {observe: 'response'}); } - find(report: number): Observable> { - return this.http.get(`${this.resourceUrl}/${report}`, {observe: 'response'}); + find(control: number): Observable> { + return this.http.get(`${this.resourceUrl}/${control}`, {observe: 'response'}); } - query(req?: any): Observable> { + query(req?: any): Observable> { const options = createRequestOption(req); - return this.http.get(this.resourceUrl, { + return this.http.get(this.resourceUrl, { params: options, observe: 'response' }); } // GET /api/compliance/report-config/get-by-report - queryByStandard(req?: any): Observable> { + queryByStandard(req?: any): Observable> { const options = createRequestOption(req); - return this.http.get(this.resourceUrl + '/get-by-filters', { + return this.http.get(this.resourceUrl + '/get-by-filters', { params: options, observe: 'response' }); diff --git a/frontend/src/app/compliance/shared/type/compliance-report-config.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-config.type.ts similarity index 75% rename from frontend/src/app/compliance/shared/type/compliance-report-config.type.ts rename to frontend/src/app/compliance/shared/type/compliance-control-config.type.ts index ed1d3c1a3..e15fd57b3 100644 --- a/frontend/src/app/compliance/shared/type/compliance-report-config.type.ts +++ b/frontend/src/app/compliance/shared/type/compliance-control-config.type.ts @@ -4,14 +4,14 @@ import {UtmComplianceQueryConfigType} from './compliance-query-config.type'; import {ComplianceStandardSectionType} from './compliance-standard-section.type'; -export class ComplianceReportConfigType { +export class ComplianceControlConfigType { id?: number; section?: ComplianceStandardSectionType; standardSectionId?: number; - configReportName?: string; - configSolution?: string; - configRemediation?: string; - configStrategy?: ComplianceStrategyEnum; + controlName?: string; + controlSolution?: string; + controlRemediation?: string; + controlStrategy?: ComplianceStrategyEnum; queriesConfigs?: UtmComplianceQueryConfigType[]; columns?: UtmFieldType[]; From 6bad1687e09813efcdb473008bf44bcb38458ec5 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Tue, 27 Jan 2026 11:42:05 -0600 Subject: [PATCH 014/135] =?UTF-8?q?feat:=20Add=20new=20ControlConfig=20cre?= =?UTF-8?q?ation=20component=20for=20SQL=E2=80=91based=20compliance=20eval?= =?UTF-8?q?uation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compliance-management.module.ts | 14 ++- .../cp-standard-management.component.html | 4 +- ...tm-cp-control-config-delete.component.html | 23 +++++ ...tm-cp-control-config-delete.component.scss | 0 .../utm-cp-control-config-delete.component.ts | 36 ++++++++ .../utm-cp-control-config.component.html | 56 +++++++++++ .../utm-cp-control-config.component.scss | 5 + .../utm-cp-control-config.component.ts | 92 +++++++++++++++++++ .../utm-compliance-query-form.component.html | 22 +++++ .../utm-compliance-query-form.component.ts | 19 +++- ...iance-control-config-create.component.html | 4 +- ...pliance-control-config-create.component.ts | 5 +- .../services/cp-control-config.service.ts | 58 ++++++++---- .../type/compliance-query-config.type.ts | 1 + .../code-editor/code-editor.component.ts | 19 +--- 15 files changed, 314 insertions(+), 44 deletions(-) create mode 100644 frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.html create mode 100644 frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.scss create mode 100644 frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.ts create mode 100644 frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.html create mode 100644 frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.scss create mode 100644 frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.ts diff --git a/frontend/src/app/compliance/compliance-management/compliance-management.module.ts b/frontend/src/app/compliance/compliance-management/compliance-management.module.ts index 9310dc4bf..32dd9c7cd 100644 --- a/frontend/src/app/compliance/compliance-management/compliance-management.module.ts +++ b/frontend/src/app/compliance/compliance-management/compliance-management.module.ts @@ -9,6 +9,10 @@ import {InputClassResolve} from '../../shared/util/input-class-resolve'; import {UtmSharedModule} from '../../shared/utm-shared.module'; import {ComplianceSharedModule} from '../shared/compliance-shared.module'; import {CpStandardManagementComponent} from './cp-standard-management/cp-standard-management.component'; +import { + UtmCpControlConfigDeleteComponent +} from './utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component'; +import {UtmCpControlConfigComponent} from './utm-cp-control-config/utm-cp-control-config.component'; import {UtmCpExportComponent} from './utm-cp-export/utm-cp-export.component'; import {UtmCpImportComponent} from './utm-cp-import/utm-cp-import.component'; import {UtmCpReportDeleteComponent} from './utm-cp-reports/utm-cp-report-delete/utm-cp-report-delete.component'; @@ -19,6 +23,8 @@ import {UtmCpStandardSectionComponent} from './utm-cp-standard-section/utm-cp-st import {UtmCpStandardDeleteComponent} from './utm-cp-standard/utm-cp-standard-delete/utm-cp-standard-delete.component'; import {UtmCpStandardComponent} from './utm-cp-standard/utm-cp-standard.component'; + + @NgModule({ declarations: [ CpStandardManagementComponent, @@ -29,13 +35,17 @@ import {UtmCpStandardComponent} from './utm-cp-standard/utm-cp-standard.componen UtmCpReportsComponent, UtmCpReportDeleteComponent, UtmCpExportComponent, - UtmCpImportComponent], + UtmCpImportComponent, + UtmCpControlConfigComponent, + UtmCpControlConfigDeleteComponent], entryComponents: [ UtmCpReportDeleteComponent, UtmCpStandardDeleteComponent, UtmCpStandardSectionDeleteComponent, UtmCpExportComponent, - UtmCpImportComponent], + UtmCpImportComponent, + UtmCpControlConfigDeleteComponent + ], exports: [CpStandardManagementComponent, UtmCpStandardComponent], providers: [InputClassResolve], schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA], diff --git a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.html b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.html index 080fcc790..14db54fec 100644 --- a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.html +++ b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.html @@ -33,7 +33,9 @@
Compliance management
- + + +
diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.html b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.html new file mode 100644 index 000000000..e675c1f15 --- /dev/null +++ b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.html @@ -0,0 +1,23 @@ + +
+
+ Warning! + This action cant not be undone +
+
+ Are you sure that you want to delete standard section: + {{control.controlName|slice:0:50}}.? +
+ +
+ + +
+
diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.scss b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.ts b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.ts new file mode 100644 index 000000000..99821b175 --- /dev/null +++ b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.ts @@ -0,0 +1,36 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; +import {UtmToastService} from '../../../../shared/alert/utm-toast.service'; +import {CpControlConfigService} from '../../../shared/services/cp-control-config.service'; +import {ComplianceControlConfigType} from '../../../shared/type/compliance-control-config.type'; + +@Component({ + selector: 'app-utm-cp-control-config-delete', + templateUrl: './utm-cp-control-config-delete.component.html', + styleUrls: ['./utm-cp-control-config-delete.component.scss'] +}) +export class UtmCpControlConfigDeleteComponent implements OnInit { + @Input() control: ComplianceControlConfigType; + @Output() controlDelete = new EventEmitter(); + + constructor(public activeModal: NgbActiveModal, + private utmToastService: UtmToastService, + private cpControlConfigService: CpControlConfigService) { + } + + ngOnInit() { + + } + + deleteControl() { + this.cpControlConfigService.delete(this.control.id) + .subscribe(() => { + this.utmToastService.showSuccessBottom('Control deleted successfully'); + this.activeModal.close(); + this.controlDelete.emit('deleted'); + }, (error) => { + this.utmToastService.showError('Error deleting control', + error.error.statusText); + }); + } +} diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.html b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.html new file mode 100644 index 000000000..545edabfe --- /dev/null +++ b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.html @@ -0,0 +1,56 @@ +
+
+ {{section.standardSectionName}} +
+ +
+ + +
+
+ +
+
+ +
+
diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.scss b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.scss new file mode 100644 index 000000000..2b328118f --- /dev/null +++ b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.scss @@ -0,0 +1,5 @@ +.report-container { + max-height: 85vh !important; + overflow-y: auto; + overflow-x: hidden; +} diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.ts b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.ts new file mode 100644 index 000000000..7e0ce48fb --- /dev/null +++ b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.ts @@ -0,0 +1,92 @@ +import {Component, isDevMode, OnInit} from '@angular/core'; +import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {CpReportBehavior} from '../../shared/behavior/cp-report.behavior'; +import {CpStandardSectionBehavior} from '../../shared/behavior/cp-standard-section.behavior'; +import { + UtmComplianceControlConfigCreateComponent +} from '../../shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component'; +import {CpControlConfigService} from '../../shared/services/cp-control-config.service'; +import {ComplianceControlConfigType} from '../../shared/type/compliance-control-config.type'; +import {ComplianceStandardSectionType} from '../../shared/type/compliance-standard-section.type'; +import {UtmCpControlConfigDeleteComponent} from './utm-cp-control-config-delete/utm-cp-control-config-delete.component'; + +@Component({ + selector: 'app-utm-cp-control-config', + templateUrl: './utm-cp-control-config.component.html', + styleUrls: ['./utm-cp-control-config.component.scss'] +}) +export class UtmCpControlConfigComponent implements OnInit { + section: ComplianceStandardSectionType; + complianceControls: ComplianceControlConfigType[] = []; + loadingTemplates = true; + page = 1; + solution: string; + showDetailFor = 0; + isDevMode = isDevMode; + + constructor(private cpControlConfigService: CpControlConfigService, + public cpStandardSectionBehavior: CpStandardSectionBehavior, + private cpReportBehavior: CpReportBehavior, + private modalService: NgbModal) { + } + + ngOnInit() { + this.cpStandardSectionBehavior.$standardSection.subscribe(section => { + if (section) { + this.section = section; + this.getControls(); + } else { + this.complianceControls = []; + this.section = null; + this.loadingTemplates = false; + } + }); + + this.cpReportBehavior.$reportUpdate.subscribe(update => { + if (update) { + this.getControls(); + } + }); + + } + + getControls() { + const query = { + page: this.page - 1, + size: 1000, + sort: 'id,asc', + 'standardSectionId.equals': this.section.id, + 'configSolution.contains': this.solution + }; + this.complianceControls = []; + this.cpControlConfigService.query(query).subscribe(response => { + this.complianceControls = response.body; + this.loadingTemplates = false; + }); + } + + onSearchFor($event: string) { + this.solution = $event; + this.getControls(); + } + + deleteControl(control: ComplianceControlConfigType) { + const modal = this.modalService.open(UtmCpControlConfigDeleteComponent, {centered: true}); + modal.componentInstance.control = control; + modal.componentInstance.controlDelete.subscribe(() => { + this.getControls(); + }); + } + + editControl(control: ComplianceControlConfigType) { + const controlModal = this.modalService.open(UtmComplianceControlConfigCreateComponent, {centered: true, size: 'lg'}); + controlModal.componentInstance.control = control; + controlModal.componentInstance.controlCreated.subscribe(() => { + this.getControls(); + }); + } + + toggleDetail(id: number) { + this.showDetailFor = this.showDetailFor === id ? 0 : id; + } +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html index 56a7dd4f2..f9f63d117 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html @@ -84,6 +84,28 @@
+
+ + +
+ + Rule value is required. + + + Rule value must be greater than 0. + + + Rule value must be a positive integer. + +
+
+ +
-
+
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts index 1ce10b090..45bade259 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts @@ -17,6 +17,7 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { @Input() control: ComplianceControlConfigType; @Output() controlCreated = new EventEmitter(); + loading = true; step = 1; stepCompleted: number[] = []; creating = false; @@ -41,7 +42,7 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { solution: [this.control ? this.control.controlSolution : '', [Validators.maxLength(2000)]], remediation: [this.control && this.control.controlRemediation ? this.control.controlRemediation : '', [Validators.maxLength(2000)]], strategy: [this.control ? this.control.controlStrategy as ComplianceStrategyEnum : null, [Validators.required]], - queriesConfigs: this.fb.array([], Validators.minLength(1)) + queriesConfigs: this.fb.array(this.control ? this.control.queriesConfigs : [], [Validators.minLength(1)]) }); this.strategies = Object.keys(ComplianceStrategyEnum).map( @@ -55,6 +56,7 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { this.viewSection = true; this.standardSectionId = this.control.standardSectionId; } + this.loading = false; } backStep() { @@ -90,7 +92,6 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { queriesConfigs: this.queriesList }; - //Edit if (this.control) { controlConfigCompliance.id = this.control.id; this.cpControlConfigService.update(controlConfigCompliance).subscribe(() => { diff --git a/frontend/src/app/compliance/shared/services/cp-control-config.service.ts b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts index e6cf8fa9e..15c2d0aeb 100644 --- a/frontend/src/app/compliance/shared/services/cp-control-config.service.ts +++ b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts @@ -28,33 +28,55 @@ export class CpControlConfigService extends RefreshDataService<{ sectionId: numb } create(control: ComplianceControlConfigType): Observable> { - return this.http.post(this.resourceUrl, control, {observe: 'response'}); + return this.http.post( + this.resourceUrl, + control, + {observe: 'response'}); } - import(reports: { - override: boolean - reports: ComplianceControlConfigType[] - }): Observable> { - return this.http.post(this.resourceUrl + '/import', reports, {observe: 'response'}); + query(req?: any): Observable> { + const options = createRequestOption(req); + return this.http.get(this.resourceUrl, { + params: options, + observe: 'response' + }); } + update(control: ComplianceControlConfigType): Observable> { - return this.http.put(this.resourceUrl, control, {observe: 'response'}); + return this.http.put( + `${this.resourceUrl}/${control.id}`, + control, + { observe: 'response' } + ); } - find(control: number): Observable> { - return this.http.get(`${this.resourceUrl}/${control}`, {observe: 'response'}); + delete(control: number): Observable> { + return this.http.delete( + `${this.resourceUrl}/${control}`, + {observe: 'response'} + ); } - query(req?: any): Observable> { - const options = createRequestOption(req); - return this.http.get(this.resourceUrl, { - params: options, - observe: 'response' - }); + + //TODO: ELENA revisar el uso de estos de abajo + import(control: { + override: boolean + reports: ComplianceControlConfigType[] + }): Observable> { + return this.http.post( + this.resourceUrl + '/import', + control, {observe: 'response'} + ); + } + + find(control: number): Observable> { + return this.http.get( + `${this.resourceUrl}/${control}`, + {observe: 'response'} + ); } - // GET /api/compliance/report-config/get-by-report queryByStandard(req?: any): Observable> { const options = createRequestOption(req); return this.http.get(this.resourceUrl + '/get-by-filters', { @@ -63,10 +85,6 @@ export class CpControlConfigService extends RefreshDataService<{ sectionId: numb }); } - delete(report: number): Observable> { - return this.http.delete(`${this.resourceUrl}/${report}`, {observe: 'response'}); - } - fetchData(request: any): Observable> { return this.queryByStandard(request); } diff --git a/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts b/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts index db3f836f1..21225d632 100644 --- a/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts +++ b/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts @@ -6,6 +6,7 @@ export class UtmComplianceQueryConfigType { queryDescription?: string; sqlQuery?: string; evaluationRule?: ComplianceEvaluationRuleEnum; + ruleValue?: number; indexPatternId?: number; controlConfigId?: number; } diff --git a/frontend/src/app/shared/components/code-editor/code-editor.component.ts b/frontend/src/app/shared/components/code-editor/code-editor.component.ts index aae529575..b4c20571d 100644 --- a/frontend/src/app/shared/components/code-editor/code-editor.component.ts +++ b/frontend/src/app/shared/components/code-editor/code-editor.component.ts @@ -66,8 +66,6 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces private editorInstance?: monaco.editor.IStandaloneCodeEditor; private completionProvider?: monaco.IDisposable; - private onChange = (_: any) => {}; - private onTouched = () => {}; private updatingFromOutside = false; readonly defaultOptions: ConsoleOptions = { @@ -90,6 +88,9 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces this.consoleOptions = { ...this.defaultOptions, ...this.consoleOptions }; } + private onChange = (_: any) => {}; + private onTouched = () => {}; + ngOnDestroy(): void { if (this.completionProvider) { this.completionProvider.dispose(); @@ -97,16 +98,13 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces } } - // ⭐ Se llama cuando Monaco inicializa el editor onEditorInit(editor: monaco.editor.IStandaloneCodeEditor) { this.editorInstance = editor; - // Si el formulario ya tenía un valor, lo mostramos if (this.sqlQuery) { editor.setValue(this.sqlQuery); } - // Autocompletado this.completionProvider = monaco.languages.registerCompletionItemProvider('sql', { provideCompletionItems: () => { const allKeywords = Array.from(new Set([ @@ -124,7 +122,6 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces } }); - // ⭐ Captura cambios del usuario editor.onDidChangeModelContent(() => { if (this.updatingFromOutside) { return; @@ -137,7 +134,6 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces }); } - // ⭐ ControlValueAccessor: Angular escribe valores aquí writeValue(value: any): void { this.updatingFromOutside = true; @@ -164,15 +160,6 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces } } - onEditorInput(value: string) { - this.onChange(value); - this.onTouched(); - } - - // ------------------------- - // Funciones adicionales - // ------------------------- - executeQuery(): void { this.clearMessages(); this.errorMessage = this.sqlValidationService.validateSqlQuery(this.sqlQuery); From 6f93bfd596171ffe482a2e1bac1c2c32b9b78753 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Tue, 27 Jan 2026 14:10:30 -0600 Subject: [PATCH 015/135] =?UTF-8?q?feat:=20Add=20new=20ControlConfig=20cre?= =?UTF-8?q?ation=20component=20for=20SQL=E2=80=91based=20compliance=20eval?= =?UTF-8?q?uation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utm-compliance-query-form.component.html | 24 ++----------------- .../utm-compliance-query-form.component.ts | 15 ++++++++++++ .../code-editor/code-editor.component.ts | 17 +++++++------ 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html index f9f63d117..947667ca6 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html @@ -35,7 +35,8 @@ [showFullEditor]="false" formControlName="sqlQuery" [consoleOptions]="codeEditorOptions" - [customKeywords]="loadFieldNames().concat(indexPatternNames)"> + [customKeywords]="loadFieldNames().concat(indexPatternNames)" + (indexPatternChange)="indexPatternSelected($event)">
@@ -61,27 +62,6 @@
- -
- - - -
- - Index Pattern is required. - -
-
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts index 984daaebc..13f48236f 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts @@ -88,4 +88,19 @@ export class UtmComplianceQueryFormComponent implements OnInit { ...this.localFieldService.getPatternStoredFields(LOG_INDEX_PATTERN).map(f => f.name) ]; } + + indexPatternSelected(event: any) { + const selected = this.indexPatterns.find(p => p.pattern === event); + if (selected) { + this.form.get('indexPatternId').setValue(selected.id); + this.errorMessage = ''; + this.form.get('indexPatternId').markAsPristine(); + this.form.get('indexPatternId').markAsUntouched(); + + } else { + this.errorMessage = 'Invalid index pattern.'; + this.form.get('indexPatternId').setValue(''); + this.form.get('indexPatternId').markAsDirty(); + } + } } diff --git a/frontend/src/app/shared/components/code-editor/code-editor.component.ts b/frontend/src/app/shared/components/code-editor/code-editor.component.ts index c1db4d36a..d479a485a 100644 --- a/frontend/src/app/shared/components/code-editor/code-editor.component.ts +++ b/frontend/src/app/shared/components/code-editor/code-editor.component.ts @@ -73,9 +73,14 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces value: this.sqlQuery, language: 'sql', theme: 'myCustomTheme', - minimap: { enabled: false }, + minimap: { + enabled: false + }, renderLineHighlight: 'none', - scrollbar: { vertical: 'auto', horizontal: 'hidden' }, + scrollbar: { + vertical: 'auto', + horizontal: 'hidden' + }, overviewRulerLanes: 0, wordWrap: 'on', automaticLayout: true, @@ -113,7 +118,7 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces ...(this.customKeywords || []) ])); - const suggestions = allKeywords.map(k => ({ + const suggestions: monaco.languages.CompletionItem[] = allKeywords.map(k => ({ label: k, kind: monaco.languages.CompletionItemKind.Text, insertText: k @@ -210,6 +215,7 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces } clearMessages(): void { + this.extractIndexPattern(this.sqlQuery); this.errorMessage = ''; this.successMessage = ''; } @@ -238,10 +244,7 @@ export class CodeEditorComponent implements OnInit, OnDestroy, ControlValueAcces if (originalFragment.length > 0) { const indexPatternSelected = this.customKeywords.find(keyword => keyword === originalFragment); - - if (indexPatternSelected) { - this.indexPatternChange.emit(indexPatternSelected); - } + this.indexPatternChange.emit(indexPatternSelected ? indexPatternSelected : null); } } } From 49ff25c5de4e19c269c0ff37a55a2a767967d5fb Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Tue, 27 Jan 2026 14:17:30 -0600 Subject: [PATCH 016/135] =?UTF-8?q?feat:=20Add=20new=20ControlConfig=20cre?= =?UTF-8?q?ation=20component=20for=20SQL=E2=80=91based=20compliance=20eval?= =?UTF-8?q?uation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cp-standard-management.component.html | 2 +- .../cp-standard-management.component.ts | 1 + .../services/cp-control-config.service.ts | 29 +------------------ 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.html b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.html index 14db54fec..6d2cd85df 100644 --- a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.html +++ b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.html @@ -33,7 +33,7 @@
Compliance management
- +
diff --git a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts index 9d055aa63..72bf0f2db 100644 --- a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts +++ b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts @@ -51,6 +51,7 @@ export class CpStandardManagementComponent implements OnInit { }); } + //TODO: ELENA to be checked newCompliance() { //this.modalService.open(UtmComplianceCreateComponent, {centered: true}); this.modalService.open(UtmComplianceControlConfigCreateComponent, {centered: true, size: 'lg'}); diff --git a/frontend/src/app/compliance/shared/services/cp-control-config.service.ts b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts index 15c2d0aeb..2ef16b069 100644 --- a/frontend/src/app/compliance/shared/services/cp-control-config.service.ts +++ b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts @@ -1,18 +1,12 @@ import {HttpClient, HttpResponse} from '@angular/common/http'; import {Injectable} from '@angular/core'; -import {BehaviorSubject, Observable} from 'rxjs'; +import {Observable} from 'rxjs'; import {SERVER_API_URL} from '../../../app.constants'; import {RefreshDataService} from '../../../shared/services/util/refresh-data.service'; import {createRequestOption} from '../../../shared/util/request-util'; import {ComplianceControlConfigType} from '../type/compliance-control-config.type'; import {ComplianceReportType} from '../type/compliance-report.type'; -export interface ReportParams { - template: ComplianceReportType; - sectionId: number; - standardId: number; -} - @Injectable({ providedIn: 'root' }) @@ -20,8 +14,6 @@ export class CpControlConfigService extends RefreshDataService<{ sectionId: numb loading: boolean, reportSelected: number, page?: number }, HttpResponse> { private resourceUrl = SERVER_API_URL + 'api/compliance/control-config'; - private loadReportSubject = new BehaviorSubject(null); - private onLoadReportNoteSubject = new BehaviorSubject(null); constructor(private http: HttpClient) { super(); @@ -58,25 +50,6 @@ export class CpControlConfigService extends RefreshDataService<{ sectionId: numb ); } - - //TODO: ELENA revisar el uso de estos de abajo - import(control: { - override: boolean - reports: ComplianceControlConfigType[] - }): Observable> { - return this.http.post( - this.resourceUrl + '/import', - control, {observe: 'response'} - ); - } - - find(control: number): Observable> { - return this.http.get( - `${this.resourceUrl}/${control}`, - {observe: 'response'} - ); - } - queryByStandard(req?: any): Observable> { const options = createRequestOption(req); return this.http.get(this.resourceUrl + '/get-by-filters', { From f36a597434a8c8e2242417a4ca79f4ac05877d7f Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 16 Jan 2026 18:56:42 -0600 Subject: [PATCH 017/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../compliance/UtmComplianceControlConfigRepository.java | 6 +++++- .../compliance/UtmComplianceQueryConfigRepository.java | 4 +--- .../config/UtmComplianceControlConfigService.java | 9 ++++++--- .../config/UtmComplianceQueryConfigService.java | 4 ---- .../config/UtmComplianceControlConfigResource.java | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java index b48ae1831..751d000f1 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java @@ -2,11 +2,15 @@ import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; @Repository public interface UtmComplianceControlConfigRepository extends JpaRepository { - + @Query(" SELECT c FROM UtmComplianceControlConfig c LEFT JOIN FETCH c.queriesConfigs WHERE c.id = :id") + Optional findByIdWithQueries(@Param("id") Long id); } diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java index e583464c7..43f11723e 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java @@ -9,6 +9,4 @@ @Repository public interface UtmComplianceQueryConfigRepository extends JpaRepository { - List findByControlConfigId(Long controlConfigId); -} - +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 14febd6ce..96e91e9db 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -69,10 +69,13 @@ public void delete(Long id) { repository.deleteById(id); } - public UtmComplianceControlConfig findById(Long id) { - return repository.findById(id).orElse(null); + public UtmComplianceControlConfigDto findById(Long id) { + var entity = repository.findByIdWithQueries(id) + .orElseThrow(() -> new RuntimeException("Control not found")); + + return mapper.toDto(entity); } - + public List findAll() { return repository.findAll(); } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java index 199fa07d8..6114e2452 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java @@ -23,8 +23,4 @@ public void delete(Long id) { repository.deleteById(id); } - public List findByControlConfigId(Long controlId) { - return repository.findByControlConfigId((controlId)); - } - } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java index a917f5eb3..298f52136 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -35,7 +35,7 @@ public ResponseEntity getControl(@PathVariable Lo if (entity == null) { return ResponseEntity.notFound().build(); } - return ResponseEntity.ok(controlMapper.toDto(entity)); + return ResponseEntity.ok(entity); } @PutMapping("/{id}") From 3a27ff1170d775ffb5edbb4650428b69365acabd Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 16 Jan 2026 21:31:37 -0600 Subject: [PATCH 018/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../compliance/UtmComplianceQueryConfig.java | 9 +- .../UtmComplianceControlConfigService.java | 33 ++++--- .../UtmComplianceControlConfigMapper.java | 5 +- .../UtmComplianceQueryConfigMapper.java | 8 +- ...create_table_compliance_control_config.xml | 89 +++++++++-------- ...2_create_table_compliance_query_config.xml | 97 +++++++++++-------- 6 files changed, 133 insertions(+), 108 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java index 1d0cec61f..e20f4c6b3 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java @@ -49,12 +49,7 @@ public class UtmComplianceQueryConfig implements Serializable { ) private UtmIndexPattern indexPattern; - @Column(name = "control_config_id") - private Long controlConfigId; - - @ManyToOne @JoinColumn(name = "control_config_id", - insertable = false, - updatable = false - ) + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "control_config_id", nullable = false) private UtmComplianceControlConfig controlConfig; } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 96e91e9db..d7a64cfef 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -1,6 +1,7 @@ package com.park.utmstack.service.compliance.config; import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; +import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; import com.park.utmstack.repository.compliance.UtmComplianceControlConfigRepository; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; @@ -8,8 +9,9 @@ import org.springframework.stereotype.Service; import javax.transaction.Transactional; -import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service public class UtmComplianceControlConfigService { @@ -29,13 +31,10 @@ public UtmComplianceControlConfigService(UtmComplianceControlConfigRepository re @Transactional public UtmComplianceControlConfigDto create(UtmComplianceControlConfigDto dto) { UtmComplianceControlConfig entity = mapper.toEntity(dto); - entity.setQueriesConfigs(new ArrayList<>()); - - entity = repository.save(entity); for (var qdto : dto.getQueriesConfigs()) { var q = queryMapper.toEntity(qdto); - q.setControlConfigId(entity.getId()); + q.setControlConfig(entity); entity.getQueriesConfigs().add(q); } @@ -44,24 +43,32 @@ public UtmComplianceControlConfigDto create(UtmComplianceControlConfigDto dto) { return mapper.toDto(entity); } - @Transactional public UtmComplianceControlConfigDto update(Long id, UtmComplianceControlConfigDto dto) { - UtmComplianceControlConfig entity = repository.findById(id) + UtmComplianceControlConfig entity = repository.findByIdWithQueries(id) .orElseThrow(() -> new RuntimeException("Control not found")); mapper.updateEntity(entity, dto); + + Map existing = entity.getQueriesConfigs() + .stream() + .collect(Collectors.toMap(UtmComplianceQueryConfig::getId, q -> q)); + entity.getQueriesConfigs().clear(); for (var qdto : dto.getQueriesConfigs()) { - var q = queryMapper.toEntity(qdto); - q.setControlConfigId(id); - entity.getQueriesConfigs().add(q); + if (qdto.getId() != null && existing.containsKey(qdto.getId())) { + var q = existing.get(qdto.getId()); + queryMapper.updateEntity(q, qdto); + q.setControlConfig(entity); + entity.getQueriesConfigs().add(q); + } else { + var q = queryMapper.toEntity(qdto); + q.setControlConfig(entity); + entity.getQueriesConfigs().add(q); + } } - - entity = repository.save(entity); - return mapper.toDto(entity); } diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java index 10f6002f0..65f0d7788 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java @@ -9,11 +9,12 @@ @Mapper(componentModel = "spring", uses = UtmComplianceQueryConfigMapper.class) public interface UtmComplianceControlConfigMapper { + @Mapping(target = "queriesConfigs", ignore = true) UtmComplianceControlConfig toEntity(UtmComplianceControlConfigDto dto); UtmComplianceControlConfigDto toDto(UtmComplianceControlConfig entity); @Mapping(target = "id", ignore = true) - void updateEntity(@MappingTarget UtmComplianceControlConfig entity, UtmComplianceControlConfigDto dto - ); + @Mapping(target = "queriesConfigs", ignore = true) + void updateEntity(@MappingTarget UtmComplianceControlConfig entity, UtmComplianceControlConfigDto dto); } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java index 450f91e3c..62fd44223 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java @@ -4,11 +4,17 @@ import com.park.utmstack.service.dto.compliance.UtmComplianceQueryConfigDto; import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; @Mapper(componentModel = "spring") public interface UtmComplianceQueryConfigMapper { - + @Mapping(target = "controlConfig", ignore = true) UtmComplianceQueryConfig toEntity(UtmComplianceQueryConfigDto dto); + @Mapping(target = "controlConfigId", source = "controlConfig.id") UtmComplianceQueryConfigDto toDto(UtmComplianceQueryConfig entity); + + @Mapping(target = "id", ignore = true) + @Mapping(target = "controlConfig", ignore = true) + void updateEntity(@MappingTarget UtmComplianceQueryConfig entity, UtmComplianceQueryConfigDto dto); } \ No newline at end of file diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml index 6baace35d..b898c6e0f 100644 --- a/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml +++ b/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml @@ -2,49 +2,48 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog + http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml index 080ebe6b8..6fe468add 100644 --- a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml +++ b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml @@ -2,47 +2,64 @@ + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog + http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c2ca1ad173b5e320dc74f9675ba942fef986740c Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Mon, 26 Jan 2026 18:52:17 -0600 Subject: [PATCH 019/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../compliance/UtmComplianceQueryConfig.java | 5 ++ .../compliance/enums/ComplianceStrategy.java | 3 +- .../compliance/enums/EvaluationRule.java | 8 +-- .../UtmComplianceControlConfigRepository.java | 4 +- ...tmComplianceControlConfigQueryService.java | 65 +++++++++++++++++++ .../UtmComplianceControlConfigService.java | 1 + .../UtmComplianceQueryConfigService.java | 26 -------- .../compliance/ComplianceStrategyFilter.java | 9 +++ .../UtmComplianceControlConfigCriteria.java | 17 +++++ .../UtmComplianceQueryConfigDto.java | 1 + .../UtmComplianceControlConfigResource.java | 54 +++++++++++++-- ...2_create_table_compliance_query_config.xml | 4 +- 12 files changed, 157 insertions(+), 40 deletions(-) create mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigQueryService.java delete mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/ComplianceStrategyFilter.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigCriteria.java diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java index e20f4c6b3..cfcdddf89 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java @@ -25,6 +25,11 @@ public class UtmComplianceQueryConfig implements Serializable { @GeneratedValue(generator = "CustomIdentityGenerator") private Long id; + @Column(name = "query_name", + columnDefinition = "TEXT" + ) + private String queryName; + @Column(name = "query_description", columnDefinition = "TEXT" ) diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/enums/ComplianceStrategy.java b/backend/src/main/java/com/park/utmstack/domain/compliance/enums/ComplianceStrategy.java index ff0a6a967..f76c56de6 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/enums/ComplianceStrategy.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/enums/ComplianceStrategy.java @@ -2,6 +2,5 @@ public enum ComplianceStrategy { ALL, - ANY, - MAJORITY + ANY } diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/enums/EvaluationRule.java b/backend/src/main/java/com/park/utmstack/domain/compliance/enums/EvaluationRule.java index f60138409..3019c82ea 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/enums/EvaluationRule.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/enums/EvaluationRule.java @@ -1,8 +1,8 @@ package com.park.utmstack.domain.compliance.enums; public enum EvaluationRule { - NO_HITS_ALLOWED, - MIN_HITS_REQUIRED, - THRESHOLD_MAX, - MATCH_FIELD_VALUE + NO_HITS_ALLOWED, // no results + MIN_HITS_REQUIRED, // at least N results + THRESHOLD_MAX, // a maximum of N results. + MATCH_FIELD_VALUE // a specific value in a field } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java index 751d000f1..81780c892 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java @@ -2,15 +2,15 @@ import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import java.util.List; import java.util.Optional; @Repository -public interface UtmComplianceControlConfigRepository extends JpaRepository { +public interface UtmComplianceControlConfigRepository extends JpaRepository, JpaSpecificationExecutor { @Query(" SELECT c FROM UtmComplianceControlConfig c LEFT JOIN FETCH c.queriesConfigs WHERE c.id = :id") Optional findByIdWithQueries(@Param("id") Long id); } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigQueryService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigQueryService.java new file mode 100644 index 000000000..7f1b1f1df --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigQueryService.java @@ -0,0 +1,65 @@ +package com.park.utmstack.service.compliance.config; + +import com.park.utmstack.domain.compliance.*; +import com.park.utmstack.repository.compliance.UtmComplianceControlConfigRepository; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigCriteria; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import tech.jhipster.service.QueryService; + +@Service +@Transactional(readOnly = true) +public class UtmComplianceControlConfigQueryService extends QueryService { + + private final UtmComplianceControlConfigRepository complianceControlConfigRepository; + private final UtmComplianceControlConfigMapper mapper; + + public UtmComplianceControlConfigQueryService(UtmComplianceControlConfigRepository complianceControlConfigRepository, + UtmComplianceControlConfigMapper mapper) { + this.complianceControlConfigRepository = complianceControlConfigRepository; + this.mapper = mapper; + } + + @Transactional(readOnly = true) + public Page findByCriteria(UtmComplianceControlConfigCriteria criteria, Pageable page) { + final Specification specification = createSpecification(criteria); + return complianceControlConfigRepository.findAll(specification, page).map(mapper::toDto); + } + + private Specification createSpecification(UtmComplianceControlConfigCriteria criteria) { + Specification specification = Specification.where(null); + if (criteria != null) { + if (criteria.getId() != null) { + specification = specification.and(buildSpecification(criteria.getId(), UtmComplianceControlConfig_.id)); + } + if (criteria.getStandardSectionId() != null) { + specification = specification.and( + buildRangeSpecification(criteria.getStandardSectionId(), UtmComplianceControlConfig_.standardSectionId)); + } + if (criteria.getControlName() != null) { + specification = specification.and( + buildStringSpecification(criteria.getControlName(), UtmComplianceControlConfig_.controlName)); + } + if (criteria.getControlSolution() != null ) { + specification = specification.and( + buildStringSpecification(criteria.getControlSolution(), UtmComplianceControlConfig_.controlSolution)); + } + if (criteria.getControlRemediation() != null) { + specification = specification.and( + buildStringSpecification(criteria.getControlRemediation(), UtmComplianceControlConfig_.controlRemediation)); + } + if (criteria.getControlStrategy() != null) { + specification = specification.and( + buildSpecification(criteria.getControlStrategy(), UtmComplianceControlConfig_.controlStrategy) + ); + } + + } + return specification; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index d7a64cfef..6f11b2edb 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -83,6 +83,7 @@ public UtmComplianceControlConfigDto findById(Long id) { return mapper.toDto(entity); } + //TODO: ELENA ???? public List findAll() { return repository.findAll(); } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java deleted file mode 100644 index 6114e2452..000000000 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceQueryConfigService.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.park.utmstack.service.compliance.config; - -import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; -import com.park.utmstack.repository.compliance.UtmComplianceQueryConfigRepository; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class UtmComplianceQueryConfigService { - - private final UtmComplianceQueryConfigRepository repository; - - public UtmComplianceQueryConfigService(UtmComplianceQueryConfigRepository repository) { - this.repository = repository; - } - - public UtmComplianceQueryConfig create(UtmComplianceQueryConfig config) { - return repository.save(config); - } - - public void delete(Long id) { - repository.deleteById(id); - } - -} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/ComplianceStrategyFilter.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/ComplianceStrategyFilter.java new file mode 100644 index 000000000..206afea0a --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/ComplianceStrategyFilter.java @@ -0,0 +1,9 @@ +package com.park.utmstack.service.dto.compliance; + +import com.park.utmstack.domain.compliance.enums.ComplianceStrategy; +import tech.jhipster.service.filter.Filter; + +public class ComplianceStrategyFilter extends Filter { + +} + diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigCriteria.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigCriteria.java new file mode 100644 index 000000000..f0341f854 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigCriteria.java @@ -0,0 +1,17 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Getter; +import lombok.Setter; +import tech.jhipster.service.filter.LongFilter; +import tech.jhipster.service.filter.StringFilter; + +@Getter +@Setter +public class UtmComplianceControlConfigCriteria { + private LongFilter id; + private LongFilter standardSectionId; + private StringFilter controlName; + private StringFilter controlSolution; + private StringFilter controlRemediation; + private ComplianceStrategyFilter controlStrategy; +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java index 33e93f6a4..db1432ccc 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java @@ -6,6 +6,7 @@ @Data public class UtmComplianceQueryConfigDto { private Long id; + private String queryName; private String queryDescription; private String sqlQuery; private EvaluationRule evaluationRule; diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java index 298f52136..94899def9 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -1,24 +1,43 @@ package com.park.utmstack.web.rest.compliance.config; +import com.park.utmstack.domain.application_events.enums.ApplicationEventType; +import com.park.utmstack.service.application_events.ApplicationEventService; import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; +import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigQueryService; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigCriteria; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; -import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; +import com.park.utmstack.web.rest.util.HeaderUtil; +import com.park.utmstack.web.rest.util.PaginationUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController -@RequestMapping("/api/compliance/control") +@RequestMapping("/api/compliance/control-config") public class UtmComplianceControlConfigResource { + private final Logger log = LoggerFactory.getLogger(UtmComplianceControlConfigResource.class); + private static final String CLASS_NAME = "UtmComplianceControlConfigResource"; private final UtmComplianceControlConfigService controlService; - private final UtmComplianceControlConfigMapper controlMapper; + private final UtmComplianceControlConfigQueryService queryService; + private final ApplicationEventService applicationEventService; + public UtmComplianceControlConfigResource( UtmComplianceControlConfigService controlService, - UtmComplianceControlConfigMapper controlMapper + UtmComplianceControlConfigQueryService queryService, + ApplicationEventService applicationEventService ) { this.controlService = controlService; - this.controlMapper = controlMapper; + this.queryService = queryService; + this.applicationEventService = applicationEventService; } @PostMapping @@ -52,4 +71,29 @@ public ResponseEntity deleteControl(@PathVariable Long id) { controlService.delete(id); return ResponseEntity.noContent().build(); } + + @GetMapping + public ResponseEntity> getAllComplianceControlConfig( + UtmComplianceControlConfigCriteria criteria, + Pageable pageable) { + + final String ctx = CLASS_NAME + ".getAllComplianceControlConfig"; + + try { + Page page = queryService.findByCriteria(criteria, pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/compliance/control-config"); + + return ResponseEntity.ok().headers(headers).body(page.getContent()); + + } catch (Exception e) { + String msg = ctx + ": " + e.getMessage(); + log.error(msg); + applicationEventService.createEvent(msg, ApplicationEventType.ERROR); + + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .headers(HeaderUtil.createFailureAlert("", "", msg)) + .body(null); + } + } + } diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml index 6fe468add..0ee9531c9 100644 --- a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml +++ b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml @@ -10,7 +10,9 @@ - + + + From bde728ff3dd6111f61561872a0a8c6f6d8860fef Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Mon, 26 Jan 2026 21:13:41 -0600 Subject: [PATCH 020/135] feat: add compliance control and query configuration tables with related DTOs and mappers --- .../UtmComplianceControlConfig.java | 20 +++++++++---- .../compliance/UtmComplianceQueryConfig.java | 17 +++++++++-- .../UtmComplianceControlConfigService.java | 28 +++++++++++++++++-- .../UtmComplianceControlConfigDto.java | 17 ++++++++++- .../UtmComplianceQueryConfigDto.java | 21 ++++++++++++++ ...create_table_compliance_control_config.xml | 8 +++--- ...2_create_table_compliance_query_config.xml | 14 ++++++---- 7 files changed, 105 insertions(+), 20 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java index a9a880bd6..a9a1b736a 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java @@ -6,6 +6,7 @@ import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; +import javax.validation.constraints.Size; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -24,7 +25,9 @@ public class UtmComplianceControlConfig implements Serializable { @GeneratedValue(generator = "CustomIdentityGenerator") private Long id; - @Column(name = "standard_section_id") + @Column(name = "standard_section_id", + nullable = false + ) private Long standardSectionId; @ManyToOne @@ -35,18 +38,25 @@ public class UtmComplianceControlConfig implements Serializable { private UtmComplianceStandardSection section; @Column(name = "control_name", - length = 50 + nullable = false ) + @Size(min = 10, max = 200) private String controlName; - @Column(name = "control_solution") + @Column(name = "control_solution", + length = 2000 + ) private String controlSolution; - @Column(name = "control_remediation") + @Column(name = "control_remediation", + length = 2000 + ) private String controlRemediation; @Enumerated(EnumType.STRING) - @Column(name = "control_strategy") + @Column(name = "control_strategy", + nullable = false + ) private ComplianceStrategy controlStrategy; @OneToMany( diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java index cfcdddf89..a085f00fe 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java @@ -7,6 +7,7 @@ import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; +import javax.validation.constraints.Size; import java.io.Serializable; @Getter @@ -26,25 +27,37 @@ public class UtmComplianceQueryConfig implements Serializable { private Long id; @Column(name = "query_name", + nullable = false, columnDefinition = "TEXT" ) + @Size(min = 10, max = 200) private String queryName; @Column(name = "query_description", + length = 2000, + nullable = false, columnDefinition = "TEXT" ) private String queryDescription; @Column(name = "sql_query", + length = 2000, + nullable = false, columnDefinition = "TEXT" ) private String sqlQuery; @Enumerated(EnumType.STRING) - @Column(name = "evaluation_rule") + @Column(name = "evaluation_rule", + nullable = false + ) private EvaluationRule evaluationRule; - @Column(name = "index_pattern_id") + private Integer ruleValue; + + @Column(name = "index_pattern_id", + nullable = false + ) private Long indexPatternId; @ManyToOne diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 6f11b2edb..433b2b854 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -2,10 +2,12 @@ import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; +import com.park.utmstack.domain.compliance.enums.EvaluationRule; import com.park.utmstack.repository.compliance.UtmComplianceControlConfigRepository; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; import com.park.utmstack.service.mapper.compliance.UtmComplianceQueryConfigMapper; +import com.park.utmstack.web.rest.errors.BadRequestAlertException; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -30,6 +32,9 @@ public UtmComplianceControlConfigService(UtmComplianceControlConfigRepository re @Transactional public UtmComplianceControlConfigDto create(UtmComplianceControlConfigDto dto) { + + validateControlConfig(dto); + UtmComplianceControlConfig entity = mapper.toEntity(dto); for (var qdto : dto.getQueriesConfigs()) { @@ -46,6 +51,8 @@ public UtmComplianceControlConfigDto create(UtmComplianceControlConfigDto dto) { @Transactional public UtmComplianceControlConfigDto update(Long id, UtmComplianceControlConfigDto dto) { + validateControlConfig(dto); + UtmComplianceControlConfig entity = repository.findByIdWithQueries(id) .orElseThrow(() -> new RuntimeException("Control not found")); @@ -83,8 +90,23 @@ public UtmComplianceControlConfigDto findById(Long id) { return mapper.toDto(entity); } - //TODO: ELENA ???? - public List findAll() { - return repository.findAll(); + private void validateControlConfig(UtmComplianceControlConfigDto dto) { + if (dto.getQueriesConfigs() == null || dto.getQueriesConfigs().isEmpty()) { + throw new BadRequestAlertException( + "At least one query configuration is required", + "utmComplianceControlConfig", + "queriesConfigsEmpty" + ); + } + + for (var q : dto.getQueriesConfigs()) { + if (q.getEvaluationRule() != EvaluationRule.NO_HITS_ALLOWED && q.getRuleValue() == null) { + throw new BadRequestAlertException( + "ruleValue is required when evaluationRule is not NO_HITS_ALLOWED", + "utmComplianceQueryConfig", + "ruleValueMissing" + ); + } + } } } diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java index 533fb9d77..ac07e2125 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java @@ -3,15 +3,30 @@ import com.park.utmstack.domain.compliance.enums.ComplianceStrategy; import lombok.Data; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.util.List; @Data public class UtmComplianceControlConfigDto { + private Long id; + + @NotNull private Long standardSectionId; + + @NotNull + @Size(min = 10, max = 200) private String controlName; + + @Size(max = 2000) private String controlSolution; + + @Size(max = 2000) private String controlRemediation; + + @NotNull private ComplianceStrategy controlStrategy; + private List queriesConfigs; -} \ No newline at end of file +} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java index db1432ccc..a02b40297 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java @@ -3,13 +3,34 @@ import com.park.utmstack.domain.compliance.enums.EvaluationRule; import lombok.Data; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + @Data public class UtmComplianceQueryConfigDto { + private Long id; + + @NotNull + @Size(min = 10, max = 200) private String queryName; + + @NotNull + @Size(max = 2000) private String queryDescription; + + @NotNull + @Size(max = 2000) private String sqlQuery; + + @NotNull private EvaluationRule evaluationRule; + + private Integer ruleValue; + + @NotNull private Long indexPatternId; + + @NotNull private Long controlConfigId; } diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml index b898c6e0f..9835b81f6 100644 --- a/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml +++ b/backend/src/main/resources/config/liquibase/changelog/20260112001_create_table_compliance_control_config.xml @@ -12,11 +12,11 @@ - + - - + + @@ -28,7 +28,7 @@ - + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml index 0ee9531c9..355170a27 100644 --- a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml +++ b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_query_config.xml @@ -10,23 +10,27 @@ - - + + - + - + + + + + - + From 44a56ae6ba37619c83846aaa52d5ea179e5b660c Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Tue, 27 Jan 2026 12:03:21 -0600 Subject: [PATCH 021/135] feat: enhance compliance control configuration with section mapping and DTO updates --- .../domain/compliance/UtmComplianceControlConfig.java | 1 + .../UtmComplianceControlConfigRepository.java | 8 +++++++- .../dto/compliance/UtmComplianceControlConfigDto.java | 2 ++ .../compliance/UtmComplianceStandardSectionDto.java | 11 +++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStandardSectionDto.java diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java index a9a1b736a..68b167fb5 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java @@ -32,6 +32,7 @@ public class UtmComplianceControlConfig implements Serializable { @ManyToOne @JoinColumn(name = "standard_section_id", + referencedColumnName = "id", insertable = false, updatable = false ) diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java index 81780c892..7c504aec5 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java @@ -11,6 +11,12 @@ @Repository public interface UtmComplianceControlConfigRepository extends JpaRepository, JpaSpecificationExecutor { - @Query(" SELECT c FROM UtmComplianceControlConfig c LEFT JOIN FETCH c.queriesConfigs WHERE c.id = :id") + @Query(""" + SELECT c FROM UtmComplianceControlConfig c + LEFT JOIN FETCH c.section s + LEFT JOIN FETCH s.standard st + LEFT JOIN FETCH c.queriesConfigs q + WHERE c.id = :id + """) Optional findByIdWithQueries(@Param("id") Long id); } diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java index ac07e2125..9721650eb 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java @@ -15,6 +15,8 @@ public class UtmComplianceControlConfigDto { @NotNull private Long standardSectionId; + private UtmComplianceStandardSectionDto section; + @NotNull @Size(min = 10, max = 200) private String controlName; diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStandardSectionDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStandardSectionDto.java new file mode 100644 index 000000000..0be1165ab --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStandardSectionDto.java @@ -0,0 +1,11 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Data; + +@Data +public class UtmComplianceStandardSectionDto { + private Long id; + private String standardSectionName; + private String standardSectionDescription; + private Long standardId; +} \ No newline at end of file From 2d31b90f9c935d7397d4cefa6ef124f56d01ff0d Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Tue, 27 Jan 2026 15:44:35 -0600 Subject: [PATCH 022/135] feat: Revert unnecessary changes --- .../compliance-management/compliance-management.module.ts | 2 -- .../log-analyzer-tabs/log-analyzer-tabs.component.html | 2 +- .../explorer/log-analyzer-tabs/log-analyzer-tabs.component.ts | 2 +- frontend/src/app/log-analyzer/log-analyzer-routing.module.ts | 2 +- .../log-analyzer-query-list.component.ts | 2 +- .../shared/services/log-analyzer-query.service.ts | 2 +- frontend/src/environments/environment.ts | 4 ++-- 7 files changed, 7 insertions(+), 9 deletions(-) diff --git a/frontend/src/app/compliance/compliance-management/compliance-management.module.ts b/frontend/src/app/compliance/compliance-management/compliance-management.module.ts index 32dd9c7cd..a1c69fa10 100644 --- a/frontend/src/app/compliance/compliance-management/compliance-management.module.ts +++ b/frontend/src/app/compliance/compliance-management/compliance-management.module.ts @@ -23,8 +23,6 @@ import {UtmCpStandardSectionComponent} from './utm-cp-standard-section/utm-cp-st import {UtmCpStandardDeleteComponent} from './utm-cp-standard/utm-cp-standard-delete/utm-cp-standard-delete.component'; import {UtmCpStandardComponent} from './utm-cp-standard/utm-cp-standard.component'; - - @NgModule({ declarations: [ CpStandardManagementComponent, diff --git a/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.html b/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.html index 02473a4d8..238746a91 100644 --- a/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.html +++ b/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.html @@ -5,7 +5,7 @@
Log analyzer
-
diff --git a/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.ts b/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.ts index 78bbaa640..1e1cb3406 100644 --- a/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.ts +++ b/frontend/src/app/log-analyzer/explorer/log-analyzer-tabs/log-analyzer-tabs.component.ts @@ -72,7 +72,7 @@ export class LogAnalyzerTabsComponent implements OnInit, OnDestroy { this.router.events.pipe( filter(event => event instanceof NavigationStart), tap((event: NavigationStart) => { - if (event.url !== '/discover/log-analyzer-query-config' && !event.url.includes('/discover/log-analyzer')) { + if (event.url !== '/discover/log-analyzer-queries' && !event.url.includes('/discover/log-analyzer')) { this.tabService.closeAllTabs(); } }), diff --git a/frontend/src/app/log-analyzer/log-analyzer-routing.module.ts b/frontend/src/app/log-analyzer/log-analyzer-routing.module.ts index e33f6a383..aa13b556c 100644 --- a/frontend/src/app/log-analyzer/log-analyzer-routing.module.ts +++ b/frontend/src/app/log-analyzer/log-analyzer-routing.module.ts @@ -14,7 +14,7 @@ const routes: Routes = [ data: {authorities: [ADMIN_ROLE, USER_ROLE]} }, { - path: 'log-analyzer-query-config', + path: 'log-analyzer-queries', component: LogAnalyzerQueryListComponent, canActivate: [UserRouteAccessService], data: {authorities: [ADMIN_ROLE, USER_ROLE]} diff --git a/frontend/src/app/log-analyzer/queries/log-analyzer-query-list/log-analyzer-query-list.component.ts b/frontend/src/app/log-analyzer/queries/log-analyzer-query-list/log-analyzer-query-list.component.ts index 2cb12edf2..cc011e6bf 100644 --- a/frontend/src/app/log-analyzer/queries/log-analyzer-query-list/log-analyzer-query-list.component.ts +++ b/frontend/src/app/log-analyzer/queries/log-analyzer-query-list/log-analyzer-query-list.component.ts @@ -58,7 +58,7 @@ export class LogAnalyzerQueryListComponent implements OnInit, OnDestroy { this.router.events.pipe( filter(event => event instanceof NavigationStart), tap((event: NavigationStart) => { - if (event.url !== '/discover/log-analyzer-query-config' && !event.url.includes('/discover/log-analyzer')) { + if (event.url !== '/discover/log-analyzer-queries' && !event.url.includes('/discover/log-analyzer')) { this.tabService.closeAllTabs(); } }), diff --git a/frontend/src/app/log-analyzer/shared/services/log-analyzer-query.service.ts b/frontend/src/app/log-analyzer/shared/services/log-analyzer-query.service.ts index 87506e232..cc17c5501 100644 --- a/frontend/src/app/log-analyzer/shared/services/log-analyzer-query.service.ts +++ b/frontend/src/app/log-analyzer/shared/services/log-analyzer-query.service.ts @@ -10,7 +10,7 @@ import {LogAnalyzerQueryType} from '../type/log-analyzer-query.type'; }) export class LogAnalyzerQueryService { - public resourceUrl = SERVER_API_URL + 'api/log-analyzer/query-config'; + public resourceUrl = SERVER_API_URL + 'api/log-analyzer/queries'; constructor(private http: HttpClient) { } diff --git a/frontend/src/environments/environment.ts b/frontend/src/environments/environment.ts index a9c376b4f..c14489291 100644 --- a/frontend/src/environments/environment.ts +++ b/frontend/src/environments/environment.ts @@ -4,8 +4,8 @@ export const environment = { production: false, - //SERVER_API_URL: 'https://192.168.1.18/', - SERVER_API_URL: 'http://localhost:8080/', + SERVER_API_URL: 'https://192.168.1.18/', + //SERVER_API_URL: 'http://localhost:8080/', SERVER_API_CONTEXT: '', SESSION_AUTH_TOKEN: window.location.host.split(':')[0].toLocaleUpperCase(), WEBSOCKET_URL: '//localhost:8080', From 8d5cf6cb77470eb5ae087d24adcf3a845c02024f Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 28 Jan 2026 11:58:39 -0600 Subject: [PATCH 023/135] feat: enhance compliance control configuration with section mapping and DTO updates --- .../utmstack/domain/compliance/UtmComplianceQueryConfig.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java index a085f00fe..73435f9a2 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java @@ -68,6 +68,9 @@ public class UtmComplianceQueryConfig implements Serializable { private UtmIndexPattern indexPattern; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "control_config_id", nullable = false) + @JoinColumn( + name = "control_config_id", + nullable = false + ) private UtmComplianceControlConfig controlConfig; } From bde1081932cec516bcc38846e22d0331b379ec03 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 28 Jan 2026 12:02:08 -0600 Subject: [PATCH 024/135] feat: refactor compliance query form and related components for improved layout and usability --- .../shared/compliance-shared.module.ts | 6 +- .../utm-compliance-query-form.component.html | 103 ---------------- .../utm-compliance-query-list.component.html | 114 +++++++++--------- .../utm-compliance-query-list.component.scss | 4 - ...css => utm-compliance-query.component.css} | 0 .../utm-compliance-query.component.html | 108 +++++++++++++++++ ...t.ts => utm-compliance-query.component.ts} | 8 +- ...iance-control-config-create.component.html | 100 +++++++-------- .../utm-cp-st-section-select.component.html | 5 +- .../utm-cp-st-section-select.component.ts | 1 + .../utm-cp-standard-select.component.html | 4 +- .../utm-cp-standard-select.component.ts | 1 + 12 files changed, 230 insertions(+), 224 deletions(-) delete mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html rename frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/{utm-compliance-query-form.component.css => utm-compliance-query.component.css} (100%) create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.html rename frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/{utm-compliance-query-form.component.ts => utm-compliance-query.component.ts} (94%) diff --git a/frontend/src/app/compliance/shared/compliance-shared.module.ts b/frontend/src/app/compliance/shared/compliance-shared.module.ts index 98aff71cf..46ff57cc2 100644 --- a/frontend/src/app/compliance/shared/compliance-shared.module.ts +++ b/frontend/src/app/compliance/shared/compliance-shared.module.ts @@ -21,8 +21,8 @@ import { } from '../compliance-reports-view/components/compliance-time-window/compliance-time-windows.component'; import {ReportApplyNoteComponent} from './components/report-apply-note/report-apply-note.component'; import { - UtmComplianceQueryFormComponent -} from './components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component'; + UtmComplianceQueryComponent +} from './components/utm-compliance-control-config-create/query-config/utm-compliance-query.component'; import { UtmComplianceQueryListComponent } from './components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component'; @@ -65,7 +65,7 @@ import {GraphicBuilderSharedModule} from "../../graphic-builder/shared/graphic-b ComplianceTimeWindowsComponent, CompliancePrintViewComponent, UtmComplianceControlConfigCreateComponent, - UtmComplianceQueryFormComponent, + UtmComplianceQueryComponent, UtmComplianceQueryListComponent ], imports: [ diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html deleted file mode 100644 index 947667ca6..000000000 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.html +++ /dev/null @@ -1,103 +0,0 @@ - -
- - -
- - Query name is required. - - - Query name must be at least 10 characters long. - - - Query name must not exceed 200 characters. - -
-
- -
- - -
- - Query description is required. - - - Query description must not exceed 2000 characters. - -
-
- -
- -
- - -
-
- - {{ errorMessage || 'SQL Query is required.'}} - -
-
- -
-
- - - -
- - Evaluation Rule is required. - -
-
-
- -
- - -
- - Rule value is required. - - - Rule value must be greater than 0. - - - Rule value must be a positive integer. - -
-
- - -
- - -
- diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html index 9349b00e7..748485783 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html @@ -1,65 +1,63 @@ -
- - + + - - + + -
- - - - - - - - - - +
+
Query NameSQL QueryEvaluation RuleIndex PatternActions
+ + + + + + + + + - - - - - - - - - + + + + + + - - - - - + - - -
Query NameSQL QueryEvaluation RuleIndex PatternActions
- {{ q.queryName | slice:0:30 }}{{ q.queryName.length > 30 ? '…' : '' }} - - {{ q.sqlQuery | slice:0:30 }}{{ q.sqlQuery.length > 30 ? '…' : '' }} - {{ q.evaluationRule }}{{ getIndexPatternName(q.indexPatternId) }} -
- +
+ {{ q.queryName | slice:0:30 }}{{ q.queryName.length > 30 ? '…' : '' }} + + {{ q.sqlQuery | slice:0:30 }}{{ q.sqlQuery.length > 30 ? '…' : '' }} + {{ q.evaluationRule }}{{ getIndexPatternName(q.indexPatternId) }}
+
+ - -
- + +
-
+ + + + + + + + + +
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss index 78776b420..e24d001bf 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss @@ -5,7 +5,3 @@ .table td { vertical-align: middle; } - -.query-container { - overflow: auto; -} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.css similarity index 100% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.css rename to frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.css diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.html new file mode 100644 index 000000000..0763e93c2 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.html @@ -0,0 +1,108 @@ +
+
+
+ + +
+ + Query name is required. + + + Query name must be at least 10 characters long. + + + Query name must not exceed 200 characters. + +
+
+ +
+ + + + +
+ + Evaluation Rule is required. + +
+
+
+ +
+
+ + +
+ + Query description is required. + + + Query description must not exceed 2000 characters. + +
+
+ +
+ + +
+ + Rule value is required. + + + Rule value must be greater than 0. + + + Rule value must be a positive integer. + +
+
+
+ +
+ +
+ + +
+
+ + {{ errorMessage || 'SQL Query is required.'}} + +
+
+ +
+ + +
+
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts similarity index 94% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts rename to frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts index 13f48236f..6f987dc8a 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-form.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts @@ -9,11 +9,11 @@ import {ComplianceEvaluationRuleEnum} from '../../../enums/compliance-evaluation import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; @Component({ - selector: 'app-utm-compliance-query-form', - templateUrl: './utm-compliance-query-form.component.html', - styleUrls: ['./utm-compliance-query-form.component.css'] + selector: 'app-utm-compliance-query', + templateUrl: './utm-compliance-query.component.html', + styleUrls: ['./utm-compliance-query.component.css'] }) -export class UtmComplianceQueryFormComponent implements OnInit { +export class UtmComplianceQueryComponent implements OnInit { @Input() query: UtmComplianceQueryConfigType = null; @Input() indexPatterns: UtmIndexPattern[] = []; diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html index e1b989a3f..d2f64b0c2 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html @@ -25,36 +25,59 @@
-
- - - -
-
- - - +
+
+ + + +
+
+ + + +
-
- - -
- - Report name is required. - - - Report name must be at least 10 characters long. - - - Report name must not exceed 200 characters. - +
+
+ + +
+ + Report name is required. + + + Report name must be at least 10 characters long. + + + Report name must not exceed 200 characters. + +
+
+
+ + + +
+ + Strategy is required. + +
@@ -67,25 +90,6 @@
- -
- - - -
- - Strategy is required. - -
-
diff --git a/frontend/src/app/compliance/shared/components/utm-cp-st-section-select/utm-cp-st-section-select.component.html b/frontend/src/app/compliance/shared/components/utm-cp-st-section-select/utm-cp-st-section-select.component.html index 644dc4971..1bdba94b9 100644 --- a/frontend/src/app/compliance/shared/components/utm-cp-st-section-select/utm-cp-st-section-select.component.html +++ b/frontend/src/app/compliance/shared/components/utm-cp-st-section-select/utm-cp-st-section-select.component.html @@ -7,9 +7,10 @@ [loading]="!standardsSection" [searchable]="true" bindLabel="standardSectionName" - bindValue="id"> + bindValue="id" + [ngClass]="{ 'w-100': !showAdd }"> -
+
Add section diff --git a/frontend/src/app/compliance/shared/components/utm-cp-st-section-select/utm-cp-st-section-select.component.ts b/frontend/src/app/compliance/shared/components/utm-cp-st-section-select/utm-cp-st-section-select.component.ts index 7447d1668..2d45055d3 100644 --- a/frontend/src/app/compliance/shared/components/utm-cp-st-section-select/utm-cp-st-section-select.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-cp-st-section-select/utm-cp-st-section-select.component.ts @@ -18,6 +18,7 @@ export class UtmCpStSectionSelectComponent implements OnInit { @Input() required: boolean; @Input() onlyWithReport: boolean; @Output() standardSectionSelect = new EventEmitter(); + @Input() showAdd = true; private standarId: number; constructor(private cpStandardSectionService: CpStandardSectionService, diff --git a/frontend/src/app/compliance/shared/components/utm-cp-standard-select/utm-cp-standard-select.component.html b/frontend/src/app/compliance/shared/components/utm-cp-standard-select/utm-cp-standard-select.component.html index f2ff809ea..348ba0c11 100644 --- a/frontend/src/app/compliance/shared/components/utm-cp-standard-select/utm-cp-standard-select.component.html +++ b/frontend/src/app/compliance/shared/components/utm-cp-standard-select/utm-cp-standard-select.component.html @@ -8,9 +8,9 @@ [searchable]="true" bindLabel="standardName" bindValue="id" - class="w-50"> + [ngClass]="showAdd ? 'w-50' : 'w-100'"> -
+
Add standard diff --git a/frontend/src/app/compliance/shared/components/utm-cp-standard-select/utm-cp-standard-select.component.ts b/frontend/src/app/compliance/shared/components/utm-cp-standard-select/utm-cp-standard-select.component.ts index 4aa9823ec..6370ed8c6 100644 --- a/frontend/src/app/compliance/shared/components/utm-cp-standard-select/utm-cp-standard-select.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-cp-standard-select/utm-cp-standard-select.component.ts @@ -15,6 +15,7 @@ export class UtmCpStandardSelectComponent implements OnInit { @Input() standardId: number; @Input() required: boolean; @Output() standardSelect = new EventEmitter(); + @Input() showAdd = true; constructor(private cpStandardService: CpStandardService, private modalService: NgbModal, From b8a60d643be0a91fb7e795262356e45389f39ab1 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 28 Jan 2026 16:32:30 -0600 Subject: [PATCH 025/135] feat: implement compliance orchestrator backend client and evaluation logic --- plugins/compliance-orchestrator/bootstrap.go | 76 +++++++++++ .../compliance-orchestrator/client/backend.go | 122 ++++++++++++++++++ .../client/opensearch.go | 24 ++++ .../evaluator/evaluator.go | 86 ++++++++++++ plugins/compliance-orchestrator/go.mod | 54 ++++++++ plugins/compliance-orchestrator/main.go | 34 +++++ .../models/constant.go | 8 ++ .../models/evaluation.go | 7 + .../models/index_pattern.go | 9 ++ .../models/query_result.go | 7 + .../models/report_config.go | 37 ++++++ .../scheduler/scheduler.go | 41 ++++++ .../compliance-orchestrator/workers/worker.go | 45 +++++++ 13 files changed, 550 insertions(+) create mode 100644 plugins/compliance-orchestrator/bootstrap.go create mode 100644 plugins/compliance-orchestrator/client/backend.go create mode 100644 plugins/compliance-orchestrator/client/opensearch.go create mode 100644 plugins/compliance-orchestrator/evaluator/evaluator.go create mode 100644 plugins/compliance-orchestrator/go.mod create mode 100644 plugins/compliance-orchestrator/main.go create mode 100644 plugins/compliance-orchestrator/models/constant.go create mode 100644 plugins/compliance-orchestrator/models/evaluation.go create mode 100644 plugins/compliance-orchestrator/models/index_pattern.go create mode 100644 plugins/compliance-orchestrator/models/query_result.go create mode 100644 plugins/compliance-orchestrator/models/report_config.go create mode 100644 plugins/compliance-orchestrator/scheduler/scheduler.go create mode 100644 plugins/compliance-orchestrator/workers/worker.go diff --git a/plugins/compliance-orchestrator/bootstrap.go b/plugins/compliance-orchestrator/bootstrap.go new file mode 100644 index 000000000..273d8521d --- /dev/null +++ b/plugins/compliance-orchestrator/bootstrap.go @@ -0,0 +1,76 @@ +package main + +import ( + "context" + "time" + + "github.com/threatwinds/go-sdk/catcher" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/client" +) + +func waitForBackend(bc *client.BackendClient) error { + maxRetries := 3 + retryDelay := 2 * time.Second + + for retry := 0; retry < maxRetries; retry++ { + err := bc.HealthCheck(context.Background()) + if err == nil { + catcher.Info("Connected to Backend", map[string]any{ + "process": "compliance-orchestrator", + }) + return nil + } + + catcher.Error("Cannot connect to Backend, retrying", err, map[string]any{ + "retry": retry + 1, + }) + + if retry < maxRetries-1 { + time.Sleep(retryDelay) + retryDelay *= 2 + } else { + return err + } + } + + return nil +} + +func waitForOpenSearch() error { + maxRetries := 3 + retryDelay := 2 * time.Second + + for retry := 0; retry < maxRetries; retry++ { + err := client.ConnectOpenSearch() + if err == nil { + return nil + } + + catcher.Error("Cannot connect to OpenSearch, retrying", err, map[string]any{ + "retry": retry + 1, + }) + + if retry < maxRetries-1 { + time.Sleep(retryDelay) + retryDelay *= 2 + } else { + return err + } + } + + return nil +} + +func bootstrap() (*client.BackendClient, error) { + backend := client.NewBackendClient() + + if err := waitForBackend(backend); err != nil { + return nil, err + } + + if err := waitForOpenSearch(); err != nil { + return nil, err + } + + return backend, nil +} diff --git a/plugins/compliance-orchestrator/client/backend.go b/plugins/compliance-orchestrator/client/backend.go new file mode 100644 index 000000000..bf00d8796 --- /dev/null +++ b/plugins/compliance-orchestrator/client/backend.go @@ -0,0 +1,122 @@ +package client + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" + + "github.com/threatwinds/go-sdk/catcher" + "github.com/threatwinds/go-sdk/plugins" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/models" +) + +type BackendClient struct { + baseURL string + internalKey string + httpClient *http.Client +} + +func NewBackendClient() *BackendClient { + raw := plugins.PluginCfg("com.utmstack", false).Get("backend").String() + + if !strings.HasPrefix(raw, "http://") && !strings.HasPrefix(raw, "https://") { + raw = "http://" + raw + } + + return &BackendClient{ + baseURL: raw, + internalKey: plugins.PluginCfg("com.utmstack", false).Get("internalKey").String(), + httpClient: &http.Client{ + Timeout: 30 * time.Second, + }, + } +} + +func (c *BackendClient) HealthCheck(ctx context.Context) error { + url := fmt.Sprintf("%s/api/ping", c.baseURL) + + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return catcher.Error("failed to create backend ping request", err, nil) + } + + resp, err := c.httpClient.Do(req) + if err != nil { + return catcher.Error("backend ping request failed", err, nil) + } + + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + catcher.Error("failed to close backend ping response body", err, nil) + } + }(resp.Body) + + if resp.StatusCode != http.StatusOK { + return catcher.Error("backend ping returned non-200", nil, map[string]any{ + "status": resp.StatusCode, + }) + } + + return nil +} + +func (c *BackendClient) GetReportConfigs(ctx context.Context) ([]models.ReportConfig, error) { + url := fmt.Sprintf("%s/api/compliance/report-config?page=0&size=1000&sort=id,asc", c.baseURL) + var reports []models.ReportConfig + + var body, err = c.GetRequest(ctx, url) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(body, &reports); err != nil { + return nil, err + } + return reports, nil +} + +func (c *BackendClient) GetActiveIndexPatterns(ctx context.Context) ([]models.IndexPattern, error) { + url := fmt.Sprintf("%s/api/utm-index-patterns?page=0&size=1000&sort=id,asc&isActive.equals=true", c.baseURL) + var activeIndex []models.IndexPattern + + var body, err = c.GetRequest(ctx, url) + if err != nil { + return nil, err + } + + if err := json.Unmarshal(body, &activeIndex); err != nil { + return nil, err + } + return activeIndex, nil +} + +func (c *BackendClient) GetRequest(ctx context.Context, url string) ([]byte, error) { + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return nil, err + } + + req.Header.Set("utm-internal-key", c.internalKey) + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("backend returned %d", resp.StatusCode) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return body, nil +} diff --git a/plugins/compliance-orchestrator/client/opensearch.go b/plugins/compliance-orchestrator/client/opensearch.go new file mode 100644 index 000000000..a99b54d5b --- /dev/null +++ b/plugins/compliance-orchestrator/client/opensearch.go @@ -0,0 +1,24 @@ +package client + +import ( + "github.com/threatwinds/go-sdk/catcher" + sdkos "github.com/threatwinds/go-sdk/os" + "github.com/threatwinds/go-sdk/plugins" +) + +func ConnectOpenSearch() error { + osUrl := plugins.PluginCfg("org.opensearch", false).Get("opensearch").String() + + err := sdkos.Connect([]string{osUrl}, "", "") + if err != nil { + return catcher.Error("failed to connect to OpenSearch", err, map[string]any{ + "url": osUrl, + }) + } + + catcher.Info("Connected to OpenSearch", map[string]any{ + "url": osUrl, + }) + + return nil +} diff --git a/plugins/compliance-orchestrator/evaluator/evaluator.go b/plugins/compliance-orchestrator/evaluator/evaluator.go new file mode 100644 index 000000000..537caeb75 --- /dev/null +++ b/plugins/compliance-orchestrator/evaluator/evaluator.go @@ -0,0 +1,86 @@ +package evaluator + +import ( + "context" + "fmt" + + "github.com/threatwinds/go-sdk/catcher" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/client" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/models" +) + +type Evaluator struct { + backend *client.BackendClient +} + +func NewEvaluator(backend *client.BackendClient) *Evaluator { + return &Evaluator{backend: backend} +} + +func (e *Evaluator) Evaluate(ctx context.Context, cfg models.ReportConfig) (models.Evaluation, error) { + // 1. Obtener index patterns activos + _, err := e.backend.GetActiveIndexPatterns(ctx) + if err != nil { + return models.Evaluation{}, fmt.Errorf("failed to get index patterns: %w", err) + } + + // 2. Evaluar cada QuerySpec + /*var results []models.QueryResult*/ + for _, q := range cfg.Queries { + /*qr := e.evaluateQuery(ctx, q, patterns) + results = append(results, qr)*/ + catcher.Info("Evaluating query", map[string]any{ + "query_id": q.ID, + }) + } + + /*final := combineResults(cfg, results) + + return final, nil*/ + + return models.Evaluation{}, nil +} + +func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QuerySpec, patterns []models.IndexPattern) models.QueryResult { + + /*if !patternExists(q.IndexPatternID, patterns) { + return models.QueryResult{ + QueryID: int(q.ID), + Status: models.StatusNotApplicable, + Reason: "Index pattern not active", + } + }*/ + + return models.QueryResult{ + QueryID: int(q.ID), + Status: models.StatusCompliant, + Reason: "Query executed successfully (placeholder)", + } +} + +func patternExists(pattern int, active []models.IndexPattern) bool { + for _, p := range active { + if p.ID == pattern && p.Active { + return true + } + } + return false +} + +func combineResults(cfg models.ReportConfig, results []models.QueryResult) models.Evaluation { + final := models.Evaluation{ + ReportID: int(cfg.ID), + Results: results, + } + + // Estrategia simple: si alguna query es NON_COMPLIANT → NON_COMPLIANT + for _, r := range results { + if r.Status == models.StatusNonCompliant { + final.Status = models.StatusNonCompliant + return final + } + } + + final.Status = models.StatusCompliant + return final +} diff --git a/plugins/compliance-orchestrator/go.mod b/plugins/compliance-orchestrator/go.mod new file mode 100644 index 000000000..3cdc68db7 --- /dev/null +++ b/plugins/compliance-orchestrator/go.mod @@ -0,0 +1,54 @@ +module github.com/utmstack/UTMStack/plugins/compliance-orchestrator + +go 1.25.5 + +require github.com/threatwinds/go-sdk v1.1.8 + +require ( + cel.dev/expr v0.25.1 // indirect + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/bytedance/gopkg v0.1.3 // indirect + github.com/bytedance/sonic v1.15.0 // indirect + github.com/bytedance/sonic/loader v0.5.0 // indirect + github.com/cloudwego/base64x v0.1.6 // indirect + github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/gin-contrib/sse v1.1.0 // indirect + github.com/gin-gonic/gin v1.11.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.30.1 // indirect + github.com/goccy/go-json v0.10.5 // indirect + github.com/goccy/go-yaml v1.19.2 // indirect + github.com/google/cel-go v0.26.1 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/opensearch-project/opensearch-go/v4 v4.6.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/quic-go/qpack v0.6.0 // indirect + github.com/quic-go/quic-go v0.59.0 // indirect + github.com/stoewer/go-strcase v1.3.1 // indirect + github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/match v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.3.1 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + golang.org/x/arch v0.23.0 // indirect + golang.org/x/crypto v0.47.0 // indirect + golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect + golang.org/x/net v0.49.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.33.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect + google.golang.org/grpc v1.78.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect +) diff --git a/plugins/compliance-orchestrator/main.go b/plugins/compliance-orchestrator/main.go new file mode 100644 index 000000000..88a85cd1c --- /dev/null +++ b/plugins/compliance-orchestrator/main.go @@ -0,0 +1,34 @@ +package main + +import ( + "context" + "time" + + "github.com/threatwinds/go-sdk/catcher" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/scheduler" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/workers" +) + +func main() { + catcher.Info("Starting Compliance Orchestrator", map[string]any{ + "process": "compliance-orchestrator", + }) + + backend, err := bootstrap() + if err != nil { + catcher.Info("Compliance Orchestrator bootstrap failed", map[string]any{}) + return + } + + catcher.Info("Compliance Orchestrator bootstrapped successfully", nil) + + ctx := context.Background() + + go workers.StartWorkers(ctx, backend) + + go scheduler.StartScheduler(ctx, backend) + + for { + time.Sleep(1 * time.Hour) + } +} diff --git a/plugins/compliance-orchestrator/models/constant.go b/plugins/compliance-orchestrator/models/constant.go new file mode 100644 index 000000000..a1c2427fa --- /dev/null +++ b/plugins/compliance-orchestrator/models/constant.go @@ -0,0 +1,8 @@ +package models + +const ( + StatusCompliant = "COMPLIANT" + StatusNonCompliant = "NON_COMPLIANT" + StatusNotApplicable = "NOT_APPLICABLE" + StatusError = "ERROR" +) diff --git a/plugins/compliance-orchestrator/models/evaluation.go b/plugins/compliance-orchestrator/models/evaluation.go new file mode 100644 index 000000000..8071cbd6b --- /dev/null +++ b/plugins/compliance-orchestrator/models/evaluation.go @@ -0,0 +1,7 @@ +package models + +type Evaluation struct { + ReportID int `json:"reportId"` + Status string `json:"status"` + Results []QueryResult `json:"results"` +} diff --git a/plugins/compliance-orchestrator/models/index_pattern.go b/plugins/compliance-orchestrator/models/index_pattern.go new file mode 100644 index 000000000..0d37ce866 --- /dev/null +++ b/plugins/compliance-orchestrator/models/index_pattern.go @@ -0,0 +1,9 @@ +package models + +type IndexPattern struct { + ID int `json:"id"` + Pattern string `json:"pattern"` + PatternModule string `json:"patternModule"` + PatternSystem bool `json:"patternSystem"` + Active bool `json:"active"` +} diff --git a/plugins/compliance-orchestrator/models/query_result.go b/plugins/compliance-orchestrator/models/query_result.go new file mode 100644 index 000000000..ef94a8501 --- /dev/null +++ b/plugins/compliance-orchestrator/models/query_result.go @@ -0,0 +1,7 @@ +package models + +type QueryResult struct { + QueryID int `json:"queryId"` + Status string `json:"status"` + Reason string `json:"reason"` +} diff --git a/plugins/compliance-orchestrator/models/report_config.go b/plugins/compliance-orchestrator/models/report_config.go new file mode 100644 index 000000000..9d08e0d93 --- /dev/null +++ b/plugins/compliance-orchestrator/models/report_config.go @@ -0,0 +1,37 @@ +package models + +type ReportConfig struct { + ID int64 `json:"id"` + ConfigSolution string `json:"configSolution"` + ConfigRemediation *string `json:"configRemediation"` + StandardSectionID int64 `json:"standardSectionId"` + DashboardID int64 `json:"dashboardId"` + ConfigType string `json:"configType"` + ConfigReportName string `json:"configReportName"` + Section *Section `json:"section"` + Queries []QuerySpec `json:"queries"` +} + +type Section struct { + ID int64 `json:"id"` + StandardID int64 `json:"standardId"` + StandardSectionName string `json:"standardSectionName"` + StandardSectionDescription string `json:"standardSectionDescription"` + Standard *Standard `json:"standard"` +} + +type Standard struct { + ID int64 `json:"id"` + StandardName string `json:"standardName"` + StandardDescription string `json:"standardDescription"` + SystemOwner bool `json:"systemOwner"` +} + +type QuerySpec struct { + ID int64 `json:"id"` + Description string `json:"queryDescription"` + SQLQuery string `json:"sqlQuery"` + EvaluationRule string `json:"evaluationRule"` + IndexPatternID int64 `json:"indexPatternId"` + ControlConfigID int64 `json:"controlConfigId"` +} diff --git a/plugins/compliance-orchestrator/scheduler/scheduler.go b/plugins/compliance-orchestrator/scheduler/scheduler.go new file mode 100644 index 000000000..69b061ed2 --- /dev/null +++ b/plugins/compliance-orchestrator/scheduler/scheduler.go @@ -0,0 +1,41 @@ +package scheduler + +import ( + "context" + "time" + + "github.com/threatwinds/go-sdk/catcher" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/client" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/models" +) + +var Jobs chan models.ReportConfig + +func StartScheduler(ctx context.Context, backend *client.BackendClient) { + Jobs = make(chan models.ReportConfig, 1000) + + ticker := time.NewTicker(30 * time.Second) + + for { + select { + case <-ctx.Done(): + // Shutdown limpio + return + + case <-ticker.C: + configs, err := backend.GetReportConfigs(ctx) + if err != nil { + continue + } + + catcher.Info("Scheduler: sending configs", map[string]any{ + "cantidad": len(configs), + "timestamp": time.Now().String(), + }) + + for _, cfg := range configs { + Jobs <- cfg + } + } + } +} diff --git a/plugins/compliance-orchestrator/workers/worker.go b/plugins/compliance-orchestrator/workers/worker.go new file mode 100644 index 000000000..57032d8db --- /dev/null +++ b/plugins/compliance-orchestrator/workers/worker.go @@ -0,0 +1,45 @@ +package workers + +import ( + "context" + "runtime" + + "github.com/threatwinds/go-sdk/catcher" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/client" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/evaluator" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/scheduler" +) + +func StartWorkers(ctx context.Context, backend *client.BackendClient) { + numWorkers := 2 * runtime.NumCPU() + + for i := 0; i < numWorkers; i++ { + go func(id int) { + + eval := evaluator.NewEvaluator(backend) + + for cfg := range scheduler.Jobs { + + // Log opcional + catcher.Info("Worker evaluating control", map[string]any{ + "worker": id, + "control": cfg.ID, + }) + + // Ejecutar evaluación real + _, err := eval.Evaluate(ctx, cfg) + if err != nil { + // catcher.New("evaluation failed"). + // Set("worker", id). + // Set("control", cfg.ID). + // SetError(err). + // Log() + continue + } + + // Aquí luego enviarás el resultado al sender + // sender.Send(result) + } + }(i) + } +} From 610552f15b0d1a2f3bfeb7990597e0038a2209ab Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Tue, 3 Feb 2026 19:04:50 -0600 Subject: [PATCH 026/135] feat: implement compliance orchestrator backend client and evaluation logic --- .../compliance-orchestrator/client/backend.go | 40 ++++- .../client/opensearch.go | 44 +++++ .../evaluator/evaluator.go | 164 +++++++++++++----- .../models/constant.go | 32 +++- .../models/control_evaluation.go | 11 ++ .../models/evaluation.go | 7 - .../models/evaluation_document.go | 11 ++ .../models/query_evaluation.go | 10 ++ .../models/query_result.go | 7 - .../models/report_config.go | 51 +++--- .../scheduler/scheduler.go | 6 +- .../compliance-orchestrator/workers/worker.go | 44 +++-- 12 files changed, 321 insertions(+), 106 deletions(-) create mode 100644 plugins/compliance-orchestrator/models/control_evaluation.go delete mode 100644 plugins/compliance-orchestrator/models/evaluation.go create mode 100644 plugins/compliance-orchestrator/models/evaluation_document.go create mode 100644 plugins/compliance-orchestrator/models/query_evaluation.go delete mode 100644 plugins/compliance-orchestrator/models/query_result.go diff --git a/plugins/compliance-orchestrator/client/backend.go b/plugins/compliance-orchestrator/client/backend.go index bf00d8796..c2e8d7aff 100644 --- a/plugins/compliance-orchestrator/client/backend.go +++ b/plugins/compliance-orchestrator/client/backend.go @@ -1,6 +1,7 @@ package client import ( + "bytes" "context" "encoding/json" "fmt" @@ -65,19 +66,19 @@ func (c *BackendClient) HealthCheck(ctx context.Context) error { return nil } -func (c *BackendClient) GetReportConfigs(ctx context.Context) ([]models.ReportConfig, error) { - url := fmt.Sprintf("%s/api/compliance/report-config?page=0&size=1000&sort=id,asc", c.baseURL) - var reports []models.ReportConfig +func (c *BackendClient) GetControlConfigs(ctx context.Context) ([]models.ControlConfig, error) { + url := fmt.Sprintf("%s/api/compliance/control-config?page=0&size=1000&sort=id,asc", c.baseURL) + var controls []models.ControlConfig var body, err = c.GetRequest(ctx, url) if err != nil { return nil, err } - if err := json.Unmarshal(body, &reports); err != nil { + if err := json.Unmarshal(body, &controls); err != nil { return nil, err } - return reports, nil + return controls, nil } func (c *BackendClient) GetActiveIndexPatterns(ctx context.Context) ([]models.IndexPattern, error) { @@ -120,3 +121,32 @@ func (c *BackendClient) GetRequest(ctx context.Context, url string) ([]byte, err return body, nil } + +func (b *BackendClient) IndexEvaluationResult(ctx context.Context, index string, doc any) error { + baseURL := plugins.PluginCfg("org.opensearch", false).Get("opensearch").String() + endpoint := fmt.Sprintf("%s/%s/_doc", baseURL, index) + + jsonBody, err := json.Marshal(doc) + if err != nil { + return fmt.Errorf("failed to marshal evaluation result: %w", err) + } + + req, err := http.NewRequestWithContext(ctx, "POST", endpoint, bytes.NewBuffer(jsonBody)) + if err != nil { + return fmt.Errorf("failed to create index request: %w", err) + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := b.httpClient.Do(req) + if err != nil { + return fmt.Errorf("index request failed: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode >= 300 { + return fmt.Errorf("indexing failed with status %d", resp.StatusCode) + } + + return nil +} diff --git a/plugins/compliance-orchestrator/client/opensearch.go b/plugins/compliance-orchestrator/client/opensearch.go index a99b54d5b..75ad808af 100644 --- a/plugins/compliance-orchestrator/client/opensearch.go +++ b/plugins/compliance-orchestrator/client/opensearch.go @@ -1,6 +1,12 @@ package client import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "github.com/threatwinds/go-sdk/catcher" sdkos "github.com/threatwinds/go-sdk/os" "github.com/threatwinds/go-sdk/plugins" @@ -22,3 +28,41 @@ func ConnectOpenSearch() error { return nil } + +type SQLResponse struct { + Total int `json:"total"` +} + +func (b *BackendClient) ExecuteSQLQuery(ctx context.Context, sql string) (int, error) { + baseURL := plugins.PluginCfg("org.opensearch", false).Get("opensearch").String() + sqlEndpoint := fmt.Sprintf("%s/_plugins/_sql", baseURL) + + body := map[string]string{ + "query": sql, + } + + jsonBody, err := json.Marshal(body) + if err != nil { + return 0, fmt.Errorf("failed to marshal SQL body: %w", err) + } + + req, err := http.NewRequestWithContext(ctx, "POST", sqlEndpoint, bytes.NewBuffer(jsonBody)) + if err != nil { + return 0, fmt.Errorf("failed to create SQL request: %w", err) + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := b.httpClient.Do(req) + if err != nil { + return 0, fmt.Errorf("SQL request failed: %w", err) + } + defer resp.Body.Close() + + var result SQLResponse + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return 0, fmt.Errorf("failed to decode SQL response: %w", err) + } + + return result.Total, nil +} diff --git a/plugins/compliance-orchestrator/evaluator/evaluator.go b/plugins/compliance-orchestrator/evaluator/evaluator.go index 537caeb75..a80428b4e 100644 --- a/plugins/compliance-orchestrator/evaluator/evaluator.go +++ b/plugins/compliance-orchestrator/evaluator/evaluator.go @@ -17,70 +17,152 @@ func NewEvaluator(backend *client.BackendClient) *Evaluator { return &Evaluator{backend: backend} } -func (e *Evaluator) Evaluate(ctx context.Context, cfg models.ReportConfig) (models.Evaluation, error) { +func (e *Evaluator) Evaluate(ctx context.Context, cfg models.ControlConfig) (models.ControlEvaluation, error) { // 1. Obtener index patterns activos - _, err := e.backend.GetActiveIndexPatterns(ctx) + patterns, err := e.backend.GetActiveIndexPatterns(ctx) if err != nil { - return models.Evaluation{}, fmt.Errorf("failed to get index patterns: %w", err) + return models.ControlEvaluation{}, fmt.Errorf("failed to get index patterns: %w", err) } - // 2. Evaluar cada QuerySpec - /*var results []models.QueryResult*/ - for _, q := range cfg.Queries { - /*qr := e.evaluateQuery(ctx, q, patterns) - results = append(results, qr)*/ + results := make([]models.QueryEvaluation, 0) + applicable := make([]models.QueryEvaluation, 0) // solo queries con indexPattern activo + + // 2. Evaluar cada QueryConfig + for _, q := range cfg.QueriesConfigs { catcher.Info("Evaluating query", map[string]any{ "query_id": q.ID, }) - } - /*final := combineResults(cfg, results) + // 2.1 Si el index pattern NO está activo → NOT_APPLICABLE + if !patternExists(int(q.IndexPatternID), patterns) { + reason := "Index pattern not active" + qr := models.QueryEvaluation{ + QueryConfigID: q.ID, + QueryName: q.QueryName, + Hits: 0, + Status: models.QueryStatusNotApplicable, + ErrorMessage: &reason, + } + results = append(results, qr) + continue + } - return final, nil*/ + // 2.2 Evaluar query normalmente + qr := e.evaluateQuery(ctx, q) + results = append(results, qr) - return models.Evaluation{}, nil -} + // 2.3 Solo las queries aplicables participan en la estrategia ALL/ANY + if qr.Status != models.QueryStatusNotApplicable { + applicable = append(applicable, qr) + } + } + + // 3. Combinar resultados según la estrategia del control + finalStatus := computeControlStatus(cfg.ControlStrategy, applicable) -func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QuerySpec, patterns []models.IndexPattern) models.QueryResult { + // 4. Construir evaluación final + return models.ControlEvaluation{ + ControlConfigID: cfg.ID, + ControlName: cfg.ControlName, + Status: finalStatus, + QueryEvaluations: results, + }, nil +} - /*if !patternExists(q.IndexPatternID, patterns) { - return models.QueryResult{ - QueryID: int(q.ID), - Status: models.StatusNotApplicable, - Reason: "Index pattern not active", +func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) models.QueryEvaluation { + // Ejecutar la query SQL real contra OpenSearch + hits, err := e.backend.ExecuteSQLQuery(ctx, q.SQLQuery) + if err != nil { + msg := fmt.Sprintf("query execution failed: %v", err) + return models.QueryEvaluation{ + QueryConfigID: q.ID, + QueryName: q.QueryName, + Hits: 0, + Status: models.QueryStatusError, + ErrorMessage: &msg, } - }*/ + } + + // Evaluar la regla con los hits obtenidos + status, errMsg := evaluateQueryRule(q, hits) - return models.QueryResult{ - QueryID: int(q.ID), - Status: models.StatusCompliant, - Reason: "Query executed successfully (placeholder)", + return models.QueryEvaluation{ + QueryConfigID: q.ID, + QueryName: q.QueryName, + Hits: int64(hits), + Status: status, + ErrorMessage: errMsg, } } -func patternExists(pattern int, active []models.IndexPattern) bool { - for _, p := range active { - if p.ID == pattern && p.Active { - return true +func evaluateQueryRule(q models.QueryConfig, hits int) (models.QueryEvaluationStatus, *string) { + switch q.EvaluationRule { + + case models.NoHitsAllowed: + if hits == 0 { + return models.QueryStatusCompliant, nil + } + return models.QueryStatusNonCompliant, nil + + case models.MinHitsRequired: + if q.RuleValue == nil { + msg := "ruleValue is required for MIN_HITS_REQUIRED" + return models.QueryStatusError, &msg } + if hits >= *q.RuleValue { + return models.QueryStatusCompliant, nil + } + return models.QueryStatusNonCompliant, nil + + case models.ThresholdMax: + if q.RuleValue == nil { + msg := "ruleValue is required for THRESHOLD_MAX" + return models.QueryStatusError, &msg + } + if hits <= *q.RuleValue { + return models.QueryStatusCompliant, nil + } + return models.QueryStatusNonCompliant, nil + + default: + msg := "unknown evaluation rule" + return models.QueryStatusError, &msg } - return false } -func combineResults(cfg models.ReportConfig, results []models.QueryResult) models.Evaluation { - final := models.Evaluation{ - ReportID: int(cfg.ID), - Results: results, - } +func computeControlStatus(strategy models.ComplianceStrategy, results []models.QueryEvaluation) models.ControlEvaluationStatus { - // Estrategia simple: si alguna query es NON_COMPLIANT → NON_COMPLIANT - for _, r := range results { - if r.Status == models.StatusNonCompliant { - final.Status = models.StatusNonCompliant - return final + switch strategy { + + case models.StrategyAll: + // ALL → todas deben ser COMPLIANT + for _, r := range results { + if r.Status != models.QueryStatusCompliant { + return models.ControlStatusNonCompliant + } + } + return models.ControlStatusCompliant + + case models.StrategyAny: + // ANY → basta con que una sea COMPLIANT + for _, r := range results { + if r.Status == models.QueryStatusCompliant { + return models.ControlStatusCompliant + } } + return models.ControlStatusNonCompliant + + default: + // fallback seguro + return models.ControlStatusNonCompliant } +} - final.Status = models.StatusCompliant - return final +func patternExists(pattern int, active []models.IndexPattern) bool { + for _, p := range active { + if int(p.ID) == pattern && p.Active { + return true + } + } + return false } diff --git a/plugins/compliance-orchestrator/models/constant.go b/plugins/compliance-orchestrator/models/constant.go index a1c2427fa..c7ea48aee 100644 --- a/plugins/compliance-orchestrator/models/constant.go +++ b/plugins/compliance-orchestrator/models/constant.go @@ -1,8 +1,32 @@ package models +type QueryEvaluationStatus string + +const ( + QueryStatusCompliant QueryEvaluationStatus = "COMPLIANT" + QueryStatusNonCompliant QueryEvaluationStatus = "NON_COMPLIANT" + QueryStatusNotApplicable QueryEvaluationStatus = "NOT_APPLICABLE" + QueryStatusError QueryEvaluationStatus = "ERROR" +) + +type ControlEvaluationStatus string + +const ( + ControlStatusCompliant ControlEvaluationStatus = "COMPLIANT" + ControlStatusNonCompliant ControlEvaluationStatus = "NON_COMPLIANT" +) + +type EvaluationRule string + +const ( + NoHitsAllowed EvaluationRule = "NO_HITS_ALLOWED" + MinHitsRequired EvaluationRule = "MIN_HITS_REQUIRED" + ThresholdMax EvaluationRule = "THRESHOLD_MAX" +) + +type ComplianceStrategy string + const ( - StatusCompliant = "COMPLIANT" - StatusNonCompliant = "NON_COMPLIANT" - StatusNotApplicable = "NOT_APPLICABLE" - StatusError = "ERROR" + StrategyAll ComplianceStrategy = "ALL" + StrategyAny ComplianceStrategy = "ANY" ) diff --git a/plugins/compliance-orchestrator/models/control_evaluation.go b/plugins/compliance-orchestrator/models/control_evaluation.go new file mode 100644 index 000000000..4e9f483da --- /dev/null +++ b/plugins/compliance-orchestrator/models/control_evaluation.go @@ -0,0 +1,11 @@ +package models + +import "time" + +type ControlEvaluation struct { + ControlConfigID int64 `json:"controlConfigId"` + ControlName string `json:"controlName"` + Status ControlEvaluationStatus `json:"status"` + QueryEvaluations []QueryEvaluation `json:"queryevaluations"` + EvaluatedAt time.Time `json:"evaluatedAt"` +} diff --git a/plugins/compliance-orchestrator/models/evaluation.go b/plugins/compliance-orchestrator/models/evaluation.go deleted file mode 100644 index 8071cbd6b..000000000 --- a/plugins/compliance-orchestrator/models/evaluation.go +++ /dev/null @@ -1,7 +0,0 @@ -package models - -type Evaluation struct { - ReportID int `json:"reportId"` - Status string `json:"status"` - Results []QueryResult `json:"results"` -} diff --git a/plugins/compliance-orchestrator/models/evaluation_document.go b/plugins/compliance-orchestrator/models/evaluation_document.go new file mode 100644 index 000000000..3c748a59e --- /dev/null +++ b/plugins/compliance-orchestrator/models/evaluation_document.go @@ -0,0 +1,11 @@ +package models + +import "time" + +type EvaluationDocument struct { + ControlID int64 `json:"control_id"` + ControlName string `json:"control_name"` + Status ControlEvaluationStatus `json:"status"` + Timestamp time.Time `json:"timestamp"` + QueryEvaluations []QueryEvaluation `json:"query_evaluations"` +} diff --git a/plugins/compliance-orchestrator/models/query_evaluation.go b/plugins/compliance-orchestrator/models/query_evaluation.go new file mode 100644 index 000000000..6ae7d626b --- /dev/null +++ b/plugins/compliance-orchestrator/models/query_evaluation.go @@ -0,0 +1,10 @@ +package models + +type QueryEvaluation struct { + QueryConfigID int64 `json:"queryConfigId"` + QueryName string `json:"queryName"` + Hits int64 `json:"hits"` + Status QueryEvaluationStatus `json:"status"` + ErrorMessage *string `json:"errorMessage,omitempty"` + Evidence [][]any `json:"evidence,omitempty"` +} diff --git a/plugins/compliance-orchestrator/models/query_result.go b/plugins/compliance-orchestrator/models/query_result.go deleted file mode 100644 index ef94a8501..000000000 --- a/plugins/compliance-orchestrator/models/query_result.go +++ /dev/null @@ -1,7 +0,0 @@ -package models - -type QueryResult struct { - QueryID int `json:"queryId"` - Status string `json:"status"` - Reason string `json:"reason"` -} diff --git a/plugins/compliance-orchestrator/models/report_config.go b/plugins/compliance-orchestrator/models/report_config.go index 9d08e0d93..247edcf70 100644 --- a/plugins/compliance-orchestrator/models/report_config.go +++ b/plugins/compliance-orchestrator/models/report_config.go @@ -1,37 +1,30 @@ package models -type ReportConfig struct { - ID int64 `json:"id"` - ConfigSolution string `json:"configSolution"` - ConfigRemediation *string `json:"configRemediation"` - StandardSectionID int64 `json:"standardSectionId"` - DashboardID int64 `json:"dashboardId"` - ConfigType string `json:"configType"` - ConfigReportName string `json:"configReportName"` - Section *Section `json:"section"` - Queries []QuerySpec `json:"queries"` +type ControlConfig struct { + ID int64 `json:"id"` + StandardSectionID int64 `json:"standardSectionId"` + Section Section `json:"section"` + ControlName string `json:"controlName"` + ControlSolution string `json:"controlSolution"` + ControlRemediation string `json:"controlRemediation"` + ControlStrategy ComplianceStrategy `json:"controlStrategy"` + QueriesConfigs []QueryConfig `json:"queriesConfigs"` } type Section struct { - ID int64 `json:"id"` - StandardID int64 `json:"standardId"` - StandardSectionName string `json:"standardSectionName"` - StandardSectionDescription string `json:"standardSectionDescription"` - Standard *Standard `json:"standard"` + ID int64 `json:"id"` + StandardSectionName string `json:"standardSectionName"` + StandardSectionDescription string `json:"standardSectionDescription"` + StandardID int64 `json:"standardId"` } -type Standard struct { - ID int64 `json:"id"` - StandardName string `json:"standardName"` - StandardDescription string `json:"standardDescription"` - SystemOwner bool `json:"systemOwner"` -} - -type QuerySpec struct { - ID int64 `json:"id"` - Description string `json:"queryDescription"` - SQLQuery string `json:"sqlQuery"` - EvaluationRule string `json:"evaluationRule"` - IndexPatternID int64 `json:"indexPatternId"` - ControlConfigID int64 `json:"controlConfigId"` +type QueryConfig struct { + ID int64 `json:"id"` + QueryName string `json:"queryName"` + QueryDescription string `json:"queryDescription"` + SQLQuery string `json:"sqlQuery"` + EvaluationRule EvaluationRule `json:"evaluationRule"` + RuleValue *int `json:"ruleValue"` + IndexPatternID int64 `json:"indexPatternId"` + ControlConfigID int64 `json:"controlConfigId"` } diff --git a/plugins/compliance-orchestrator/scheduler/scheduler.go b/plugins/compliance-orchestrator/scheduler/scheduler.go index 69b061ed2..8ea4d6bec 100644 --- a/plugins/compliance-orchestrator/scheduler/scheduler.go +++ b/plugins/compliance-orchestrator/scheduler/scheduler.go @@ -9,10 +9,10 @@ import ( "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/models" ) -var Jobs chan models.ReportConfig +var Jobs chan models.ControlConfig func StartScheduler(ctx context.Context, backend *client.BackendClient) { - Jobs = make(chan models.ReportConfig, 1000) + Jobs = make(chan models.ControlConfig, 1000) ticker := time.NewTicker(30 * time.Second) @@ -23,7 +23,7 @@ func StartScheduler(ctx context.Context, backend *client.BackendClient) { return case <-ticker.C: - configs, err := backend.GetReportConfigs(ctx) + configs, err := backend.GetControlConfigs(ctx) if err != nil { continue } diff --git a/plugins/compliance-orchestrator/workers/worker.go b/plugins/compliance-orchestrator/workers/worker.go index 57032d8db..80a766b50 100644 --- a/plugins/compliance-orchestrator/workers/worker.go +++ b/plugins/compliance-orchestrator/workers/worker.go @@ -2,11 +2,14 @@ package workers import ( "context" + "fmt" "runtime" + "time" "github.com/threatwinds/go-sdk/catcher" "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/client" "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/evaluator" + "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/models" "github.com/utmstack/UTMStack/plugins/compliance-orchestrator/scheduler" ) @@ -20,25 +23,46 @@ func StartWorkers(ctx context.Context, backend *client.BackendClient) { for cfg := range scheduler.Jobs { - // Log opcional catcher.Info("Worker evaluating control", map[string]any{ "worker": id, "control": cfg.ID, }) - // Ejecutar evaluación real - _, err := eval.Evaluate(ctx, cfg) + // Ejecutar evaluación del control (incluye todas las queries) + result, err := eval.Evaluate(ctx, cfg) if err != nil { - // catcher.New("evaluation failed"). - // Set("worker", id). - // Set("control", cfg.ID). - // SetError(err). - // Log() + catcher.Error("evaluation failed", err, map[string]any{ + "worker": id, + "control": cfg.ID, + }) continue } - // Aquí luego enviarás el resultado al sender - // sender.Send(result) + // Construir documento para guardar en OpenSearch + doc := models.EvaluationDocument{ + ControlID: cfg.ID, + ControlName: cfg.ControlName, + Status: result.Status, + Timestamp: time.Now().UTC(), + QueryEvaluations: result.QueryEvaluations, + } + + // Guardar en OpenSearch + fmt.Println("Evaluation Document:", doc) + err = backend.IndexEvaluationResult(ctx, "v11-log-compliance-evaluation", doc) + if err != nil { + catcher.Error("failed to index evaluation result", err, map[string]any{ + "worker": id, + "control": cfg.ID, + }) + continue + } + + catcher.Info("Control Evaluation stored successfully", map[string]any{ + "worker": id, + "control": cfg.ID, + "status": result.Status, + }) } }(i) } From 94a84f550c82ddeafeaed77eb2f9b4b08bbedc9f Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Sun, 15 Feb 2026 16:50:30 -0600 Subject: [PATCH 027/135] feat: implement compliance orchestrator backend client and evaluation logic --- .../com/park/utmstack/config/Constants.java | 2 +- .../UtmComplianceControlConfigService.java | 1 - ...UtmComplianceControlEvaluationService.java | 23 ++++++++++ .../UtmComplianceControlEvaluationDto.java | 19 ++++++++ .../UtmComplianceQueryEvaluationDto.java | 19 ++++++++ .../elasticsearch/ElasticsearchService.java | 19 ++++++++ .../UtmComplianceControlEvaluationMapper.java | 43 +++++++++++++++++++ ...tmComplianceControlEvaluationResource.java | 26 +++++++++++ .../client/opensearch.go | 20 ++++++--- .../client/opensearch_result.go | 6 +++ .../evaluator/evaluator.go | 25 +++++++++-- .../models/query_evaluation.go | 2 +- 12 files changed, 192 insertions(+), 13 deletions(-) create mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java create mode 100644 backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java create mode 100644 backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java create mode 100644 plugins/compliance-orchestrator/client/opensearch_result.go diff --git a/backend/src/main/java/com/park/utmstack/config/Constants.java b/backend/src/main/java/com/park/utmstack/config/Constants.java index 96d7535d0..f4651ee14 100644 --- a/backend/src/main/java/com/park/utmstack/config/Constants.java +++ b/backend/src/main/java/com/park/utmstack/config/Constants.java @@ -164,7 +164,7 @@ public final class Constants { public static final List API_ENDPOINT_IGNORE = Collections.emptyList(); // Application version file - public static final String APP_VERSION_FILE = "/updates/version.json"; + public static final String APP_VERSION_FILE = "/Users/elena/Documents/Work/UTM Stack/version.json"; //TODO: ELENA public static final String ADMIN_EMAIL = "admin@localhost"; diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 433b2b854..e44c6bb7d 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -11,7 +11,6 @@ import org.springframework.stereotype.Service; import javax.transaction.Transactional; -import java.util.List; import java.util.Map; import java.util.stream.Collectors; diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java new file mode 100644 index 000000000..56715b1b0 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java @@ -0,0 +1,23 @@ +package com.park.utmstack.service.compliance.config; + +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; +import com.park.utmstack.service.elasticsearch.ElasticsearchService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UtmComplianceControlEvaluationService { + + private final ElasticsearchService elasticsearchService; + + public UtmComplianceControlEvaluationService(ElasticsearchService elasticsearchService) { + this.elasticsearchService = elasticsearchService; + } + + public List findByControlId(Long controlId) { + return elasticsearchService.getControlEvaluations(controlId); + } +} + + diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java new file mode 100644 index 000000000..0170adb70 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java @@ -0,0 +1,19 @@ +package com.park.utmstack.service.dto.compliance; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +import java.time.Instant; +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class UtmComplianceControlEvaluationDto { + + private Long controlId; + private String controlName; + private String status; + private Instant timestamp; + private List queryEvaluations; +} + diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java new file mode 100644 index 000000000..8c1649098 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java @@ -0,0 +1,19 @@ +package com.park.utmstack.service.dto.compliance; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class UtmComplianceQueryEvaluationDto { + + private Long queryConfigId; + private String queryName; + private Integer hits; + private String status; + private String errorMessage; + private List> evidence; +} diff --git a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java index d70b28f45..e2a8fb719 100644 --- a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java +++ b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java @@ -10,6 +10,8 @@ import com.park.utmstack.service.MailService; import com.park.utmstack.service.UtmSpaceNotificationControlService; import com.park.utmstack.service.application_events.ApplicationEventService; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationMapper; import com.park.utmstack.util.chart_builder.IndexPropertyType; import com.park.utmstack.util.exceptions.OpenSearchIndexNotFoundException; import com.park.utmstack.util.exceptions.UtmElasticsearchException; @@ -20,6 +22,7 @@ import com.utmstack.opensearch_connector.types.IndexSort; import com.utmstack.opensearch_connector.types.SearchSqlResponse; import com.utmstack.opensearch_connector.types.SqlQueryRequest; +import org.opensearch.client.opensearch._types.FieldValue; import org.opensearch.client.opensearch._types.SortOrder; import org.opensearch.client.opensearch._types.query_dsl.Query; import org.opensearch.client.opensearch.cat.indices.IndicesRecord; @@ -403,4 +406,20 @@ public SearchSqlResponse searchBySql(SqlQueryRequest request, Class re throw new RuntimeException(ctx + ": " + e.getMessage()); } } + + public List getControlEvaluations(Long controlId) { + final String ctx = CLASSNAME + ".getControlEvaluations"; + try { + Query query = Query.of(q -> q.term(t -> t.field("control_id").value(FieldValue.of(controlId.toString()))) + ); + + SearchRequest request = new SearchRequest.Builder().index("v11-log-compliance-evaluation").query(query).size(1000).build(); + SearchResponse response = search(request, Map.class); + + return response.hits().hits().stream().map(hit -> UtmComplianceControlEvaluationMapper.mapToEvaluationDto(hit.source())).toList(); + + } catch (Exception e) { + throw new RuntimeException(ctx + ": " + e.getMessage(), e); + } + } } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java new file mode 100644 index 000000000..5472e4a90 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java @@ -0,0 +1,43 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceQueryEvaluationDto; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public class UtmComplianceControlEvaluationMapper { + + private UtmComplianceControlEvaluationMapper() { + + } + + public static UtmComplianceControlEvaluationDto mapToEvaluationDto(Map src) { + UtmComplianceControlEvaluationDto dto = new UtmComplianceControlEvaluationDto(); + + dto.setControlId(((Number) src.get("control_id")).longValue()); + dto.setControlName((String) src.get("control_name")); + dto.setStatus((String) src.get("status")); + dto.setTimestamp(Instant.parse((String) src.get("timestamp"))); + + List> q = (List>) src.get("query_evaluations"); + if (q != null) { + dto.setQueryEvaluations(q.stream().map(UtmComplianceControlEvaluationMapper::mapQueryEval).toList()); + } + + return dto; + } + + private static UtmComplianceQueryEvaluationDto mapQueryEval(Map src) { + UtmComplianceQueryEvaluationDto dto = new UtmComplianceQueryEvaluationDto(); + + dto.setQueryConfigId(((Number) src.get("queryConfigId")).longValue()); + dto.setQueryName((String) src.get("queryName")); + dto.setHits(((Number) src.get("hits")).intValue()); + dto.setStatus((String) src.get("status")); + dto.setEvidence((List>) src.get("evidence")); + + return dto; + } +} diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java new file mode 100644 index 000000000..c2bac1756 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java @@ -0,0 +1,26 @@ +package com.park.utmstack.web.rest.compliance.config; + +import com.park.utmstack.service.compliance.config.UtmComplianceControlEvaluationService; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/compliance/control-config") +public class UtmComplianceControlEvaluationResource { + + private final UtmComplianceControlEvaluationService evaluationService; + + public UtmComplianceControlEvaluationResource(UtmComplianceControlEvaluationService evaluationService) { + this.evaluationService = evaluationService; + } + + @GetMapping("/{id}/evaluations") + public ResponseEntity> getControlEvaluations(@PathVariable Long id) { + var evaluations = evaluationService.findByControlId(id); + return ResponseEntity.ok(evaluations); + } +} + diff --git a/plugins/compliance-orchestrator/client/opensearch.go b/plugins/compliance-orchestrator/client/opensearch.go index 75ad808af..5c3f5ec72 100644 --- a/plugins/compliance-orchestrator/client/opensearch.go +++ b/plugins/compliance-orchestrator/client/opensearch.go @@ -30,10 +30,12 @@ func ConnectOpenSearch() error { } type SQLResponse struct { - Total int `json:"total"` + Schema []any `json:"schema"` + DataRows [][]any `json:"datarows"` + Total int `json:"total"` } -func (b *BackendClient) ExecuteSQLQuery(ctx context.Context, sql string) (int, error) { +func (b *BackendClient) ExecuteSQLQuery(ctx context.Context, sql string) (SQLResult, error) { baseURL := plugins.PluginCfg("org.opensearch", false).Get("opensearch").String() sqlEndpoint := fmt.Sprintf("%s/_plugins/_sql", baseURL) @@ -43,26 +45,30 @@ func (b *BackendClient) ExecuteSQLQuery(ctx context.Context, sql string) (int, e jsonBody, err := json.Marshal(body) if err != nil { - return 0, fmt.Errorf("failed to marshal SQL body: %w", err) + return SQLResult{}, fmt.Errorf("failed to marshal SQL body: %w", err) } req, err := http.NewRequestWithContext(ctx, "POST", sqlEndpoint, bytes.NewBuffer(jsonBody)) if err != nil { - return 0, fmt.Errorf("failed to create SQL request: %w", err) + return SQLResult{}, fmt.Errorf("failed to create SQL request: %w", err) } req.Header.Set("Content-Type", "application/json") resp, err := b.httpClient.Do(req) if err != nil { - return 0, fmt.Errorf("SQL request failed: %w", err) + return SQLResult{}, fmt.Errorf("SQL request failed: %w", err) } defer resp.Body.Close() var result SQLResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { - return 0, fmt.Errorf("failed to decode SQL response: %w", err) + return SQLResult{}, fmt.Errorf("failed to decode SQL response: %w", err) } - return result.Total, nil + // Convertir a tu tipo interno + return SQLResult{ + Rows: result.DataRows, + Count: result.Total, + }, nil } diff --git a/plugins/compliance-orchestrator/client/opensearch_result.go b/plugins/compliance-orchestrator/client/opensearch_result.go new file mode 100644 index 000000000..8911c1335 --- /dev/null +++ b/plugins/compliance-orchestrator/client/opensearch_result.go @@ -0,0 +1,6 @@ +package client + +type SQLResult struct { + Rows [][]any + Count int +} diff --git a/plugins/compliance-orchestrator/evaluator/evaluator.go b/plugins/compliance-orchestrator/evaluator/evaluator.go index a80428b4e..71e9d3bda 100644 --- a/plugins/compliance-orchestrator/evaluator/evaluator.go +++ b/plugins/compliance-orchestrator/evaluator/evaluator.go @@ -71,7 +71,7 @@ func (e *Evaluator) Evaluate(ctx context.Context, cfg models.ControlConfig) (mod func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) models.QueryEvaluation { // Ejecutar la query SQL real contra OpenSearch - hits, err := e.backend.ExecuteSQLQuery(ctx, q.SQLQuery) + res, err := e.backend.ExecuteSQLQuery(ctx, q.SQLQuery) if err != nil { msg := fmt.Sprintf("query execution failed: %v", err) return models.QueryEvaluation{ @@ -80,18 +80,37 @@ func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) mod Hits: 0, Status: models.QueryStatusError, ErrorMessage: &msg, + Evidence: nil, } } + // Limitar evidencia (por ejemplo, a 50 filas) + const evidenceLimit = 50 + rawRows := res.Rows + if len(rawRows) > evidenceLimit { + rawRows = rawRows[:evidenceLimit] + } + + // Convertir [][]any → []map[string]any para OpenSearch + evidence := make([]map[string]any, 0, len(rawRows)) + for _, row := range rawRows { + rowMap := map[string]any{} + for i, col := range row { + rowMap[fmt.Sprintf("col_%d", i)] = col + } + evidence = append(evidence, rowMap) + } + // Evaluar la regla con los hits obtenidos - status, errMsg := evaluateQueryRule(q, hits) + status, errMsg := evaluateQueryRule(q, res.Count) return models.QueryEvaluation{ QueryConfigID: q.ID, QueryName: q.QueryName, - Hits: int64(hits), + Hits: int64(res.Count), Status: status, ErrorMessage: errMsg, + Evidence: evidence, } } diff --git a/plugins/compliance-orchestrator/models/query_evaluation.go b/plugins/compliance-orchestrator/models/query_evaluation.go index 6ae7d626b..02d08539b 100644 --- a/plugins/compliance-orchestrator/models/query_evaluation.go +++ b/plugins/compliance-orchestrator/models/query_evaluation.go @@ -6,5 +6,5 @@ type QueryEvaluation struct { Hits int64 `json:"hits"` Status QueryEvaluationStatus `json:"status"` ErrorMessage *string `json:"errorMessage,omitempty"` - Evidence [][]any `json:"evidence,omitempty"` + Evidence []map[string]any `json:"evidence,omitempty"` } From 2c44b06d1b137bbba95a94835db400b1da3773b2 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 25 Feb 2026 14:34:28 -0600 Subject: [PATCH 028/135] feat: provide endpoint for OpenSearch evaluations including latest evaluation calculation per control --- .../UtmComplianceControlConfigRepository.java | 10 +++ .../UtmComplianceControlConfigService.java | 9 +++ ...UtmComplianceControlEvaluationService.java | 29 +++++++-- ...tmComplianceControlEvaluationsService.java | 25 ++++++++ .../UtmComplianceControlEvaluationDto.java | 20 +++--- .../UtmComplianceControlEvaluationsDto.java | 18 ++++++ .../elasticsearch/ElasticsearchService.java | 46 ++++++++++++-- .../UtmComplianceControlEvaluationMapper.java | 63 ++++++++++++------- ...UtmComplianceControlEvaluationsMapper.java | 43 +++++++++++++ ...tmComplianceControlEvaluationResource.java | 10 +-- ...mComplianceControlEvaluationsResource.java | 26 ++++++++ 11 files changed, 255 insertions(+), 44 deletions(-) create mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsDto.java create mode 100644 backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java create mode 100644 backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java index 7c504aec5..c9af7b0a2 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java @@ -7,6 +7,7 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @@ -19,4 +20,13 @@ public interface UtmComplianceControlConfigRepository extends JpaRepository findByIdWithQueries(@Param("id") Long id); + + @Query(""" + SELECT DISTINCT c FROM UtmComplianceControlConfig c + LEFT JOIN FETCH c.section s + LEFT JOIN FETCH c.queriesConfigs q + WHERE c.standardSectionId = :sectionId + """) + List findBySectionIdWithQueries(@Param("sectionId") Long sectionId); + } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index e44c6bb7d..c703896a6 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -11,6 +11,7 @@ import org.springframework.stereotype.Service; import javax.transaction.Transactional; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -108,4 +109,12 @@ private void validateControlConfig(UtmComplianceControlConfigDto dto) { } } } + + public List getControlsBySection(Long sectionId) { + var entities = repository.findBySectionIdWithQueries(sectionId); + return entities.stream() + .map(mapper::toDto) + .collect(Collectors.toList()); + } + } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java index 56715b1b0..42989b799 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java @@ -1,7 +1,9 @@ package com.park.utmstack.service.compliance.config; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; import com.park.utmstack.service.elasticsearch.ElasticsearchService; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationMapper; import org.springframework.stereotype.Service; import java.util.List; @@ -9,15 +11,30 @@ @Service public class UtmComplianceControlEvaluationService { - private final ElasticsearchService elasticsearchService; + //private final ElasticsearchService elasticsearchService; + private final UtmComplianceControlConfigService configService; + private final UtmComplianceControlEvaluationsService evaluationsService; - public UtmComplianceControlEvaluationService(ElasticsearchService elasticsearchService) { - this.elasticsearchService = elasticsearchService; + public UtmComplianceControlEvaluationService(ElasticsearchService elasticsearchService, + UtmComplianceControlConfigService configService, + UtmComplianceControlEvaluationsService evaluationsService) { + //this.elasticsearchService = elasticsearchService; + this.configService = configService; + this.evaluationsService = evaluationsService; } - public List findByControlId(Long controlId) { - return elasticsearchService.getControlEvaluations(controlId); + public List getControlsWithLastEvaluation(Long sectionId) { + + List controls = + configService.getControlsBySection(sectionId); + + return controls.stream() + .map(control -> { + var lastEval = evaluationsService.getLastEvaluationForControl(control.getId()); + return UtmComplianceControlEvaluationMapper.toDto(control, lastEval); + }) + .toList(); + } } -} diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java new file mode 100644 index 000000000..e7e49026c --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java @@ -0,0 +1,25 @@ +package com.park.utmstack.service.compliance.config; + +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; +import com.park.utmstack.service.elasticsearch.ElasticsearchService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UtmComplianceControlEvaluationsService { + + private final ElasticsearchService elasticsearchService; + + public UtmComplianceControlEvaluationsService(ElasticsearchService elasticsearchService) { + this.elasticsearchService = elasticsearchService; + } + + public List findByControlId(Long controlId) { + return elasticsearchService.getControlEvaluations(controlId); + } + + public UtmComplianceControlEvaluationsDto getLastEvaluationForControl(Long controlId) { + return elasticsearchService.getLastEvaluation(controlId); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java index 0170adb70..75f06b900 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java @@ -1,19 +1,23 @@ package com.park.utmstack.service.dto.compliance; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.park.utmstack.domain.compliance.enums.ComplianceStrategy; import lombok.Data; -import java.time.Instant; import java.util.List; @Data -@JsonIgnoreProperties(ignoreUnknown = true) public class UtmComplianceControlEvaluationDto { + private Long id; + private Long standardSectionId; + private UtmComplianceStandardSectionDto section; - private Long controlId; private String controlName; - private String status; - private Instant timestamp; - private List queryEvaluations; -} + private String controlSolution; + private String controlRemediation; + private ComplianceStrategy controlStrategy; + + private List queriesConfigs; + private String lastEvaluationStatus; + private String lastEvaluationTimestamp; +} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsDto.java new file mode 100644 index 000000000..f16587681 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsDto.java @@ -0,0 +1,18 @@ +package com.park.utmstack.service.dto.compliance; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +import java.time.Instant; +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class UtmComplianceControlEvaluationsDto { + private Long controlId; + private String controlName; + private String status; + private Instant timestamp; + private List queryEvaluations; +} + diff --git a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java index e2a8fb719..5035cb151 100644 --- a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java +++ b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java @@ -10,8 +10,9 @@ import com.park.utmstack.service.MailService; import com.park.utmstack.service.UtmSpaceNotificationControlService; import com.park.utmstack.service.application_events.ApplicationEventService; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationMapper; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationsMapper; import com.park.utmstack.util.chart_builder.IndexPropertyType; import com.park.utmstack.util.exceptions.OpenSearchIndexNotFoundException; import com.park.utmstack.util.exceptions.UtmElasticsearchException; @@ -407,19 +408,54 @@ public SearchSqlResponse searchBySql(SqlQueryRequest request, Class re } } - public List getControlEvaluations(Long controlId) { + public List getControlEvaluations(Long controlId) { final String ctx = CLASSNAME + ".getControlEvaluations"; try { - Query query = Query.of(q -> q.term(t -> t.field("control_id").value(FieldValue.of(controlId.toString()))) + Query query = Query.of(q -> q.term(t -> t + .field("control_id") + .value(FieldValue.of(controlId.toString()))) ); - SearchRequest request = new SearchRequest.Builder().index("v11-log-compliance-evaluation").query(query).size(1000).build(); + SearchRequest request = new SearchRequest.Builder() + .index("v11-log-compliance-evaluation") + .query(query) + .size(1000) + .build(); + SearchResponse response = search(request, Map.class); - return response.hits().hits().stream().map(hit -> UtmComplianceControlEvaluationMapper.mapToEvaluationDto(hit.source())).toList(); + return response.hits().hits().stream().map(hit -> UtmComplianceControlEvaluationsMapper.mapToEvaluationDto(hit.source())).toList(); } catch (Exception e) { throw new RuntimeException(ctx + ": " + e.getMessage(), e); } } + + public UtmComplianceControlEvaluationsDto getLastEvaluation(Long controlId) { + try { + SearchRequest request = new SearchRequest.Builder() + .index("v11-log-compliance-evaluation") + .query(q -> q.term(t -> t + .field("control_id") + .value(v -> v.longValue(controlId)) + )) + .sort(s -> s.field(f -> f.field("timestamp").order(SortOrder.Desc))) + .size(1) + .build(); + + SearchResponse response = client.getClient().search(request, Map.class); + + if (response.hits().hits().isEmpty()) { + return null; + } + + Map source = response.hits().hits().get(0).source(); + + return UtmComplianceControlEvaluationMapper.mapToEvaluationDto(source); + + } catch (Exception e) { + throw new RuntimeException("Error fetching last evaluation for control " + controlId, e); + } + } + } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java index 5472e4a90..6145079fe 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java @@ -1,43 +1,64 @@ package com.park.utmstack.service.mapper.compliance; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceQueryEvaluationDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; import java.time.Instant; -import java.util.List; import java.util.Map; public class UtmComplianceControlEvaluationMapper { - private UtmComplianceControlEvaluationMapper() { - - } - - public static UtmComplianceControlEvaluationDto mapToEvaluationDto(Map src) { + public static UtmComplianceControlEvaluationDto toDto( + UtmComplianceControlConfigDto control, + UtmComplianceControlEvaluationsDto controlEvaluations + ) { UtmComplianceControlEvaluationDto dto = new UtmComplianceControlEvaluationDto(); - dto.setControlId(((Number) src.get("control_id")).longValue()); - dto.setControlName((String) src.get("control_name")); - dto.setStatus((String) src.get("status")); - dto.setTimestamp(Instant.parse((String) src.get("timestamp"))); + dto.setId(control.getId()); + dto.setStandardSectionId(control.getStandardSectionId()); + dto.setSection(control.getSection()); + dto.setControlName(control.getControlName()); + dto.setControlSolution(control.getControlSolution()); + dto.setControlRemediation(control.getControlRemediation()); + dto.setControlStrategy(control.getControlStrategy()); + dto.setQueriesConfigs(control.getQueriesConfigs()); - List> q = (List>) src.get("query_evaluations"); - if (q != null) { - dto.setQueryEvaluations(q.stream().map(UtmComplianceControlEvaluationMapper::mapQueryEval).toList()); + //TODO: ELENA - this is a temporary solution, we need to decide how to handle multiple evaluations for the same control + if (controlEvaluations != null) { + dto.setLastEvaluationStatus(controlEvaluations.getStatus()); + dto.setLastEvaluationTimestamp( + controlEvaluations.getTimestamp() != null ? controlEvaluations.getTimestamp().toString() : null + ); } return dto; } - private static UtmComplianceQueryEvaluationDto mapQueryEval(Map src) { - UtmComplianceQueryEvaluationDto dto = new UtmComplianceQueryEvaluationDto(); + public static UtmComplianceControlEvaluationsDto mapToEvaluationDto(Map source) { + if (source == null) return null; + + UtmComplianceControlEvaluationsDto dto = new UtmComplianceControlEvaluationsDto(); + + dto.setControlId(getLong(source.get("control_id"))); + dto.setControlName(getString(source.get("control_name"))); + dto.setStatus(getString(source.get("status"))); - dto.setQueryConfigId(((Number) src.get("queryConfigId")).longValue()); - dto.setQueryName((String) src.get("queryName")); - dto.setHits(((Number) src.get("hits")).intValue()); - dto.setStatus((String) src.get("status")); - dto.setEvidence((List>) src.get("evidence")); + Object ts = source.get("timestamp"); + if (ts != null) { + dto.setTimestamp(Instant.parse(ts.toString())); + } return dto; } + + private static String getString(Object o) { + return o != null ? o.toString() : null; + } + + private static Long getLong(Object o) { + if (o == null) return null; + if (o instanceof Number n) return n.longValue(); + return Long.parseLong(o.toString()); + } } diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java new file mode 100644 index 000000000..50c2058d0 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java @@ -0,0 +1,43 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceQueryEvaluationDto; + +import java.time.Instant; +import java.util.List; +import java.util.Map; + +public class UtmComplianceControlEvaluationsMapper { + + private UtmComplianceControlEvaluationsMapper() { + + } + + public static UtmComplianceControlEvaluationsDto mapToEvaluationDto(Map src) { + UtmComplianceControlEvaluationsDto dto = new UtmComplianceControlEvaluationsDto(); + + dto.setControlId(((Number) src.get("control_id")).longValue()); + dto.setControlName((String) src.get("control_name")); + dto.setStatus((String) src.get("status")); + dto.setTimestamp(Instant.parse((String) src.get("timestamp"))); + + List> q = (List>) src.get("query_evaluations"); + if (q != null) { + dto.setQueryEvaluations(q.stream().map(UtmComplianceControlEvaluationsMapper::mapQueryEval).toList()); + } + + return dto; + } + + private static UtmComplianceQueryEvaluationDto mapQueryEval(Map src) { + UtmComplianceQueryEvaluationDto dto = new UtmComplianceQueryEvaluationDto(); + + dto.setQueryConfigId(((Number) src.get("queryConfigId")).longValue()); + dto.setQueryName((String) src.get("queryName")); + dto.setHits(((Number) src.get("hits")).intValue()); + dto.setStatus((String) src.get("status")); + dto.setEvidence((List>) src.get("evidence")); + + return dto; + } +} diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java index c2bac1756..5c09f5b26 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java @@ -17,10 +17,12 @@ public UtmComplianceControlEvaluationResource(UtmComplianceControlEvaluationServ this.evaluationService = evaluationService; } - @GetMapping("/{id}/evaluations") - public ResponseEntity> getControlEvaluations(@PathVariable Long id) { - var evaluations = evaluationService.findByControlId(id); - return ResponseEntity.ok(evaluations); + @GetMapping("/get-by-section") + public ResponseEntity> getControlsBySection( + @RequestParam Long sectionId) { + + var controls = evaluationService.getControlsWithLastEvaluation(sectionId); + return ResponseEntity.ok(controls); } } diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java new file mode 100644 index 000000000..ab6ef3ffe --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java @@ -0,0 +1,26 @@ +package com.park.utmstack.web.rest.compliance.config; + +import com.park.utmstack.service.compliance.config.UtmComplianceControlEvaluationsService; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/compliance/control-config") +public class UtmComplianceControlEvaluationsResource { + + private final UtmComplianceControlEvaluationsService evaluationsService; + + public UtmComplianceControlEvaluationsResource(UtmComplianceControlEvaluationsService evaluationService) { + this.evaluationsService = evaluationService; + } + + @GetMapping("/{id}/evaluations") + public ResponseEntity> getControlEvaluations(@PathVariable Long id) { + var evaluations = evaluationsService.findByControlId(id); + return ResponseEntity.ok(evaluations); + } +} + From 07cc80af21407f4e0d9d4fb6da6b3f3440a81d9c Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Tue, 10 Mar 2026 15:02:46 -0500 Subject: [PATCH 029/135] feat: implement compliance orchestrator backend client and evaluation logic --- .../client/opensearch.go | 1 - .../evaluator/evaluator.go | 19 ++----------------- .../scheduler/scheduler.go | 16 ++++++++++++++-- .../compliance-orchestrator/workers/worker.go | 3 --- 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/plugins/compliance-orchestrator/client/opensearch.go b/plugins/compliance-orchestrator/client/opensearch.go index 5c3f5ec72..0b7b67a4b 100644 --- a/plugins/compliance-orchestrator/client/opensearch.go +++ b/plugins/compliance-orchestrator/client/opensearch.go @@ -66,7 +66,6 @@ func (b *BackendClient) ExecuteSQLQuery(ctx context.Context, sql string) (SQLRes return SQLResult{}, fmt.Errorf("failed to decode SQL response: %w", err) } - // Convertir a tu tipo interno return SQLResult{ Rows: result.DataRows, Count: result.Total, diff --git a/plugins/compliance-orchestrator/evaluator/evaluator.go b/plugins/compliance-orchestrator/evaluator/evaluator.go index 71e9d3bda..d7e68b728 100644 --- a/plugins/compliance-orchestrator/evaluator/evaluator.go +++ b/plugins/compliance-orchestrator/evaluator/evaluator.go @@ -18,22 +18,20 @@ func NewEvaluator(backend *client.BackendClient) *Evaluator { } func (e *Evaluator) Evaluate(ctx context.Context, cfg models.ControlConfig) (models.ControlEvaluation, error) { - // 1. Obtener index patterns activos + patterns, err := e.backend.GetActiveIndexPatterns(ctx) if err != nil { return models.ControlEvaluation{}, fmt.Errorf("failed to get index patterns: %w", err) } results := make([]models.QueryEvaluation, 0) - applicable := make([]models.QueryEvaluation, 0) // solo queries con indexPattern activo + applicable := make([]models.QueryEvaluation, 0) - // 2. Evaluar cada QueryConfig for _, q := range cfg.QueriesConfigs { catcher.Info("Evaluating query", map[string]any{ "query_id": q.ID, }) - // 2.1 Si el index pattern NO está activo → NOT_APPLICABLE if !patternExists(int(q.IndexPatternID), patterns) { reason := "Index pattern not active" qr := models.QueryEvaluation{ @@ -47,20 +45,16 @@ func (e *Evaluator) Evaluate(ctx context.Context, cfg models.ControlConfig) (mod continue } - // 2.2 Evaluar query normalmente qr := e.evaluateQuery(ctx, q) results = append(results, qr) - // 2.3 Solo las queries aplicables participan en la estrategia ALL/ANY if qr.Status != models.QueryStatusNotApplicable { applicable = append(applicable, qr) } } - // 3. Combinar resultados según la estrategia del control finalStatus := computeControlStatus(cfg.ControlStrategy, applicable) - // 4. Construir evaluación final return models.ControlEvaluation{ ControlConfigID: cfg.ID, ControlName: cfg.ControlName, @@ -70,7 +64,6 @@ func (e *Evaluator) Evaluate(ctx context.Context, cfg models.ControlConfig) (mod } func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) models.QueryEvaluation { - // Ejecutar la query SQL real contra OpenSearch res, err := e.backend.ExecuteSQLQuery(ctx, q.SQLQuery) if err != nil { msg := fmt.Sprintf("query execution failed: %v", err) @@ -84,14 +77,12 @@ func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) mod } } - // Limitar evidencia (por ejemplo, a 50 filas) const evidenceLimit = 50 rawRows := res.Rows if len(rawRows) > evidenceLimit { rawRows = rawRows[:evidenceLimit] } - // Convertir [][]any → []map[string]any para OpenSearch evidence := make([]map[string]any, 0, len(rawRows)) for _, row := range rawRows { rowMap := map[string]any{} @@ -101,7 +92,6 @@ func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) mod evidence = append(evidence, rowMap) } - // Evaluar la regla con los hits obtenidos status, errMsg := evaluateQueryRule(q, res.Count) return models.QueryEvaluation{ @@ -116,7 +106,6 @@ func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) mod func evaluateQueryRule(q models.QueryConfig, hits int) (models.QueryEvaluationStatus, *string) { switch q.EvaluationRule { - case models.NoHitsAllowed: if hits == 0 { return models.QueryStatusCompliant, nil @@ -152,9 +141,7 @@ func evaluateQueryRule(q models.QueryConfig, hits int) (models.QueryEvaluationSt func computeControlStatus(strategy models.ComplianceStrategy, results []models.QueryEvaluation) models.ControlEvaluationStatus { switch strategy { - case models.StrategyAll: - // ALL → todas deben ser COMPLIANT for _, r := range results { if r.Status != models.QueryStatusCompliant { return models.ControlStatusNonCompliant @@ -163,7 +150,6 @@ func computeControlStatus(strategy models.ComplianceStrategy, results []models.Q return models.ControlStatusCompliant case models.StrategyAny: - // ANY → basta con que una sea COMPLIANT for _, r := range results { if r.Status == models.QueryStatusCompliant { return models.ControlStatusCompliant @@ -172,7 +158,6 @@ func computeControlStatus(strategy models.ComplianceStrategy, results []models.Q return models.ControlStatusNonCompliant default: - // fallback seguro return models.ControlStatusNonCompliant } } diff --git a/plugins/compliance-orchestrator/scheduler/scheduler.go b/plugins/compliance-orchestrator/scheduler/scheduler.go index 8ea4d6bec..3a8be6b64 100644 --- a/plugins/compliance-orchestrator/scheduler/scheduler.go +++ b/plugins/compliance-orchestrator/scheduler/scheduler.go @@ -14,12 +14,24 @@ var Jobs chan models.ControlConfig func StartScheduler(ctx context.Context, backend *client.BackendClient) { Jobs = make(chan models.ControlConfig, 1000) - ticker := time.NewTicker(30 * time.Second) + ticker := time.NewTicker(24 * time.Hour) + + // TODO: ELENA QUITAR - Ejecutar inmediatamente + configs, err := backend.GetControlConfigs(ctx) + if err == nil { + catcher.Info("Scheduler: sending configs", map[string]any{ + "cantidad": len(configs), + "timestamp": time.Now().String(), + }) + + for _, cfg := range configs { + Jobs <- cfg + } + } // HASTA AQUI for { select { case <-ctx.Done(): - // Shutdown limpio return case <-ticker.C: diff --git a/plugins/compliance-orchestrator/workers/worker.go b/plugins/compliance-orchestrator/workers/worker.go index 80a766b50..cc9bdcc62 100644 --- a/plugins/compliance-orchestrator/workers/worker.go +++ b/plugins/compliance-orchestrator/workers/worker.go @@ -28,7 +28,6 @@ func StartWorkers(ctx context.Context, backend *client.BackendClient) { "control": cfg.ID, }) - // Ejecutar evaluación del control (incluye todas las queries) result, err := eval.Evaluate(ctx, cfg) if err != nil { catcher.Error("evaluation failed", err, map[string]any{ @@ -38,7 +37,6 @@ func StartWorkers(ctx context.Context, backend *client.BackendClient) { continue } - // Construir documento para guardar en OpenSearch doc := models.EvaluationDocument{ ControlID: cfg.ID, ControlName: cfg.ControlName, @@ -47,7 +45,6 @@ func StartWorkers(ctx context.Context, backend *client.BackendClient) { QueryEvaluations: result.QueryEvaluations, } - // Guardar en OpenSearch fmt.Println("Evaluation Document:", doc) err = backend.IndexEvaluationResult(ctx, "v11-log-compliance-evaluation", doc) if err != nil { From 3b39ba33146777b6f53d26e21321cdcffed6a00a Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Thu, 12 Mar 2026 17:27:41 -0500 Subject: [PATCH 030/135] feat: provide endpoint for OpenSearch evaluations including latest evaluation calculation per control --- ...UtmComplianceControlEvaluationService.java | 9 +- ...tmComplianceControlEvaluationsService.java | 212 +++++++++++++++++- .../ControlEvaluationsResponseDto.java | 17 ++ .../IndexPatternQueriesGroupDto.java | 12 + ...omplianceControlEvaluationsGroupedDto.java | 19 ++ .../UtmComplianceQueryEvaluationDto.java | 4 + .../elasticsearch/ElasticsearchService.java | 14 +- .../UtmComplianceControlEvaluationMapper.java | 5 +- ...mComplianceControlEvaluationsResource.java | 10 +- 9 files changed, 280 insertions(+), 22 deletions(-) create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/ControlEvaluationsResponseDto.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/IndexPatternQueriesGroupDto.java create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsGroupedDto.java diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java index 42989b799..5b6179f63 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java @@ -2,7 +2,6 @@ import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; -import com.park.utmstack.service.elasticsearch.ElasticsearchService; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationMapper; import org.springframework.stereotype.Service; @@ -11,22 +10,18 @@ @Service public class UtmComplianceControlEvaluationService { - //private final ElasticsearchService elasticsearchService; private final UtmComplianceControlConfigService configService; private final UtmComplianceControlEvaluationsService evaluationsService; - public UtmComplianceControlEvaluationService(ElasticsearchService elasticsearchService, - UtmComplianceControlConfigService configService, + public UtmComplianceControlEvaluationService(UtmComplianceControlConfigService configService, UtmComplianceControlEvaluationsService evaluationsService) { - //this.elasticsearchService = elasticsearchService; this.configService = configService; this.evaluationsService = evaluationsService; } public List getControlsWithLastEvaluation(Long sectionId) { - List controls = - configService.getControlsBySection(sectionId); + List controls = configService.getControlsBySection(sectionId); return controls.stream() .map(control -> { diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java index e7e49026c..d451b4de2 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java @@ -1,18 +1,27 @@ package com.park.utmstack.service.compliance.config; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; +import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; +import com.park.utmstack.repository.compliance.UtmComplianceQueryConfigRepository; +import com.park.utmstack.service.dto.compliance.*; import com.park.utmstack.service.elasticsearch.ElasticsearchService; import org.springframework.stereotype.Service; -import java.util.List; +import java.time.Instant; +import java.time.ZoneOffset; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; @Service public class UtmComplianceControlEvaluationsService { private final ElasticsearchService elasticsearchService; + private final UtmComplianceQueryConfigRepository queryConfigRepository; - public UtmComplianceControlEvaluationsService(ElasticsearchService elasticsearchService) { + public UtmComplianceControlEvaluationsService(ElasticsearchService elasticsearchService, + UtmComplianceQueryConfigRepository QueryConfigRepository) { this.elasticsearchService = elasticsearchService; + this.queryConfigRepository = QueryConfigRepository; } public List findByControlId(Long controlId) { @@ -20,6 +29,201 @@ public List findByControlId(Long controlId) } public UtmComplianceControlEvaluationsDto getLastEvaluationForControl(Long controlId) { - return elasticsearchService.getLastEvaluation(controlId); + return elasticsearchService.getLatestControlEvaluation(controlId); + } + + /*public ControlEvaluationsResponseDto getEvaluationsWithRange(Long controlId) { + var evaluations = findByControlId(controlId); + + if (evaluations.isEmpty()) { + return new ControlEvaluationsResponseDto(null, null, evaluations); + } + + var timestamps = evaluations.stream() + .map(UtmComplianceControlEvaluationsDto::getTimestamp) + .toList(); + + Instant min = timestamps.stream().min(Instant::compareTo).get(); + Instant max = timestamps.stream().max(Instant::compareTo).get(); + + LocalDate start = min.atZone(ZoneOffset.UTC).toLocalDate(); + LocalDate end = max.atZone(ZoneOffset.UTC).toLocalDate(); + + return new ControlEvaluationsResponseDto(start, end, evaluations); + }*/ + + /*public ControlEvaluationsResponseDto getEvaluationsWithRange(Long controlId) { + + // 1. Evaluaciones crudas desde OpenSearch - UtmComplianceControlEvaluationsDto + var evaluations = findByControlId(controlId); + + if (evaluations.isEmpty()) { + return new ControlEvaluationsResponseDto( + null, + null, + List.of() + ); + } + + // 2. Extraer todos los queryConfigId de todas las evaluaciones + var queryConfigIds = evaluations.stream() + .flatMap(ev -> ev.getQueryEvaluations().stream()) + .map(UtmComplianceQueryEvaluationDto::getQueryConfigId) + .collect(Collectors.toSet()); + + // 3. Lookup masivo en DB - UtmComplianceQueryConfig + var configs = queryConfigRepository.findAllById(queryConfigIds); + var configMap = configs.stream() + .collect(Collectors.toMap( + UtmComplianceQueryConfig::getId, + Function.identity() + )); + + // 4. Enriquecer cada query evaluation + evaluations.forEach(controlEval -> { + controlEval.getQueryEvaluations().forEach(queryEval -> { + var cfg = configMap.get(queryEval.getQueryConfigId()); + if (cfg != null) { + queryEval.setQueryDescription(cfg.getQueryDescription()); + queryEval.setEvaluationRule(cfg.getEvaluationRule().name()); + queryEval.setIndexPatternId(cfg.getIndexPattern().getId()); + queryEval.setIndexPatternName(cfg.getIndexPattern().getPattern()); + } + }); + }); + + // 5. Aplanar todas las queryEvaluations para agrupar por indexPattern + var allQueryEvaluations = evaluations.stream() + .flatMap(ev -> ev.getQueryEvaluations().stream()) + .toList(); + + // 6. Agrupar por indexPattern + var groupedEvaluations = allQueryEvaluations.stream() + .collect(Collectors.groupingBy(UtmComplianceQueryEvaluationDto::getIndexPatternId)) + .entrySet().stream() + .map(entry -> { + var first = entry.getValue().get(0); + var dto = new IndexPatternQueriesGroupDto(); + dto.setIndexPatternId(entry.getKey()); + dto.setIndexPatternName(first.getIndexPatternName()); + dto.setQueries(entry.getValue()); + return dto; + }) + .toList(); + + // 7. Calcular rango de fechas + var timestamps = evaluations.stream() + .map(UtmComplianceControlEvaluationsDto::getTimestamp) + .toList(); + + Instant min = timestamps.stream().min(Instant::compareTo).get(); + Instant max = timestamps.stream().max(Instant::compareTo).get(); + + LocalDate startDate = min.atZone(ZoneOffset.UTC).toLocalDate(); + LocalDate endDate = max.atZone(ZoneOffset.UTC).toLocalDate(); + + var groupedDto = new UtmComplianceControlEvaluationsGroupedDto(); + groupedDto.setControlId(evaluations.get(0).getControlId()); + groupedDto.setControlName(evaluations.get(0).getControlName()); + groupedDto.setStatus(evaluations.get(0).getStatus()); + groupedDto.setTimestamp(evaluations.get(0).getTimestamp()); + groupedDto.setQueryEvaluations(groupedEvaluations); + + + // 8. Devolver DTO final enriquecido y agrupado + return new ControlEvaluationsResponseDto( + startDate, + endDate, + List.of(groupedDto) + ); + + }*/ + + public ControlEvaluationsResponseDto getEvaluationsWithRange(Long controlId) { + //TODO: Elena Ordenar por fecha descendente + var evaluations = findByControlId(controlId); + + if (evaluations.isEmpty()) { + return new ControlEvaluationsResponseDto(null, null, List.of()); + } + + var queryConfigIds = evaluations.stream() + .flatMap(ev -> ev.getQueryEvaluations().stream()) + .map(UtmComplianceQueryEvaluationDto::getQueryConfigId) + .collect(Collectors.toSet()); + + var configMap = queryConfigRepository.findAllById(queryConfigIds).stream() + .collect(Collectors.toMap(UtmComplianceQueryConfig::getId, Function.identity())); + + //evaluations = enrichQueries(evaluations, configMap); + + List groupedList = + enrichQueries(evaluations, configMap).stream() + .map(evaluation -> { + var grouped = groupByIndexPattern(evaluation); + return buildGroupedDto(evaluation, grouped); + }) + .toList(); + + var timestamps = evaluations.stream() + .map(UtmComplianceControlEvaluationsDto::getTimestamp) + .toList(); + + return new ControlEvaluationsResponseDto( + timestamps.stream().min(Instant::compareTo) + .get().atZone(ZoneOffset.UTC).toLocalDate(), + timestamps.stream().max(Instant::compareTo) + .get().atZone(ZoneOffset.UTC).toLocalDate(), + groupedList); + } + + + private List enrichQueries( + List evaluations, + Map configMap + ) { + evaluations.forEach(controlEval -> + controlEval.getQueryEvaluations().forEach(queryEval -> { + var cfg = configMap.get(queryEval.getQueryConfigId()); + if (cfg != null) { + queryEval.setQueryDescription(cfg.getQueryDescription()); + queryEval.setEvaluationRule(cfg.getEvaluationRule().name()); + queryEval.setIndexPatternId(cfg.getIndexPattern().getId()); + queryEval.setIndexPatternName(cfg.getIndexPattern().getPattern()); + } + }) + ); + return evaluations; + } + + private List groupByIndexPattern( + UtmComplianceControlEvaluationsDto evaluation + ) { + return evaluation.getQueryEvaluations().stream() + .collect(Collectors.groupingBy(UtmComplianceQueryEvaluationDto::getIndexPatternId)) + .entrySet().stream() + .map(entry -> { + var first = entry.getValue().get(0); + var dto = new IndexPatternQueriesGroupDto(); + dto.setIndexPatternId(entry.getKey()); + dto.setIndexPatternName(first.getIndexPatternName()); + dto.setQueries(entry.getValue()); + return dto; + }) + .toList(); + } + + private UtmComplianceControlEvaluationsGroupedDto buildGroupedDto( + UtmComplianceControlEvaluationsDto evaluation, + List groupedEvaluations + ) { + var dto = new UtmComplianceControlEvaluationsGroupedDto(); + dto.setControlId(evaluation.getControlId()); + dto.setControlName(evaluation.getControlName()); + dto.setStatus(evaluation.getStatus()); + dto.setTimestamp(evaluation.getTimestamp()); + dto.setQueryEvaluations(groupedEvaluations); + + return dto; } } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/ControlEvaluationsResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/ControlEvaluationsResponseDto.java new file mode 100644 index 000000000..b8ebdf469 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/ControlEvaluationsResponseDto.java @@ -0,0 +1,17 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ControlEvaluationsResponseDto { + LocalDate startDate; + LocalDate endDate; + List evaluations; +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/IndexPatternQueriesGroupDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/IndexPatternQueriesGroupDto.java new file mode 100644 index 000000000..18e857a4c --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/IndexPatternQueriesGroupDto.java @@ -0,0 +1,12 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Data; + +import java.util.List; + +@Data +public class IndexPatternQueriesGroupDto { + private Long indexPatternId; + private String indexPatternName; + private List queries; +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsGroupedDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsGroupedDto.java new file mode 100644 index 000000000..e1d48a093 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsGroupedDto.java @@ -0,0 +1,19 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.Instant; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UtmComplianceControlEvaluationsGroupedDto { + private Long controlId; + private String controlName; + private String status; + private Instant timestamp; + private List queryEvaluations; +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java index 8c1649098..6e61985a2 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java @@ -12,6 +12,10 @@ public class UtmComplianceQueryEvaluationDto { private Long queryConfigId; private String queryName; + private String queryDescription; + private String evaluationRule; + private Long indexPatternId; + private String indexPatternName; private Integer hits; private String status; private String errorMessage; diff --git a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java index 5035cb151..bf48c7783 100644 --- a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java +++ b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java @@ -419,19 +419,27 @@ public List getControlEvaluations(Long contr SearchRequest request = new SearchRequest.Builder() .index("v11-log-compliance-evaluation") .query(query) - .size(1000) + .size(30) + .sort(s -> s.field(f -> f + .field("timestamp") + .order(SortOrder.Desc) + )) .build(); SearchResponse response = search(request, Map.class); - return response.hits().hits().stream().map(hit -> UtmComplianceControlEvaluationsMapper.mapToEvaluationDto(hit.source())).toList(); + var evaluations = response.hits().hits().stream() + .map(hit -> UtmComplianceControlEvaluationsMapper.mapToEvaluationDto(hit.source())) + .toList(); + + return evaluations; } catch (Exception e) { throw new RuntimeException(ctx + ": " + e.getMessage(), e); } } - public UtmComplianceControlEvaluationsDto getLastEvaluation(Long controlId) { + public UtmComplianceControlEvaluationsDto getLatestControlEvaluation(Long controlId) { try { SearchRequest request = new SearchRequest.Builder() .index("v11-log-compliance-evaluation") diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java index 6145079fe..77b1db430 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java @@ -36,10 +36,11 @@ public static UtmComplianceControlEvaluationDto toDto( } public static UtmComplianceControlEvaluationsDto mapToEvaluationDto(Map source) { - if (source == null) return null; + if (source == null) { + return null; + } UtmComplianceControlEvaluationsDto dto = new UtmComplianceControlEvaluationsDto(); - dto.setControlId(getLong(source.get("control_id"))); dto.setControlName(getString(source.get("control_name"))); dto.setStatus(getString(source.get("status"))); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java index ab6ef3ffe..53820811f 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java @@ -1,12 +1,10 @@ package com.park.utmstack.web.rest.compliance.config; import com.park.utmstack.service.compliance.config.UtmComplianceControlEvaluationsService; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; +import com.park.utmstack.service.dto.compliance.ControlEvaluationsResponseDto; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; - @RestController @RequestMapping("/api/compliance/control-config") public class UtmComplianceControlEvaluationsResource { @@ -18,9 +16,9 @@ public UtmComplianceControlEvaluationsResource(UtmComplianceControlEvaluationsSe } @GetMapping("/{id}/evaluations") - public ResponseEntity> getControlEvaluations(@PathVariable Long id) { - var evaluations = evaluationsService.findByControlId(id); - return ResponseEntity.ok(evaluations); + public ResponseEntity getControlEvaluations(@PathVariable Long id) { + return ResponseEntity.ok(evaluationsService.getEvaluationsWithRange(id)); } + } From dc67353b66b46a78d9cff67efaad07af394d8f42 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Thu, 12 Mar 2026 22:39:33 -0500 Subject: [PATCH 031/135] feat: refactor compliance evaluation classes and update related mappings --- .../com/park/utmstack/config/Constants.java | 2 +- .../UtmComplianceQueryConfigRepository.java | 2 - ...mplianceControlConfigCriteriaService.java} | 6 +- ...lianceControlEvaluationHistoryService.java | 115 +++++++++ ...plianceControlEvaluationLatestService.java | 36 +++ ...UtmComplianceControlEvaluationService.java | 35 --- ...tmComplianceControlEvaluationsService.java | 229 ------------------ .../UtmComplianceControlConfigCriteria.java | 2 +- .../UtmComplianceControlEvaluationDto.java | 23 -- ...omplianceControlEvaluationGroupedDto.java} | 4 +- ...omplianceControlEvaluationHistoryDto.java} | 2 +- ...eControlEvaluationHistoryResponseDto.java} | 4 +- ...mComplianceControlLatestEvaluationDto.java | 11 + ...omplianceIndexPatternQueriesGroupDto.java} | 2 +- ....java => UtmComplianceStrategyFilter.java} | 2 +- .../elasticsearch/ElasticsearchService.java | 10 +- ...UtmComplianceControlEvaluationsMapper.java | 6 +- ...plianceControlLatestEvaluationMapper.java} | 23 +- .../UtmComplianceControlConfigResource.java | 10 +- ...ianceControlEvaluationHistoryResource.java | 24 ++ ...tmComplianceControlEvaluationResource.java | 28 --- ...mComplianceControlEvaluationsResource.java | 24 -- ...lianceControlLatestEvaluationResource.java | 28 +++ 23 files changed, 250 insertions(+), 378 deletions(-) rename backend/src/main/java/com/park/utmstack/service/compliance/config/{UtmComplianceControlConfigQueryService.java => UtmComplianceControlConfigCriteriaService.java} (90%) create mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationHistoryService.java create mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java delete mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java delete mode 100644 backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java delete mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java rename backend/src/main/java/com/park/utmstack/service/dto/compliance/{UtmComplianceControlEvaluationsGroupedDto.java => UtmComplianceControlEvaluationGroupedDto.java} (72%) rename backend/src/main/java/com/park/utmstack/service/dto/compliance/{UtmComplianceControlEvaluationsDto.java => UtmComplianceControlEvaluationHistoryDto.java} (88%) rename backend/src/main/java/com/park/utmstack/service/dto/compliance/{ControlEvaluationsResponseDto.java => UtmComplianceControlEvaluationHistoryResponseDto.java} (69%) create mode 100644 backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlLatestEvaluationDto.java rename backend/src/main/java/com/park/utmstack/service/dto/compliance/{IndexPatternQueriesGroupDto.java => UtmComplianceIndexPatternQueriesGroupDto.java} (80%) rename backend/src/main/java/com/park/utmstack/service/dto/compliance/{ComplianceStrategyFilter.java => UtmComplianceStrategyFilter.java} (68%) rename backend/src/main/java/com/park/utmstack/service/mapper/compliance/{UtmComplianceControlEvaluationMapper.java => UtmComplianceControlLatestEvaluationMapper.java} (65%) create mode 100644 backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationHistoryResource.java delete mode 100644 backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java delete mode 100644 backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java create mode 100644 backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java diff --git a/backend/src/main/java/com/park/utmstack/config/Constants.java b/backend/src/main/java/com/park/utmstack/config/Constants.java index f4651ee14..96d7535d0 100644 --- a/backend/src/main/java/com/park/utmstack/config/Constants.java +++ b/backend/src/main/java/com/park/utmstack/config/Constants.java @@ -164,7 +164,7 @@ public final class Constants { public static final List API_ENDPOINT_IGNORE = Collections.emptyList(); // Application version file - public static final String APP_VERSION_FILE = "/Users/elena/Documents/Work/UTM Stack/version.json"; //TODO: ELENA + public static final String APP_VERSION_FILE = "/updates/version.json"; public static final String ADMIN_EMAIL = "admin@localhost"; diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java index 43f11723e..362d4a2a1 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java @@ -4,8 +4,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.List; - @Repository public interface UtmComplianceQueryConfigRepository extends JpaRepository { diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigQueryService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigCriteriaService.java similarity index 90% rename from backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigQueryService.java rename to backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigCriteriaService.java index 7f1b1f1df..3407adac8 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigQueryService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigCriteriaService.java @@ -14,13 +14,13 @@ @Service @Transactional(readOnly = true) -public class UtmComplianceControlConfigQueryService extends QueryService { +public class UtmComplianceControlConfigCriteriaService extends QueryService { private final UtmComplianceControlConfigRepository complianceControlConfigRepository; private final UtmComplianceControlConfigMapper mapper; - public UtmComplianceControlConfigQueryService(UtmComplianceControlConfigRepository complianceControlConfigRepository, - UtmComplianceControlConfigMapper mapper) { + public UtmComplianceControlConfigCriteriaService(UtmComplianceControlConfigRepository complianceControlConfigRepository, + UtmComplianceControlConfigMapper mapper) { this.complianceControlConfigRepository = complianceControlConfigRepository; this.mapper = mapper; } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationHistoryService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationHistoryService.java new file mode 100644 index 000000000..066971433 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationHistoryService.java @@ -0,0 +1,115 @@ +package com.park.utmstack.service.compliance.config; + +import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; +import com.park.utmstack.repository.compliance.UtmComplianceQueryConfigRepository; +import com.park.utmstack.service.dto.compliance.*; +import com.park.utmstack.service.elasticsearch.ElasticsearchService; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.time.ZoneOffset; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Service +public class UtmComplianceControlEvaluationHistoryService { + + private final ElasticsearchService elasticsearchService; + private final UtmComplianceQueryConfigRepository queryConfigRepository; + + public UtmComplianceControlEvaluationHistoryService(ElasticsearchService elasticsearchService, + UtmComplianceQueryConfigRepository QueryConfigRepository) { + this.elasticsearchService = elasticsearchService; + this.queryConfigRepository = QueryConfigRepository; + } + + public List findByControlId(Long controlId) { + return elasticsearchService.getControlEvaluations(controlId); + } + + public UtmComplianceControlEvaluationHistoryResponseDto getEvaluationsWithRange(Long controlId) { + var evaluations = findByControlId(controlId); + + if (evaluations.isEmpty()) { + return new UtmComplianceControlEvaluationHistoryResponseDto(null, null, List.of()); + } + + var queryConfigIds = evaluations.stream() + .flatMap(ev -> ev.getQueryEvaluations().stream()) + .map(UtmComplianceQueryEvaluationDto::getQueryConfigId) + .collect(Collectors.toSet()); + + var configMap = queryConfigRepository.findAllById(queryConfigIds).stream() + .collect(Collectors.toMap(UtmComplianceQueryConfig::getId, Function.identity())); + + List groupedList = + enrichQueries(evaluations, configMap).stream() + .map(evaluation -> { + var grouped = groupByIndexPattern(evaluation); + return buildGroupedDto(evaluation, grouped); + }) + .toList(); + + var timestamps = evaluations.stream() + .map(UtmComplianceControlEvaluationHistoryDto::getTimestamp) + .toList(); + + return new UtmComplianceControlEvaluationHistoryResponseDto( + timestamps.stream().min(Instant::compareTo) + .get().atZone(ZoneOffset.UTC).toLocalDate(), + timestamps.stream().max(Instant::compareTo) + .get().atZone(ZoneOffset.UTC).toLocalDate(), + groupedList); + } + + + private List enrichQueries( + List evaluations, + Map configMap + ) { + evaluations.forEach(controlEval -> + controlEval.getQueryEvaluations().forEach(queryEval -> { + var cfg = configMap.get(queryEval.getQueryConfigId()); + if (cfg != null) { + queryEval.setQueryDescription(cfg.getQueryDescription()); + queryEval.setEvaluationRule(cfg.getEvaluationRule().name()); + queryEval.setIndexPatternId(cfg.getIndexPattern().getId()); + queryEval.setIndexPatternName(cfg.getIndexPattern().getPattern()); + } + }) + ); + return evaluations; + } + + private List groupByIndexPattern( + UtmComplianceControlEvaluationHistoryDto evaluation + ) { + return evaluation.getQueryEvaluations().stream() + .collect(Collectors.groupingBy(UtmComplianceQueryEvaluationDto::getIndexPatternId)) + .entrySet().stream() + .map(entry -> { + var first = entry.getValue().get(0); + var dto = new UtmComplianceIndexPatternQueriesGroupDto(); + dto.setIndexPatternId(entry.getKey()); + dto.setIndexPatternName(first.getIndexPatternName()); + dto.setQueries(entry.getValue()); + return dto; + }) + .toList(); + } + + private UtmComplianceControlEvaluationGroupedDto buildGroupedDto( + UtmComplianceControlEvaluationHistoryDto evaluation, + List groupedEvaluations + ) { + var dto = new UtmComplianceControlEvaluationGroupedDto(); + dto.setControlId(evaluation.getControlId()); + dto.setControlName(evaluation.getControlName()); + dto.setStatus(evaluation.getStatus()); + dto.setTimestamp(evaluation.getTimestamp()); + dto.setQueryEvaluations(groupedEvaluations); + + return dto; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java new file mode 100644 index 000000000..1ca4513ff --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java @@ -0,0 +1,36 @@ +package com.park.utmstack.service.compliance.config; + +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlLatestEvaluationDto; +import com.park.utmstack.service.elasticsearch.ElasticsearchService; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlLatestEvaluationMapper; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UtmComplianceControlEvaluationLatestService { + + private final UtmComplianceControlConfigService configService; + private final ElasticsearchService elasticsearchService; + + public UtmComplianceControlEvaluationLatestService(UtmComplianceControlConfigService configService, + ElasticsearchService elasticsearchService) { + this.configService = configService; + this.elasticsearchService = elasticsearchService; + } + + public List getControlsWithLastEvaluation(Long sectionId) { + + List controls = configService.getControlsBySection(sectionId); + + return controls.stream() + .map(control -> { + var lastEval = this.elasticsearchService.getLatestControlEvaluation(control.getId()); + return UtmComplianceControlLatestEvaluationMapper.toDto(control, lastEval); + }) + .toList(); + } +} + + diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java deleted file mode 100644 index 5b6179f63..000000000 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationService.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.park.utmstack.service.compliance.config; - -import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; -import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationMapper; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -public class UtmComplianceControlEvaluationService { - - private final UtmComplianceControlConfigService configService; - private final UtmComplianceControlEvaluationsService evaluationsService; - - public UtmComplianceControlEvaluationService(UtmComplianceControlConfigService configService, - UtmComplianceControlEvaluationsService evaluationsService) { - this.configService = configService; - this.evaluationsService = evaluationsService; - } - - public List getControlsWithLastEvaluation(Long sectionId) { - - List controls = configService.getControlsBySection(sectionId); - - return controls.stream() - .map(control -> { - var lastEval = evaluationsService.getLastEvaluationForControl(control.getId()); - return UtmComplianceControlEvaluationMapper.toDto(control, lastEval); - }) - .toList(); - } - } - - diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java deleted file mode 100644 index d451b4de2..000000000 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationsService.java +++ /dev/null @@ -1,229 +0,0 @@ -package com.park.utmstack.service.compliance.config; - -import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; -import com.park.utmstack.repository.compliance.UtmComplianceQueryConfigRepository; -import com.park.utmstack.service.dto.compliance.*; -import com.park.utmstack.service.elasticsearch.ElasticsearchService; -import org.springframework.stereotype.Service; - -import java.time.Instant; -import java.time.ZoneOffset; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -@Service -public class UtmComplianceControlEvaluationsService { - - private final ElasticsearchService elasticsearchService; - private final UtmComplianceQueryConfigRepository queryConfigRepository; - - public UtmComplianceControlEvaluationsService(ElasticsearchService elasticsearchService, - UtmComplianceQueryConfigRepository QueryConfigRepository) { - this.elasticsearchService = elasticsearchService; - this.queryConfigRepository = QueryConfigRepository; - } - - public List findByControlId(Long controlId) { - return elasticsearchService.getControlEvaluations(controlId); - } - - public UtmComplianceControlEvaluationsDto getLastEvaluationForControl(Long controlId) { - return elasticsearchService.getLatestControlEvaluation(controlId); - } - - /*public ControlEvaluationsResponseDto getEvaluationsWithRange(Long controlId) { - var evaluations = findByControlId(controlId); - - if (evaluations.isEmpty()) { - return new ControlEvaluationsResponseDto(null, null, evaluations); - } - - var timestamps = evaluations.stream() - .map(UtmComplianceControlEvaluationsDto::getTimestamp) - .toList(); - - Instant min = timestamps.stream().min(Instant::compareTo).get(); - Instant max = timestamps.stream().max(Instant::compareTo).get(); - - LocalDate start = min.atZone(ZoneOffset.UTC).toLocalDate(); - LocalDate end = max.atZone(ZoneOffset.UTC).toLocalDate(); - - return new ControlEvaluationsResponseDto(start, end, evaluations); - }*/ - - /*public ControlEvaluationsResponseDto getEvaluationsWithRange(Long controlId) { - - // 1. Evaluaciones crudas desde OpenSearch - UtmComplianceControlEvaluationsDto - var evaluations = findByControlId(controlId); - - if (evaluations.isEmpty()) { - return new ControlEvaluationsResponseDto( - null, - null, - List.of() - ); - } - - // 2. Extraer todos los queryConfigId de todas las evaluaciones - var queryConfigIds = evaluations.stream() - .flatMap(ev -> ev.getQueryEvaluations().stream()) - .map(UtmComplianceQueryEvaluationDto::getQueryConfigId) - .collect(Collectors.toSet()); - - // 3. Lookup masivo en DB - UtmComplianceQueryConfig - var configs = queryConfigRepository.findAllById(queryConfigIds); - var configMap = configs.stream() - .collect(Collectors.toMap( - UtmComplianceQueryConfig::getId, - Function.identity() - )); - - // 4. Enriquecer cada query evaluation - evaluations.forEach(controlEval -> { - controlEval.getQueryEvaluations().forEach(queryEval -> { - var cfg = configMap.get(queryEval.getQueryConfigId()); - if (cfg != null) { - queryEval.setQueryDescription(cfg.getQueryDescription()); - queryEval.setEvaluationRule(cfg.getEvaluationRule().name()); - queryEval.setIndexPatternId(cfg.getIndexPattern().getId()); - queryEval.setIndexPatternName(cfg.getIndexPattern().getPattern()); - } - }); - }); - - // 5. Aplanar todas las queryEvaluations para agrupar por indexPattern - var allQueryEvaluations = evaluations.stream() - .flatMap(ev -> ev.getQueryEvaluations().stream()) - .toList(); - - // 6. Agrupar por indexPattern - var groupedEvaluations = allQueryEvaluations.stream() - .collect(Collectors.groupingBy(UtmComplianceQueryEvaluationDto::getIndexPatternId)) - .entrySet().stream() - .map(entry -> { - var first = entry.getValue().get(0); - var dto = new IndexPatternQueriesGroupDto(); - dto.setIndexPatternId(entry.getKey()); - dto.setIndexPatternName(first.getIndexPatternName()); - dto.setQueries(entry.getValue()); - return dto; - }) - .toList(); - - // 7. Calcular rango de fechas - var timestamps = evaluations.stream() - .map(UtmComplianceControlEvaluationsDto::getTimestamp) - .toList(); - - Instant min = timestamps.stream().min(Instant::compareTo).get(); - Instant max = timestamps.stream().max(Instant::compareTo).get(); - - LocalDate startDate = min.atZone(ZoneOffset.UTC).toLocalDate(); - LocalDate endDate = max.atZone(ZoneOffset.UTC).toLocalDate(); - - var groupedDto = new UtmComplianceControlEvaluationsGroupedDto(); - groupedDto.setControlId(evaluations.get(0).getControlId()); - groupedDto.setControlName(evaluations.get(0).getControlName()); - groupedDto.setStatus(evaluations.get(0).getStatus()); - groupedDto.setTimestamp(evaluations.get(0).getTimestamp()); - groupedDto.setQueryEvaluations(groupedEvaluations); - - - // 8. Devolver DTO final enriquecido y agrupado - return new ControlEvaluationsResponseDto( - startDate, - endDate, - List.of(groupedDto) - ); - - }*/ - - public ControlEvaluationsResponseDto getEvaluationsWithRange(Long controlId) { - //TODO: Elena Ordenar por fecha descendente - var evaluations = findByControlId(controlId); - - if (evaluations.isEmpty()) { - return new ControlEvaluationsResponseDto(null, null, List.of()); - } - - var queryConfigIds = evaluations.stream() - .flatMap(ev -> ev.getQueryEvaluations().stream()) - .map(UtmComplianceQueryEvaluationDto::getQueryConfigId) - .collect(Collectors.toSet()); - - var configMap = queryConfigRepository.findAllById(queryConfigIds).stream() - .collect(Collectors.toMap(UtmComplianceQueryConfig::getId, Function.identity())); - - //evaluations = enrichQueries(evaluations, configMap); - - List groupedList = - enrichQueries(evaluations, configMap).stream() - .map(evaluation -> { - var grouped = groupByIndexPattern(evaluation); - return buildGroupedDto(evaluation, grouped); - }) - .toList(); - - var timestamps = evaluations.stream() - .map(UtmComplianceControlEvaluationsDto::getTimestamp) - .toList(); - - return new ControlEvaluationsResponseDto( - timestamps.stream().min(Instant::compareTo) - .get().atZone(ZoneOffset.UTC).toLocalDate(), - timestamps.stream().max(Instant::compareTo) - .get().atZone(ZoneOffset.UTC).toLocalDate(), - groupedList); - } - - - private List enrichQueries( - List evaluations, - Map configMap - ) { - evaluations.forEach(controlEval -> - controlEval.getQueryEvaluations().forEach(queryEval -> { - var cfg = configMap.get(queryEval.getQueryConfigId()); - if (cfg != null) { - queryEval.setQueryDescription(cfg.getQueryDescription()); - queryEval.setEvaluationRule(cfg.getEvaluationRule().name()); - queryEval.setIndexPatternId(cfg.getIndexPattern().getId()); - queryEval.setIndexPatternName(cfg.getIndexPattern().getPattern()); - } - }) - ); - return evaluations; - } - - private List groupByIndexPattern( - UtmComplianceControlEvaluationsDto evaluation - ) { - return evaluation.getQueryEvaluations().stream() - .collect(Collectors.groupingBy(UtmComplianceQueryEvaluationDto::getIndexPatternId)) - .entrySet().stream() - .map(entry -> { - var first = entry.getValue().get(0); - var dto = new IndexPatternQueriesGroupDto(); - dto.setIndexPatternId(entry.getKey()); - dto.setIndexPatternName(first.getIndexPatternName()); - dto.setQueries(entry.getValue()); - return dto; - }) - .toList(); - } - - private UtmComplianceControlEvaluationsGroupedDto buildGroupedDto( - UtmComplianceControlEvaluationsDto evaluation, - List groupedEvaluations - ) { - var dto = new UtmComplianceControlEvaluationsGroupedDto(); - dto.setControlId(evaluation.getControlId()); - dto.setControlName(evaluation.getControlName()); - dto.setStatus(evaluation.getStatus()); - dto.setTimestamp(evaluation.getTimestamp()); - dto.setQueryEvaluations(groupedEvaluations); - - return dto; - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigCriteria.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigCriteria.java index f0341f854..7bf9931fb 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigCriteria.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigCriteria.java @@ -13,5 +13,5 @@ public class UtmComplianceControlConfigCriteria { private StringFilter controlName; private StringFilter controlSolution; private StringFilter controlRemediation; - private ComplianceStrategyFilter controlStrategy; + private UtmComplianceStrategyFilter controlStrategy; } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java deleted file mode 100644 index 75f06b900..000000000 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationDto.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.park.utmstack.service.dto.compliance; - -import com.park.utmstack.domain.compliance.enums.ComplianceStrategy; -import lombok.Data; - -import java.util.List; - -@Data -public class UtmComplianceControlEvaluationDto { - private Long id; - private Long standardSectionId; - private UtmComplianceStandardSectionDto section; - - private String controlName; - private String controlSolution; - private String controlRemediation; - private ComplianceStrategy controlStrategy; - - private List queriesConfigs; - - private String lastEvaluationStatus; - private String lastEvaluationTimestamp; -} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsGroupedDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationGroupedDto.java similarity index 72% rename from backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsGroupedDto.java rename to backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationGroupedDto.java index e1d48a093..cf19524c7 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsGroupedDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationGroupedDto.java @@ -10,10 +10,10 @@ @Data @AllArgsConstructor @NoArgsConstructor -public class UtmComplianceControlEvaluationsGroupedDto { +public class UtmComplianceControlEvaluationGroupedDto { private Long controlId; private String controlName; private String status; private Instant timestamp; - private List queryEvaluations; + private List queryEvaluations; } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryDto.java similarity index 88% rename from backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsDto.java rename to backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryDto.java index f16587681..2cdbb1c3c 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationsDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryDto.java @@ -8,7 +8,7 @@ @Data @JsonIgnoreProperties(ignoreUnknown = true) -public class UtmComplianceControlEvaluationsDto { +public class UtmComplianceControlEvaluationHistoryDto { private Long controlId; private String controlName; private String status; diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/ControlEvaluationsResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryResponseDto.java similarity index 69% rename from backend/src/main/java/com/park/utmstack/service/dto/compliance/ControlEvaluationsResponseDto.java rename to backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryResponseDto.java index b8ebdf469..fbc433503 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/ControlEvaluationsResponseDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryResponseDto.java @@ -10,8 +10,8 @@ @Data @AllArgsConstructor @NoArgsConstructor -public class ControlEvaluationsResponseDto { +public class UtmComplianceControlEvaluationHistoryResponseDto { LocalDate startDate; LocalDate endDate; - List evaluations; + List evaluations; } \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlLatestEvaluationDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlLatestEvaluationDto.java new file mode 100644 index 000000000..9b9106e57 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlLatestEvaluationDto.java @@ -0,0 +1,11 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class UtmComplianceControlLatestEvaluationDto extends UtmComplianceControlConfigDto { + private String lastEvaluationStatus; + private String lastEvaluationTimestamp; +} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/IndexPatternQueriesGroupDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceIndexPatternQueriesGroupDto.java similarity index 80% rename from backend/src/main/java/com/park/utmstack/service/dto/compliance/IndexPatternQueriesGroupDto.java rename to backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceIndexPatternQueriesGroupDto.java index 18e857a4c..3d0979513 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/IndexPatternQueriesGroupDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceIndexPatternQueriesGroupDto.java @@ -5,7 +5,7 @@ import java.util.List; @Data -public class IndexPatternQueriesGroupDto { +public class UtmComplianceIndexPatternQueriesGroupDto { private Long indexPatternId; private String indexPatternName; private List queries; diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/ComplianceStrategyFilter.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStrategyFilter.java similarity index 68% rename from backend/src/main/java/com/park/utmstack/service/dto/compliance/ComplianceStrategyFilter.java rename to backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStrategyFilter.java index 206afea0a..4948c2e03 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/ComplianceStrategyFilter.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStrategyFilter.java @@ -3,7 +3,7 @@ import com.park.utmstack.domain.compliance.enums.ComplianceStrategy; import tech.jhipster.service.filter.Filter; -public class ComplianceStrategyFilter extends Filter { +public class UtmComplianceStrategyFilter extends Filter { } diff --git a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java index bf48c7783..d900b5eea 100644 --- a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java +++ b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java @@ -10,8 +10,8 @@ import com.park.utmstack.service.MailService; import com.park.utmstack.service.UtmSpaceNotificationControlService; import com.park.utmstack.service.application_events.ApplicationEventService; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; -import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationMapper; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationHistoryDto; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlLatestEvaluationMapper; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationsMapper; import com.park.utmstack.util.chart_builder.IndexPropertyType; import com.park.utmstack.util.exceptions.OpenSearchIndexNotFoundException; @@ -408,7 +408,7 @@ public SearchSqlResponse searchBySql(SqlQueryRequest request, Class re } } - public List getControlEvaluations(Long controlId) { + public List getControlEvaluations(Long controlId) { final String ctx = CLASSNAME + ".getControlEvaluations"; try { Query query = Query.of(q -> q.term(t -> t @@ -439,7 +439,7 @@ public List getControlEvaluations(Long contr } } - public UtmComplianceControlEvaluationsDto getLatestControlEvaluation(Long controlId) { + public UtmComplianceControlEvaluationHistoryDto getLatestControlEvaluation(Long controlId) { try { SearchRequest request = new SearchRequest.Builder() .index("v11-log-compliance-evaluation") @@ -459,7 +459,7 @@ public UtmComplianceControlEvaluationsDto getLatestControlEvaluation(Long contro Map source = response.hits().hits().get(0).source(); - return UtmComplianceControlEvaluationMapper.mapToEvaluationDto(source); + return UtmComplianceControlLatestEvaluationMapper.mapToEvaluationDto(source); } catch (Exception e) { throw new RuntimeException("Error fetching last evaluation for control " + controlId, e); diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java index 50c2058d0..2fa10f526 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java @@ -1,6 +1,6 @@ package com.park.utmstack.service.mapper.compliance; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationHistoryDto; import com.park.utmstack.service.dto.compliance.UtmComplianceQueryEvaluationDto; import java.time.Instant; @@ -13,8 +13,8 @@ private UtmComplianceControlEvaluationsMapper() { } - public static UtmComplianceControlEvaluationsDto mapToEvaluationDto(Map src) { - UtmComplianceControlEvaluationsDto dto = new UtmComplianceControlEvaluationsDto(); + public static UtmComplianceControlEvaluationHistoryDto mapToEvaluationDto(Map src) { + UtmComplianceControlEvaluationHistoryDto dto = new UtmComplianceControlEvaluationHistoryDto(); dto.setControlId(((Number) src.get("control_id")).longValue()); dto.setControlName((String) src.get("control_name")); diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlLatestEvaluationMapper.java similarity index 65% rename from backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java rename to backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlLatestEvaluationMapper.java index 77b1db430..28a648f3e 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlLatestEvaluationMapper.java @@ -1,19 +1,19 @@ package com.park.utmstack.service.mapper.compliance; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationsDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlLatestEvaluationDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationHistoryDto; import java.time.Instant; import java.util.Map; -public class UtmComplianceControlEvaluationMapper { +public class UtmComplianceControlLatestEvaluationMapper { - public static UtmComplianceControlEvaluationDto toDto( + public static UtmComplianceControlLatestEvaluationDto toDto( UtmComplianceControlConfigDto control, - UtmComplianceControlEvaluationsDto controlEvaluations + UtmComplianceControlEvaluationHistoryDto controlEvaluationHistory ) { - UtmComplianceControlEvaluationDto dto = new UtmComplianceControlEvaluationDto(); + UtmComplianceControlLatestEvaluationDto dto = new UtmComplianceControlLatestEvaluationDto(); dto.setId(control.getId()); dto.setStandardSectionId(control.getStandardSectionId()); @@ -24,23 +24,22 @@ public static UtmComplianceControlEvaluationDto toDto( dto.setControlStrategy(control.getControlStrategy()); dto.setQueriesConfigs(control.getQueriesConfigs()); - //TODO: ELENA - this is a temporary solution, we need to decide how to handle multiple evaluations for the same control - if (controlEvaluations != null) { - dto.setLastEvaluationStatus(controlEvaluations.getStatus()); + if (controlEvaluationHistory != null) { + dto.setLastEvaluationStatus(controlEvaluationHistory.getStatus()); dto.setLastEvaluationTimestamp( - controlEvaluations.getTimestamp() != null ? controlEvaluations.getTimestamp().toString() : null + controlEvaluationHistory.getTimestamp() != null ? controlEvaluationHistory.getTimestamp().toString() : null ); } return dto; } - public static UtmComplianceControlEvaluationsDto mapToEvaluationDto(Map source) { + public static UtmComplianceControlEvaluationHistoryDto mapToEvaluationDto(Map source) { if (source == null) { return null; } - UtmComplianceControlEvaluationsDto dto = new UtmComplianceControlEvaluationsDto(); + UtmComplianceControlEvaluationHistoryDto dto = new UtmComplianceControlEvaluationHistoryDto(); dto.setControlId(getLong(source.get("control_id"))); dto.setControlName(getString(source.get("control_name"))); dto.setStatus(getString(source.get("status"))); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java index 94899def9..25e792cda 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -3,7 +3,7 @@ import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.service.application_events.ApplicationEventService; import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigService; -import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigQueryService; +import com.park.utmstack.service.compliance.config.UtmComplianceControlConfigCriteriaService; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigCriteria; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import com.park.utmstack.web.rest.util.HeaderUtil; @@ -26,17 +26,17 @@ public class UtmComplianceControlConfigResource { private static final String CLASS_NAME = "UtmComplianceControlConfigResource"; private final UtmComplianceControlConfigService controlService; - private final UtmComplianceControlConfigQueryService queryService; + private final UtmComplianceControlConfigCriteriaService criteriaService; private final ApplicationEventService applicationEventService; public UtmComplianceControlConfigResource( UtmComplianceControlConfigService controlService, - UtmComplianceControlConfigQueryService queryService, + UtmComplianceControlConfigCriteriaService criteriaService, ApplicationEventService applicationEventService ) { this.controlService = controlService; - this.queryService = queryService; + this.criteriaService = criteriaService; this.applicationEventService = applicationEventService; } @@ -80,7 +80,7 @@ public ResponseEntity> getAllComplianceContr final String ctx = CLASS_NAME + ".getAllComplianceControlConfig"; try { - Page page = queryService.findByCriteria(criteria, pageable); + Page page = criteriaService.findByCriteria(criteria, pageable); HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/compliance/control-config"); return ResponseEntity.ok().headers(headers).body(page.getContent()); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationHistoryResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationHistoryResource.java new file mode 100644 index 000000000..de5402e76 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationHistoryResource.java @@ -0,0 +1,24 @@ +package com.park.utmstack.web.rest.compliance.config; + +import com.park.utmstack.service.compliance.config.UtmComplianceControlEvaluationHistoryService; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationHistoryResponseDto; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/compliance/control-config") +public class UtmComplianceControlEvaluationHistoryResource { + + private final UtmComplianceControlEvaluationHistoryService evaluationHistoryService; + + public UtmComplianceControlEvaluationHistoryResource(UtmComplianceControlEvaluationHistoryService evaluationHistoryService) { + this.evaluationHistoryService = evaluationHistoryService; + } + + @GetMapping("/{id}/evaluations") + public ResponseEntity getControlEvaluationHistory(@PathVariable Long id) { + return ResponseEntity.ok(evaluationHistoryService.getEvaluationsWithRange(id)); + } + +} + diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java deleted file mode 100644 index 5c09f5b26..000000000 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationResource.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.park.utmstack.web.rest.compliance.config; - -import com.park.utmstack.service.compliance.config.UtmComplianceControlEvaluationService; -import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationDto; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping("/api/compliance/control-config") -public class UtmComplianceControlEvaluationResource { - - private final UtmComplianceControlEvaluationService evaluationService; - - public UtmComplianceControlEvaluationResource(UtmComplianceControlEvaluationService evaluationService) { - this.evaluationService = evaluationService; - } - - @GetMapping("/get-by-section") - public ResponseEntity> getControlsBySection( - @RequestParam Long sectionId) { - - var controls = evaluationService.getControlsWithLastEvaluation(sectionId); - return ResponseEntity.ok(controls); - } -} - diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java deleted file mode 100644 index 53820811f..000000000 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlEvaluationsResource.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.park.utmstack.web.rest.compliance.config; - -import com.park.utmstack.service.compliance.config.UtmComplianceControlEvaluationsService; -import com.park.utmstack.service.dto.compliance.ControlEvaluationsResponseDto; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/api/compliance/control-config") -public class UtmComplianceControlEvaluationsResource { - - private final UtmComplianceControlEvaluationsService evaluationsService; - - public UtmComplianceControlEvaluationsResource(UtmComplianceControlEvaluationsService evaluationService) { - this.evaluationsService = evaluationService; - } - - @GetMapping("/{id}/evaluations") - public ResponseEntity getControlEvaluations(@PathVariable Long id) { - return ResponseEntity.ok(evaluationsService.getEvaluationsWithRange(id)); - } - -} - diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java new file mode 100644 index 000000000..0962b5426 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java @@ -0,0 +1,28 @@ +package com.park.utmstack.web.rest.compliance.config; + +import com.park.utmstack.service.compliance.config.UtmComplianceControlEvaluationLatestService; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlLatestEvaluationDto; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/compliance/control-config") +public class UtmComplianceControlLatestEvaluationResource { + + private final UtmComplianceControlEvaluationLatestService latestEvaluationService; + + public UtmComplianceControlLatestEvaluationResource(UtmComplianceControlEvaluationLatestService latestEvaluationService) { + this.latestEvaluationService = latestEvaluationService; + } + + @GetMapping("/get-by-section") + public ResponseEntity> getControlsLatestEvaluationBySection( + @RequestParam Long sectionId) { + + var controls = latestEvaluationService.getControlsWithLastEvaluation(sectionId); + return ResponseEntity.ok(controls); + } +} + From 004eaace2fce13fd03fadeabc4f5b0af0cc6bdb5 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Thu, 12 Mar 2026 22:51:38 -0500 Subject: [PATCH 032/135] feat: implement compliance orchestrator backend client and evaluation logic --- .../compliance-orchestrator/scheduler/scheduler.go | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/plugins/compliance-orchestrator/scheduler/scheduler.go b/plugins/compliance-orchestrator/scheduler/scheduler.go index 3a8be6b64..acecaec93 100644 --- a/plugins/compliance-orchestrator/scheduler/scheduler.go +++ b/plugins/compliance-orchestrator/scheduler/scheduler.go @@ -16,19 +16,6 @@ func StartScheduler(ctx context.Context, backend *client.BackendClient) { ticker := time.NewTicker(24 * time.Hour) - // TODO: ELENA QUITAR - Ejecutar inmediatamente - configs, err := backend.GetControlConfigs(ctx) - if err == nil { - catcher.Info("Scheduler: sending configs", map[string]any{ - "cantidad": len(configs), - "timestamp": time.Now().String(), - }) - - for _, cfg := range configs { - Jobs <- cfg - } - } // HASTA AQUI - for { select { case <-ctx.Done(): From 16ab4b496185b6dd352e56a0a8bdbbe01b2ab73a Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 13 Mar 2026 00:19:03 -0500 Subject: [PATCH 033/135] feat: refactor compliance evaluation classes and update related mappings --- .../config/UtmComplianceControlConfigService.java | 9 +++++++-- .../service/elasticsearch/ElasticsearchService.java | 4 ++-- ... => UtmComplianceControlEvaluationHistoryMapper.java} | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) rename backend/src/main/java/com/park/utmstack/service/mapper/compliance/{UtmComplianceControlEvaluationsMapper.java => UtmComplianceControlEvaluationHistoryMapper.java} (89%) diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index c703896a6..66cc7be00 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -13,6 +13,7 @@ import javax.transaction.Transactional; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.stream.Collectors; @Service @@ -54,7 +55,7 @@ public UtmComplianceControlConfigDto update(Long id, UtmComplianceControlConfigD validateControlConfig(dto); UtmComplianceControlConfig entity = repository.findByIdWithQueries(id) - .orElseThrow(() -> new RuntimeException("Control not found")); + .orElseThrow(() -> new NoSuchElementException("Control not found")); mapper.updateEntity(entity, dto); @@ -80,12 +81,16 @@ public UtmComplianceControlConfigDto update(Long id, UtmComplianceControlConfigD } public void delete(Long id) { + if (!repository.existsById(id)) { + throw new NoSuchElementException("Control not found"); + } repository.deleteById(id); } + public UtmComplianceControlConfigDto findById(Long id) { var entity = repository.findByIdWithQueries(id) - .orElseThrow(() -> new RuntimeException("Control not found")); + .orElseThrow(() -> new NoSuchElementException("Control not found")); return mapper.toDto(entity); } diff --git a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java index d900b5eea..5ffbdbdad 100644 --- a/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java +++ b/backend/src/main/java/com/park/utmstack/service/elasticsearch/ElasticsearchService.java @@ -12,7 +12,7 @@ import com.park.utmstack.service.application_events.ApplicationEventService; import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationHistoryDto; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlLatestEvaluationMapper; -import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationsMapper; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlEvaluationHistoryMapper; import com.park.utmstack.util.chart_builder.IndexPropertyType; import com.park.utmstack.util.exceptions.OpenSearchIndexNotFoundException; import com.park.utmstack.util.exceptions.UtmElasticsearchException; @@ -429,7 +429,7 @@ public List getControlEvaluations(Long SearchResponse response = search(request, Map.class); var evaluations = response.hits().hits().stream() - .map(hit -> UtmComplianceControlEvaluationsMapper.mapToEvaluationDto(hit.source())) + .map(hit -> UtmComplianceControlEvaluationHistoryMapper.mapToEvaluationDto(hit.source())) .toList(); return evaluations; diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationHistoryMapper.java similarity index 89% rename from backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java rename to backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationHistoryMapper.java index 2fa10f526..ada707572 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationsMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationHistoryMapper.java @@ -7,9 +7,9 @@ import java.util.List; import java.util.Map; -public class UtmComplianceControlEvaluationsMapper { +public class UtmComplianceControlEvaluationHistoryMapper { - private UtmComplianceControlEvaluationsMapper() { + private UtmComplianceControlEvaluationHistoryMapper() { } @@ -23,7 +23,7 @@ public static UtmComplianceControlEvaluationHistoryDto mapToEvaluationDto(Map> q = (List>) src.get("query_evaluations"); if (q != null) { - dto.setQueryEvaluations(q.stream().map(UtmComplianceControlEvaluationsMapper::mapQueryEval).toList()); + dto.setQueryEvaluations(q.stream().map(UtmComplianceControlEvaluationHistoryMapper::mapQueryEval).toList()); } return dto; From 1467cffe23b183fb4a53eeab8ee342350bc48223 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 25 Feb 2026 13:51:31 -0600 Subject: [PATCH 034/135] feat: implement timeline visualization for compliance evaluations with initial chart setup and styling --- ...compliance-evaluations-view.component.html | 11 + ...compliance-evaluations-view.component.scss | 20 ++ .../compliance-evaluations-view.component.ts | 242 ++++++++++++++++++ 3 files changed, 273 insertions(+) create mode 100644 frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html create mode 100644 frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss create mode 100644 frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html new file mode 100644 index 000000000..6e784790b --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html @@ -0,0 +1,11 @@ + +
+
+
+
+
+ + diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss new file mode 100644 index 000000000..8a9531ac6 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss @@ -0,0 +1,20 @@ +.signature-card { + min-width: 245px !important; +} + +.print-logo-img { + img { + width: 40px; + height: 40px; + } +} + +::ng-deep { + .popover-solution { + min-width: 400px; + } +} + +.timeline-chart { + width: 100%; height: 250px; +} diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts new file mode 100644 index 000000000..6326abf46 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts @@ -0,0 +1,242 @@ +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {CompactType, GridsterConfig, GridType} from 'angular-gridster2'; +import {UUID} from 'angular2-uuid'; +import {NgxSpinnerService} from 'ngx-spinner'; +import {Subject} from 'rxjs'; +import {filter, takeUntil, tap} from 'rxjs/operators'; +import {rebuildVisualizationFilterTime} from '../../graphic-builder/shared/util/chart-filter/chart-filter.util'; +import {TimeFilterBehavior} from '../../shared/behaviors/time-filter.behavior'; +import {UtmDashboardType} from '../../shared/chart/types/dashboard/utm-dashboard.type'; +import {ExportPdfService} from '../../shared/services/util/export-pdf.service'; +import {ElasticFilterType} from '../../shared/types/filter/elastic-filter.type'; +import {ComplianceParamsEnum} from '../shared/enums/compliance-params.enum'; +import {CpControlConfigService} from '../shared/services/cp-control-config.service'; +import {ComplianceControlEvaluationsType} from '../shared/type/compliance-control-evaluations.type'; + +@Component({ + selector: 'app-compliance-evaluations-view', + templateUrl: './compliance-evaluations-view.component.html', + styleUrls: ['./compliance-evaluations-view.component.scss'] +}) +export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { + @Input() showExport = true; + @Input() template: 'default' | 'compliance' = 'default'; + controlId: number; + evaluations: ComplianceControlEvaluationsType[]; + UUID = UUID.UUID(); + interval: any; + dashboard: UtmDashboardType; + pdfExport = false; + public options: GridsterConfig = { + gridType: GridType.ScrollVertical, + setGridSize: true, + compactType: CompactType.None, + minCols: 30, + minRows: 1, + minItemRows: 1, + fixedRowHeight: 430, + fixedColWidth: 500, + defaultItemCols: 1, + defaultItemRows: 1, + draggable: { + enabled: false, + }, + resizable: { + enabled: false, + }, + swap: false, + disableWindowResize: false, + }; + standardId: number; + sectionId: number; + configSolution: string; + filtersValues: ElasticFilterType[] = []; + destroy$: Subject = new Subject(); + showBack = false; + + option = { + tooltip: { + trigger: 'item', + formatter: params => { + const e = params.data; + return ` + ${e.dateFormatted}
+ Status: ${e.status} + `; + } + }, + xAxis: { + type: 'time', + name: 'Evaluations over time' + }, + yAxis: { + show: false + }, + dataZoom: [ + { + type: 'slider', + show: true, + xAxisIndex: 0, + filterMode: 'none', + start: 0, + end: 10 + }, + { + type: 'inside', + xAxisIndex: 0, + filterMode: 'none', + start: 0, + end: 10 + } + ], + series: [ + { + type: 'scatter', + symbolSize: 20, // ← importante para que se vea como punto + data: [] // ← se llena después + } + ] + }; + + constructor(private activeRoute: ActivatedRoute, + // private cpReportsService: CpReportsService, + private cpControlConfigService: CpControlConfigService, + private timeFilterBehavior: TimeFilterBehavior, + private spinner: NgxSpinnerService, + private exportPdfService: ExportPdfService) { + } + + ngOnInit() { + this.activeRoute.queryParams + .pipe( + takeUntil(this.destroy$), + filter((params) => Object.keys(params).length > 0), + tap(() => { + this.showBack = true; + })) + .subscribe((params) => { + this.initializeReportParams(params); + }); + + this.cpControlConfigService.onLoadControl$ + .pipe(takeUntil(this.destroy$), + filter(params => !!params), + ).subscribe(params => { + this.loadReport(params); + }); + + this.timeFilterBehavior.$time + .pipe(takeUntil(this.destroy$)) + .subscribe(time => { + if (time) { + rebuildVisualizationFilterTime({timeFrom: time.from, timeTo: time.to}, this.filtersValues).then(filters => { + this.filtersValues = filters; + }); + } + }); + } + + loadReport(params: any) { + this.controlId = params.template && params.template.id ? params.template.id : null; + this.standardId = params[ComplianceParamsEnum.STANDARD_ID]; + this.sectionId = params[ComplianceParamsEnum.SECTION_ID]; + this.evaluations = params.template; + this.getEvaluations(); + } + + initializeReportParams(params: any) { + this.controlId = params[ComplianceParamsEnum.TEMPLATE]; + this.standardId = params[ComplianceParamsEnum.STANDARD_ID]; + this.sectionId = params[ComplianceParamsEnum.SECTION_ID]; + + this.getEvaluations(); + } + + getEvaluations() { + if (this.controlId) { + this.cpControlConfigService.evaluationsByControl(this.controlId) + .subscribe(response => { + this.evaluations = response.body; + console.log('Evaluations: ', this.evaluations); + this.option.series[0].data = this.buildChartData(); + this.option = { ...this.option }; + }); + } + } + + private buildChartData() { + return this.evaluations.map(e => ({ + value: [e.timestamp, 0], + controlId: e.controlId, + status: e.status, + timestamp: e.timestamp, + dateFormatted: new Date(e.timestamp).toLocaleString(), + itemStyle: { + color: e.status === 'COMPLIANT' ? '#4CAF50' : '#F44336' + } + })); + } + + loadVisualizations(dashboardId) { + /*this.dashboardId = dashboardId; + if (this.dashboardId) { + const request = { + page: 0, + size: 10000, + 'idDashboard.equals': this.dashboardId, + sort: 'order,asc' + }; + this.utmRenderVisualization.query(request).subscribe(vis => { + this.visualizationRender = vis.body; + this.loadingVisualizations = false; + }); + }*/ + } + exportToPdf() { + /*filtersToStringParam(this.filtersValues).then(queryParams => { + this.spinner.show('buildPrintPDF'); + const params = queryParams !== '' ? '?' + queryParams : ''; + const url = '/dashboard/export-compliance/' + this.controlId + params; + const fileName = this.control.associatedDashboard.name.replace(/ /g, '_'); + this.exportPdfService.getPdf(url, fileName, 'PDF_TYPE_TOKEN').subscribe(response => { + this.spinner.hide('buildPrintPDF').then(() => + this.exportPdfService.handlePdfResponse(response)); + }, error => { + this.spinner.hide('buildPrintPDF').then(() => + this.utmToastService.showError('Error', 'An error occurred while creating a PDF.')); + }); + });*/ + } + viewSolution(solution: string): void { + this.configSolution = solution; + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + + onChartInit(chart: any) { + /*this.chartInstance = chart; + + // Limpia listeners previos para evitar duplicados al refrescar datos + this.chartInstance.off('click'); + + // Listener principal + this.chartInstance.on('click', (params: any) => { + const point = params.data; + + // Encuentra la evaluación seleccionada + const evaluation = this.evaluations.find( + e => e.timestamp === point.timestamp + ); + + if (evaluation) { + this.selectedEvaluation = evaluation; + // Aquí puedes abrir panel lateral, modal, etc. + } + }); + */ + } +} From 1e4b6d6a3dc90ec9862f6d8a5552dd8ee32c8c90 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 25 Feb 2026 20:05:02 -0600 Subject: [PATCH 035/135] feat: implement timeline visualization for compliance evaluations with initial chart setup and styling --- ...compliance-evaluations-view.component.html | 2 +- .../compliance-evaluations-view.component.ts | 143 ++++++++++++------ 2 files changed, 96 insertions(+), 49 deletions(-) diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html index 6e784790b..bfabdb460 100644 --- a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html +++ b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html @@ -1,7 +1,7 @@
diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts index 6326abf46..52c13a941 100644 --- a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts +++ b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts @@ -55,49 +55,7 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { destroy$: Subject = new Subject(); showBack = false; - option = { - tooltip: { - trigger: 'item', - formatter: params => { - const e = params.data; - return ` - ${e.dateFormatted}
- Status: ${e.status} - `; - } - }, - xAxis: { - type: 'time', - name: 'Evaluations over time' - }, - yAxis: { - show: false - }, - dataZoom: [ - { - type: 'slider', - show: true, - xAxisIndex: 0, - filterMode: 'none', - start: 0, - end: 10 - }, - { - type: 'inside', - xAxisIndex: 0, - filterMode: 'none', - start: 0, - end: 10 - } - ], - series: [ - { - type: 'scatter', - symbolSize: 20, // ← importante para que se vea como punto - data: [] // ← se llena después - } - ] - }; + chartOption: any = {}; constructor(private activeRoute: ActivatedRoute, // private cpReportsService: CpReportsService, @@ -157,10 +115,95 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { if (this.controlId) { this.cpControlConfigService.evaluationsByControl(this.controlId) .subscribe(response => { - this.evaluations = response.body; - console.log('Evaluations: ', this.evaluations); - this.option.series[0].data = this.buildChartData(); - this.option = { ...this.option }; + this.evaluations = response.body.evaluations; + this.chartOption = { + tooltip: { + trigger: 'item', + formatter: params => { + const e = params.data; + return ` + ${e.dateFormatted}
+ Status: ${e.status} + `; + } + }, + xAxis: { + type: 'time', + min: new Date(response.body.startDate).getTime(), + max: new Date(response.body.endDate).getTime(), + axisLabel: { + formatter: value => { + const d = new Date(value); + return d.toLocaleString('en-US', { + month: 'short', + day: '2-digit', + year: 'numeric', + }); + } + }, + axisTick: { + alignWithLabel: true + }, + splitLine: { + show: true + }, + interval: 1000 * 60 * 60 * 24 + }, + yAxis: { show: false }, + dataZoom: [ + { type: 'slider', start: 0, end: 10 }, + { type: 'inside', start: 0, end: 10 } + ], + series: [ + { + type: 'custom', + renderItem: (params, api) => { + const xValue = api.value(0); + const x = api.coord([xValue, 0])[0]; + + const totalWidth = 40; + const margin = 2; + const width = totalWidth - margin * 2; + + const yBottom = api.coord([xValue, 0])[1]; + const yTop = api.coord([xValue, 1])[1]; + const height = yBottom - yTop; + + return { + type: 'group', + children: [ + { + type: 'rect', + shape: { + x: x - totalWidth / 2 + margin, + y: yTop, + width, + height + }, + style: api.style(), + // ⭐ Aquí viene la magia + clipPath: { + type: 'rect', + shape: { + x: x - totalWidth / 2 + margin, + y: yTop, + width, + height, + r: 5 // ⭐ radio de borde redondeado + } + } + } + ] + }; + }, + data: [] + } + ] + + }; + + this.chartOption.series[0].data = this.buildChartData(); + this.chartOption = { ...this.chartOption }; }); } } @@ -171,7 +214,11 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { controlId: e.controlId, status: e.status, timestamp: e.timestamp, - dateFormatted: new Date(e.timestamp).toLocaleString(), + dateFormatted: new Date(e.timestamp).toLocaleString('en-US', { + month: 'short', + day: '2-digit', + year: 'numeric' + }), itemStyle: { color: e.status === 'COMPLIANT' ? '#4CAF50' : '#F44336' } From 75842a8d3684dfda88828eba5789c6ca02d6a93c Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Thu, 5 Mar 2026 17:14:53 -0600 Subject: [PATCH 036/135] feat: implement timeline visualization for compliance evaluations --- .../compliance-timeline.component.html | 75 ++++++++++++ .../compliance-timeline.component.scss | 113 ++++++++++++++++++ .../compliance-timeline.component.ts | 79 ++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html new file mode 100644 index 000000000..1098c8e4c --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html @@ -0,0 +1,75 @@ +
+
+
+ Control Status Timeline +
+
+
+
+
+
    +
  • +
    + + +
    + + +
    + +
  • +
+ +
+ + +
+
+
+ +
+
+
+
+
+ No data found +
+
+
+
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss new file mode 100644 index 000000000..143f27d9b --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss @@ -0,0 +1,113 @@ + +.timeline-scroll-wrapper { + width: 100%; + overflow-x: auto; + overflow-y: hidden; + padding-bottom: 8px; + } + +.timeline { + display: flex; + flex-direction: row; + gap: 25px; + list-style: none; + padding: 10px 0; + align-items: center; + position: relative; + min-width: max-content; +} + +.timeline::before { + position: absolute; + top: 25px; + left: 0; + right: 0; + height: 1px; + z-index: 0; + width: 100%; + border-radius: unset; +} + +.timeline-item { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + width: 100px; + } + + .timeline-label { + font-size: 14px; + border-bottom: 3px solid #4caf50 !important; + height: 150px; + display: flex; + align-items: center; + width: 50px; + justify-content: center; + box-shadow: 2px 0 1px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24); + } + + .timeline-line { + width: 2px; + height: 30px; + margin: 4px 0; + } + + .timeline-icons { + width: 25px; + height: 25px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-size: 20px; + z-index: 2; + border-color: whitesmoke !important; + box-shadow: 0 0 0 4px rgba(104, 159, 56, .25); + } + + .timeline-icons::before { + content: '\ea16'; + font-family: icomoon, sans-serif; + color: white; + font-size: 12px; + } + + .timeline-icons::after { + display: none; + } + + .timeline-line.compliant, + .timeline-icons.compliant, + .timeline-label.compliant, + .timeline-label.compliant:hover { + background: #4CAF50; + } + + .timeline-line.non-compliant, + .timeline-icons.non-compliant, + .timeline-label.non-compliant, + .timeline-label.non-compliant:hover { + background: #DC3545; + } + + .timeline-time { + font-size: 12px; + color: #666; + margin-top: 6px; + margin-bottom: 0 !important; + } + + .vertical-text { + transform: rotate(270deg); + } + + .selected p{ + color: white; + } + + .timeline-label:hover { + background-color: #f0f0f0; + box-shadow: 2px 0 8px 0 rgba(0, 0, 0, 0.12); + } diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts new file mode 100644 index 000000000..8674866a9 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts @@ -0,0 +1,79 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {WinlogbeatService} from '../../../../active-directory/shared/services/winlogbeat.service'; +import {ActiveDirectoryTreeType} from '../../../../active-directory/shared/types/active-directory-tree.type'; +import {ITEMS_PER_PAGE} from '../../../../shared/constants/pagination.constants'; +import {UtmDateFormatEnum} from '../../../../shared/enums/utm-date-format.enum'; +import {TimeFilterType} from '../../../../shared/types/time-filter.type'; +import {ComplianceControlEvaluationsType} from '../../type/compliance-control-evaluations.type'; + + +@Component({ + selector: 'app-compliance-timeline', + templateUrl: './compliance-timeline.component.html', + styleUrls: ['./compliance-timeline.component.scss'] +}) +export class ComplianceTimelineComponent implements OnInit { + @Input() evaluations: ComplianceControlEvaluationsType[]; + @Input() time: TimeFilterType; + @Output() evaluationSelected = new EventEmitter(); + objectId: ActiveDirectoryTreeType; + loadingMore = false; + totalItems: any; + page = 1; + itemsPerPage = ITEMS_PER_PAGE; + filterTime: TimeFilterType; + loading = true; + selected: ComplianceControlEvaluationsType; + formatDateEnum = UtmDateFormatEnum; + noMoreResult = false; + + constructor(private winlogbeatService: WinlogbeatService) { + } + + ngOnInit(): void { + this.selected = null; + this.page = 1; + this.totalItems = this.evaluations.length; + this.loading = false; + } + + getEvents() { + if (this.filterTime && this.objectId.objectSid) { + const req = { + page: this.page, + size: this.itemsPerPage, + sort: '@timestamp,desc', + sid: this.objectId.objectSid, + indexPattern: this.objectId.indexPattern, + from: this.filterTime.timeFrom, + to: this.filterTime.timeTo, + 'eventId.in': this.evaluations ? this.evaluations.toString() : undefined + }; + this.winlogbeatService.query(req).subscribe(response => { + this.loadingMore = false; + this.loading = false; + if (response.body === null || response.body.length === 0) { + this.evaluationSelected.emit(null); + } else { + this.evaluations = response.body; + this.totalItems = Number(response.headers.get('X-Total-Count')); + } + }); + } else { + this.loading = false; + } + } + + onScroll() { + this.loadingMore = true; + this.page += 1; + this.getEvents(); + } + + selectEvaluation(evaluation: ComplianceControlEvaluationsType) { + this.selected = evaluation; + this.evaluationSelected.emit(evaluation); + } +} + + From 331849d273cf620ef4edd7ea057d39555c0f7656 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Mon, 9 Mar 2026 15:50:31 -0500 Subject: [PATCH 037/135] feat: implement timeline visualization for compliance evaluations --- .../compliance-timeline.component.html | 74 +- .../compliance-timeline.component.scss | 122 +- .../compliance-timeline.component.ts | 1857 ++++++++++++++++- 3 files changed, 1821 insertions(+), 232 deletions(-) diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html index 1098c8e4c..42876815c 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html @@ -1,75 +1,11 @@ -
-
+
Control Status Timeline
-
-
-
-
    -
  • -
    - - -
    - - -
    - -
  • -
- -
- - -
-
-
- -
-
-
-
-
- No data found -
-
+
+
+ diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss index 143f27d9b..9ee1e0212 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss @@ -1,113 +1,19 @@ - -.timeline-scroll-wrapper { - width: 100%; - overflow-x: auto; - overflow-y: hidden; - padding-bottom: 8px; - } - -.timeline { - display: flex; - flex-direction: row; - gap: 25px; - list-style: none; - padding: 10px 0; - align-items: center; - position: relative; - min-width: max-content; -} - -.timeline::before { - position: absolute; - top: 25px; - left: 0; - right: 0; - height: 1px; - z-index: 0; +.chart-container { width: 100%; - border-radius: unset; + height: 200px; + overflow-x: auto; + overflow-y: hidden; + display: block; /* ← IMPORTANTE */ + white-space: nowrap; /* ← permite crecimiento horizontal */ } -.timeline-item { - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - width: 100px; - } - - .timeline-label { - font-size: 14px; - border-bottom: 3px solid #4caf50 !important; - height: 150px; - display: flex; - align-items: center; - width: 50px; - justify-content: center; - box-shadow: 2px 0 1px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24); - } - - .timeline-line { - width: 2px; - height: 30px; - margin: 4px 0; - } - - .timeline-icons { - width: 25px; - height: 25px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - color: white; - font-size: 20px; - z-index: 2; - border-color: whitesmoke !important; - box-shadow: 0 0 0 4px rgba(104, 159, 56, .25); - } - - .timeline-icons::before { - content: '\ea16'; - font-family: icomoon, sans-serif; - color: white; - font-size: 12px; - } - .timeline-icons::after { - display: none; - } - - .timeline-line.compliant, - .timeline-icons.compliant, - .timeline-label.compliant, - .timeline-label.compliant:hover { - background: #4CAF50; - } - - .timeline-line.non-compliant, - .timeline-icons.non-compliant, - .timeline-label.non-compliant, - .timeline-label.non-compliant:hover { - background: #DC3545; - } - - .timeline-time { - font-size: 12px; - color: #666; - margin-top: 6px; - margin-bottom: 0 !important; - } - - .vertical-text { - transform: rotate(270deg); - } - - .selected p{ - color: white; - } +.chart { + height: 200px; + width: max-content; /* ← permite que ECharts crezca horizontalmente */ + min-width: 100%; /* ← pero nunca menos que el contenedor */ +} - .timeline-label:hover { - background-color: #f0f0f0; - box-shadow: 2px 0 8px 0 rgba(0, 0, 0, 0.12); - } +.echarts canvas { + width: max-content !important; +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts index 8674866a9..5032a07ab 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts @@ -1,12 +1,7 @@ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; -import {WinlogbeatService} from '../../../../active-directory/shared/services/winlogbeat.service'; -import {ActiveDirectoryTreeType} from '../../../../active-directory/shared/types/active-directory-tree.type'; -import {ITEMS_PER_PAGE} from '../../../../shared/constants/pagination.constants'; -import {UtmDateFormatEnum} from '../../../../shared/enums/utm-date-format.enum'; -import {TimeFilterType} from '../../../../shared/types/time-filter.type'; +import {ComplianceStatusEnum} from '../../enums/compliance-status.enum'; import {ComplianceControlEvaluationsType} from '../../type/compliance-control-evaluations.type'; - @Component({ selector: 'app-compliance-timeline', templateUrl: './compliance-timeline.component.html', @@ -14,66 +9,1818 @@ import {ComplianceControlEvaluationsType} from '../../type/compliance-control-ev }) export class ComplianceTimelineComponent implements OnInit { @Input() evaluations: ComplianceControlEvaluationsType[]; - @Input() time: TimeFilterType; @Output() evaluationSelected = new EventEmitter(); - objectId: ActiveDirectoryTreeType; - loadingMore = false; - totalItems: any; - page = 1; - itemsPerPage = ITEMS_PER_PAGE; - filterTime: TimeFilterType; - loading = true; - selected: ComplianceControlEvaluationsType; - formatDateEnum = UtmDateFormatEnum; - noMoreResult = false; - - constructor(private winlogbeatService: WinlogbeatService) { + private originalData: ComplianceControlEvaluationsType[] = []; + + options: any; + complianceValue = [ + 'COMPLIANT', + 'NON_COMPLIANT', + ]; + bgColors = { + COMPLIANT: '#28A745', + NON_COMPLIANT: '#DC3545', + }; + textColors = { + COMPLIANT: '#ffffff', + NON_COMPLIANT: '#ffffff', + }; + lightBgColors = { + COMPLIANT: '#E8F5E9', + NON_COMPLIANT: '#FAEBED', + }; + cellBorderRadius = 4; + private rawData: any[]; + private monthDays: string[] = []; + + constructor() { } ngOnInit(): void { - this.selected = null; - this.page = 1; - this.totalItems = this.evaluations.length; - this.loading = false; + this.fetchAndRender(); } - getEvents() { - if (this.filterTime && this.objectId.objectSid) { - const req = { - page: this.page, - size: this.itemsPerPage, - sort: '@timestamp,desc', - sid: this.objectId.objectSid, - indexPattern: this.objectId.indexPattern, - from: this.filterTime.timeFrom, - to: this.filterTime.timeTo, - 'eventId.in': this.evaluations ? this.evaluations.toString() : undefined - }; - this.winlogbeatService.query(req).subscribe(response => { - this.loadingMore = false; - this.loading = false; - if (response.body === null || response.body.length === 0) { - this.evaluationSelected.emit(null); - } else { - this.evaluations = response.body; - this.totalItems = Number(response.headers.get('X-Total-Count')); - } - }); - } else { - this.loading = false; + private fetchAndRender(): void { + this.options = null; + + this.evaluations = [ + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'NON_COMPLIANT', + timestamp: '2026-03-06T02:02:12.237900Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 110 + }, + { + col_0: 'Low', + col_1: 1408 + }, + { + col_0: 'High', + col_1: 927 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T02:32:12.149376Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 110 + }, + { + col_0: 'Low', + col_1: 1408 + }, + { + col_0: 'High', + col_1: 927 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T03:02:12.345416Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 110 + }, + { + col_0: 'Low', + col_1: 1408 + }, + { + col_0: 'High', + col_1: 927 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T03:32:12.365162Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 110 + }, + { + col_0: 'Low', + col_1: 1408 + }, + { + col_0: 'High', + col_1: 927 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T04:02:12.408607Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 110 + }, + { + col_0: 'Low', + col_1: 1408 + }, + { + col_0: 'High', + col_1: 927 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T19:32:15.636113Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 111 + }, + { + col_0: 'Low', + col_1: 1460 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T20:02:15.734160Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 111 + }, + { + col_0: 'Low', + col_1: 1460 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T20:32:15.602356Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 111 + }, + { + col_0: 'Low', + col_1: 1460 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T21:02:15.526139Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 111 + }, + { + col_0: 'Low', + col_1: 1462 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T21:32:15.630359Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 111 + }, + { + col_0: 'Low', + col_1: 1463 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T22:02:15.713148Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 111 + }, + { + col_0: 'Low', + col_1: 1463 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T22:32:15.613718Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1465 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T23:02:15.733429Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1467 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-06T23:32:15.629790Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1468 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T00:02:15.789470Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1470 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T00:32:15.772747Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1470 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T01:02:15.642143Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1471 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T01:32:15.709608Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1471 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:02:15.692529Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1474 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + },{ + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + }, + { + controlId: 1, + controlName: 'Control Test Elena 1', + status: 'COMPLIANT', + timestamp: '2026-03-07T02:32:15.564329Z', + queryEvaluations: [ + { + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + queries: [ + { + queryConfigId: 1, + queryName: 'Test Elena 1', + queryDescription: 'Description', + evaluationRule: 'MIN_HITS_REQUIRED', + indexPatternId: 2, + indexPatternName: 'v11-alert-*', + hits: 3, + status: 'COMPLIANT', + errorMessage: null, + evidence: [ + { + col_0: 'Medium', + col_1: 112 + }, + { + col_0: 'Low', + col_1: 1475 + }, + { + col_0: 'High', + col_1: 931 + } + ] + } + ] + } + ] + } + ]; + this.transformResponse(this.evaluations); + if (this.rawData.length > 0) { + this.initChartOptions(); } } - onScroll() { - this.loadingMore = true; - this.page += 1; - this.getEvents(); + private transformResponse(data: ComplianceControlEvaluationsType[]): void { + this.rawData = []; + this.monthDays = []; + this.originalData = this.evaluations; + + data.forEach((entry, index) => { + const date = new Date(entry.timestamp); + const dayLabel = date.toLocaleDateString('en-US', { + month: 'short', + day: '2-digit', + year: 'numeric', + }); + this.monthDays.push(dayLabel); + + this.rawData.push([index, 0, entry.status === ComplianceStatusEnum.COMPLIANT ? 1 : 0]); + this.rawData.push([index, 1, entry.status === ComplianceStatusEnum.NON_COMPLIANT ? 1 : 0]); + }); } - selectEvaluation(evaluation: ComplianceControlEvaluationsType) { - this.selected = evaluation; - this.evaluationSelected.emit(evaluation); + private initChartOptions(): void { + this.options = { + tooltip: { + position: 'top', + formatter: (params: any) => { + const point = Array.isArray(params) ? params[0] : params; + if ( + !point || + typeof point.value !== 'object' || + point.value === null || + !Array.isArray(point.value) + ) { + return ''; + } + + const [dayIdx, sevIdx, count] = point.value as [ + number, + number, + number + ]; + + if ( + dayIdx >= this.monthDays.length || + sevIdx >= this.complianceValue.length + ) { + return 'Invalid data'; + } + + const day = this.monthDays[dayIdx]; + const value = this.complianceValue[sevIdx]; + const markerColor = count === 0 ? this.lightBgColors[value] : this.bgColors[value]; + // tslint:disable-next-line:max-line-length + const marker = ``; + return count !== 0 ? + `${marker} ${day} (${value === ComplianceStatusEnum.COMPLIANT ? + ComplianceStatusEnum.COMPLIANT + : ComplianceStatusEnum.NON_COMPLIANT})` + : ''; + }, + }, + grid: { + height: '50%', + top: '15%', + left: '10%', + right: '3%', + bottom: '5%', + width: this.monthDays.length * 30, + containLabel: false + }, + xAxis: { + type: 'category', + data: this.monthDays, + axisLabel: { rotate: 45, fontSize: 10, interval: 0 }, + axisLine: { show: false }, + axisTick: { alignWithLabel: true }, + }, + yAxis: { + type: 'category', + data: this.complianceValue.map((value) => + value + ), + axisLine: { show: false }, + axisTick: { show: false }, + axisLabel: { fontSize: 10 } + }, + series: [ + { + name: 'Compliance Timeline', + type: 'custom', + renderItem: this.renderItem.bind(this), + data: this.rawData, + emphasis: { + disabled: true + }, + encode: { + x: 0, + y: 1, + tooltip: [0, 1, 2], + }, + silent: false, + }, + ], + }; } -} + private renderItem( + params: any, + api: any): any { + const dayIndex = api.value(0) as number; + const valueIndex = api.value(1) as number; + const count = api.value(2) as number; + const cellCenterCoord = api.coord([dayIndex, valueIndex]); + const cellSize = api.size ? api.size([1, 1]) : 0; + const cellWidth = 25; + const cellHeight = 45; + const x = cellCenterCoord[0] - cellWidth / 2; + const y = cellCenterCoord[1] - cellHeight / 2; + const value = this.complianceValue[valueIndex]; + const baseColor = this.bgColors[value]; + const fillColor = count === 0 ? this.lightBgColors[value] : baseColor; + const textColor = count > 0 ? this.textColors[value] : undefined; + + const rectShape = { + x, + y, + width: cellWidth, + height: cellHeight, + r: this.cellBorderRadius, + }; + const rectStyle = { + fill: fillColor, + lineWidth: 1, + }; + const rectElement = { + type: 'rect', + shape: rectShape, + style: { + ...rectStyle, + cursor: 'pointer', + }, + }; + + const childrenElements: any[] = [rectElement]; + + if (count > 0 && textColor) { + childrenElements.push({ + type: 'text', + style: { + fill: textColor, + x: cellCenterCoord[0], + y: cellCenterCoord[1], + textAlign: 'center', + textVerticalAlign: 'middle', + fontSize: 11, + fontWeight: 'bold', + }, + }); + } + return { + type: 'group', + children: childrenElements, + silent: count === 0, + info: { + value: [dayIndex, valueIndex, count], + }, + }; + } + onChartClick(event: any): void { + const value = event ? event.data : null; + if (Array.isArray(value)) { + const [dayIndex] = value; + this.evaluationSelected.emit(this.originalData[dayIndex]); + } + } +} From b31b8c6b2efcdf5098a4c9c33b8fb654434358ec Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Fri, 13 Mar 2026 17:06:57 -0500 Subject: [PATCH 038/135] feat: implement timeline visualization for compliance evaluations --- ...iance-evaluation-view-detail.component.css | 25 + ...ance-evaluation-view-detail.component.html | 65 + ...liance-evaluation-view-detail.component.ts | 23 + .../compliance-evaluation-view.component.css | 38 + .../compliance-evaluation-view.component.html | 135 ++ .../compliance-evaluation-view.component.ts | 155 ++ ...compliance-evaluations-view.component.html | 81 +- ...compliance-evaluations-view.component.scss | 185 ++ .../compliance-evaluations-view.component.ts | 75 +- ...ance-query-evaluations-view.component.html | 94 + ...ance-query-evaluations-view.component.scss | 38 + ...liance-query-evaluations-view.component.ts | 28 + ...ance-query-evaluation-detail.component.css | 23 + ...nce-query-evaluation-detail.component.html | 48 + ...iance-query-evaluation-detail.component.ts | 21 + .../compliance-report-viewer.component.html | 22 +- .../shared/compliance-shared.module.ts | 48 +- .../utm-compliance-query-list.component.ts | 10 +- .../utm-compliance-query.component.ts | 16 +- ...pliance-control-config-create.component.ts | 4 +- .../compliance-timeline.component.scss | 11 +- .../compliance-timeline.component.ts | 1628 +---------------- .../time-windows.service.ts | 12 + .../utm-cp-section-config.component.css | 46 + .../utm-cp-section-config.component.html | 21 + .../utm-cp-section-config.component.ts | 109 ++ .../enums/compliance-evaluation-rule.enum.ts | 9 +- .../shared/enums/compliance-status.enum.ts | 20 + .../pipes/compliance-status-label.pipe.ts | 11 + .../services/cp-control-config.service.ts | 34 +- .../type/compliance-control-config.type.ts | 4 +- .../compliance-control-evaluation.type.ts | 21 + ...iance-control-evaluations-response.type.ts | 7 + .../compliance-control-evaluations.type.ts | 13 + ...dex-pattern-query-group-evaluation.type.ts | 8 + .../type/compliance-query-config.type.ts | 2 +- .../type/compliance-query-evaluation.type.ts | 12 + 37 files changed, 1417 insertions(+), 1685 deletions(-) create mode 100644 frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.css create mode 100644 frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.html create mode 100644 frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.ts create mode 100644 frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.css create mode 100644 frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.html create mode 100644 frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.ts create mode 100644 frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html create mode 100644 frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss create mode 100644 frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts create mode 100644 frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css create mode 100644 frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html create mode 100644 frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.ts create mode 100644 frontend/src/app/compliance/shared/components/utm-cp-section-config/time-windows.service.ts create mode 100644 frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.css create mode 100644 frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.html create mode 100644 frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.ts create mode 100644 frontend/src/app/compliance/shared/pipes/compliance-status-label.pipe.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-control-evaluation.type.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-control-evaluations-response.type.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-control-evaluations.type.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-index-pattern-query-group-evaluation.type.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-query-evaluation.type.ts diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.css b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.css new file mode 100644 index 000000000..470c44de5 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.css @@ -0,0 +1,25 @@ +* { + font-size: .75rem !important; +} + +.span-small-icon i { + font-size: 10px !important; +} + +.border-left-danger { + border-left: 5px solid #dc3545 !important; +} + +.border-left-success{ + border-left: 5px solid #28a745 !important; +} + +.border-left-neutral { + border-left: 5px solid #e9e9e9 !important; +} + +button { + white-space: nowrap; +} + + diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.html b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.html new file mode 100644 index 000000000..6dc8bdf31 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.html @@ -0,0 +1,65 @@ +
+
+
+
+ Status: + + {{ control.lastEvaluationStatus | complianceStatusLabel }} + +
+ +
+ Last Evaluation: + + + {{ control.lastEvaluationTimestamp | date:dateFormat.dateFormat:dateFormat.timezone }} + + + + {{ control.lastEvaluationStatus | complianceStatusLabel }} + + + +
+
+
+
+
+ Compliance section: +
+
+

{{ control.section.standardSectionName }}

+
+
+ +
+ +
+ Compliance report: +
+ +
+ +
+ + +
+ Compliance remediation: +
+ +
+ +
+
+
+
diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.ts b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.ts new file mode 100644 index 000000000..26c93f4f3 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.ts @@ -0,0 +1,23 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {Observable} from 'rxjs'; +import {TimezoneFormatService} from '../../../shared/services/utm-timezone.service'; +import {DatePipeDefaultOptions} from '../../../shared/types/date-pipe-default-options'; +import {ComplianceStatusExtendedEnum} from '../../shared/enums/compliance-status.enum'; +import {ComplianceControlEvaluationType} from '../../shared/type/compliance-control-evaluation.type'; + + +@Component({ + selector: 'app-compliance-evaluation-view-detail', + templateUrl: './compliance-evaluation-view-detail.component.html', + styleUrls: ['./compliance-evaluation-view-detail.component.css'] +}) +export class ComplianceEvaluationViewDetailComponent implements OnInit { + @Input() control: ComplianceControlEvaluationType; + dateFormat$: Observable; + ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; + constructor(private timezoneFormatService: TimezoneFormatService) { } + + ngOnInit() { + this.dateFormat$ = this.timezoneFormatService.getDateFormatSubject(); + } +} diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.css b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.css new file mode 100644 index 000000000..83edee8e7 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.css @@ -0,0 +1,38 @@ + +img{ + margin-right: 5px; +} + +table { + tr { + border-top: 1px solid #dee2e6; + } + td { + border: none !important; + } +} + +.card-title { + font-weight: bold; +} + +.label-header { + font-size: 12px; +} + +.border-left-danger { + border-left: 5px solid #dc3545 !important; +} + +.border-left-success{ + border-left: 5px solid #28a745 !important; +} + +.border-left-neutral { + border-left: 5px solid #e9e9e9 !important; +} + +.button-pdf { + margin-right: 25px !important; + margin-top: 0; +} diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.html b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.html new file mode 100644 index 000000000..dea3615bb --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.html @@ -0,0 +1,135 @@ +
+
+
+
+
+
+
+ Compliance assessment +
+ + + +
+
+ + +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ Status + + Security Control Name + + Last Evaluation + + Description +
+ {{ control.lastEvaluationStatus | complianceStatusLabel }} + +
+ shield + + {{ control.controlName }} + +
+
+ + {{ control.lastEvaluationTimestamp | date:dateFormat.dateFormat:dateFormat.timezone }} + + +
+ {{ control.controlSolution }} +
+
+ +
+
+
+
+ + +
+
+
+
+
+
+ + +
+
+
+
+
+ shield + +
+ +
+ +
+
diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.ts b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.ts new file mode 100644 index 000000000..e63b77cfc --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.ts @@ -0,0 +1,155 @@ +import {HttpErrorResponse} from '@angular/common/http'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, HostListener, + Input, + OnChanges, + OnDestroy, + OnInit, + Output +} from '@angular/core'; +import {EMPTY, Observable, Subject} from 'rxjs'; +import {catchError, filter, map, switchMap, takeUntil, tap} from 'rxjs/operators'; +import {UtmToastService} from '../../shared/alert/utm-toast.service'; +import {SortEvent} from '../../shared/directives/sortable/type/sort-event'; +import {TimezoneFormatService} from '../../shared/services/utm-timezone.service'; +import {DatePipeDefaultOptions} from '../../shared/types/date-pipe-default-options'; +import {SortByType} from '../../shared/types/sort-by.type'; +import {ComplianceStatusExtendedEnum} from '../shared/enums/compliance-status.enum'; +import {CpControlConfigService} from '../shared/services/cp-control-config.service'; +import {ComplianceControlEvaluationType} from '../shared/type/compliance-control-evaluation.type'; +import {ComplianceStandardSectionType} from '../shared/type/compliance-standard-section.type'; + +@Component({ + selector: 'app-compliance-evaluation-view', + templateUrl: './compliance-evaluation-view.component.html', + styleUrls: ['./compliance-evaluation-view.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ComplianceEvaluationViewComponent implements OnInit, OnChanges, OnDestroy { + @Input() section: ComplianceStandardSectionType; + @Output() pageChange = new EventEmitter<{}>(); + + controls$: Observable; + selected: number; + fields: SortByType[]; + controlDetail: ComplianceControlEvaluationType; + loading = true; + noData = false; + itemsPerPage = 15; + page = 0; + totalItems = 0; + sortEvent: SortEvent = { + column: 'controlName', + direction: 'desc' + }; + destroy$: Subject = new Subject(); + sort = 'controlName,desc'; + search: string; + viewportHeight: number; + dateFormat$: Observable; + + ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; + + constructor(private controlsService: CpControlConfigService, + private toastService: UtmToastService, + private timezoneFormatService: TimezoneFormatService) { + } + + @HostListener('window:resize', ['$event']) + onResize(event: Event) { + this.viewportHeight = window.innerHeight; + } + + ngOnInit() { + this.viewportHeight = window.innerHeight; + this.dateFormat$ = this.timezoneFormatService.getDateFormatSubject(); + this.controls$ = this.controlsService.onRefresh$ + .pipe(takeUntil(this.destroy$), + filter(reportRefresh => + !!reportRefresh && reportRefresh.loading), + tap((reportRefresh) => { + this.loading = true; + this.selected = reportRefresh.reportSelected; + }), + switchMap((reportRefresh) => this.controlsService.fetchData({ + page: reportRefresh.page, // TODO: ELENA - check + size: this.itemsPerPage, // ?? + sectionId: this.section.id, + sort: this.sort, // ?? + search: this.search ? this.search : null, // ?? + })), + tap(res => this.totalItems = Number(res.headers.get('X-Total-Count'))), + map((res) => { + return res.body.map((r, index) => { + return { + ...r, + selected: index === this.selected + }; + }); + }), + catchError((err: HttpErrorResponse) => { + this.toastService.showError('Error', + 'Unable to retrieve the list of reports. Please try again or contact support.'); + this.loading = false; + return EMPTY; + }), + tap((data) => { + this.loading = false; + this.noData = data.length === 0; + })); + } + + ngOnChanges(): void { + this.page = 0; + this.controlsService.notifyRefresh({ + loading: true, + sectionId: this.section.id, + reportSelected: 0 + }); + } + + loadPage(pageEvent: number) { + const page = this.page !== 0 ? this.page - 1 : this.page; + this.controlsService.notifyRefresh({ + loading: true, + sectionId: this.section.id, + reportSelected: 0, + page + }); + this.pageChange.emit({ + page, + size: this.itemsPerPage, + sort: this.sort + }); + } + + onSortBy(sort: SortEvent) { + this.sort = `${sort.column},${sort.direction}`; + this.controlsService.notifyRefresh({ + loading: true, + sectionId: this.section.id, + reportSelected: 0 + }); + } + + onSearch($event: string) { + this.search = $event; + this.controlsService.notifyRefresh({ + loading: true, + sectionId: this.section.id, + reportSelected: 0 + }); + } + + getTableHeight() { + return 100 - ((350 / this.viewportHeight) * 100) + 'vh'; + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + +} diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html index bfabdb460..13923068b 100644 --- a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html +++ b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html @@ -1,4 +1,4 @@ - + +
+
+
+ shield +
+ {{ currentEvaluation.controlName }} +
+
+ + +
+ +
+ + + +
+ +
+
+ + +
+ +

+ {{ currentEvaluation.controlSolution }} +

+
+ +
+
+ + +
+ +

+ {{ currentEvaluation.controlRemediation }} +

+
+ + + {{ currentEvaluation.controlStrategy }} + + + + + +
+ +
+ + +
+ + + + +
+
+
+
+ No data found
+
+
diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss index 8a9531ac6..6ee083dcd 100644 --- a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss +++ b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss @@ -18,3 +18,188 @@ .timeline-chart { width: 100%; height: 250px; } + + +//Nuevo TODO: ELENA +.query-card { + border: 1px solid #ddd; + border-radius: 6px; + padding: 10px 12px; + margin-bottom: 10px; + background: #fff; + box-shadow: 0 1px 4px rgba(0,0,0,0.08); +} + +.query-card__header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.query-card__name { + font-weight: 600; + font-size: 14px; +} + +.query-card__status { + padding: 2px 6px; + border-radius: 4px; + font-size: 11px; + text-transform: uppercase; + font-weight: 600; +} + +.query-card__status.COMPLIANT { + background: #e6f7e6; + color: #2e7d32; +} + +.query-card__status.NON_COMPLIANT { + background: #fdecea; + color: #c62828; +} + +.query-card__evidence-title { + margin: 8px 0 4px; + font-size: 12px; + font-weight: 600; + color: #555; +} + +.query-card__evidence ul { + margin: 0; + padding-left: 16px; + font-size: 12px; + color: #666; +} +.query-card { + border: 1px solid #ddd; + border-radius: 6px; + padding: 10px 12px; + margin-bottom: 10px; + background: #fff; + box-shadow: 0 1px 4px rgba(0,0,0,0.08); +} + +.query-card__header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.query-card__name { + font-weight: 600; + font-size: 14px; +} + +.query-card__status { + padding: 2px 6px; + border-radius: 4px; + font-size: 11px; + text-transform: uppercase; + font-weight: 600; +} + +.query-card__status.COMPLIANT { + background: #e6f7e6; + color: #2e7d32; +} + +.query-card__status.NON_COMPLIANT { + background: #fdecea; + color: #c62828; +} + +.query-card__status.NOT_EVALUATED { + background: #e9e9e9; +} + +.query-card__evidence-title { + margin: 8px 0 4px; + font-size: 12px; + font-weight: 600; + color: #555; +} + +.query-card__evidence ul { + margin: 0; + padding-left: 16px; + font-size: 12px; + color: #666; +} + + +// TODO: ELENA mas nuevos + +.control-summary-card { + border: 1px solid #ddd; + border-radius: 10px; + padding: 14px 18px; + //width: 320px; + background: #fff; + box-shadow: 0 2px 6px rgba(0,0,0,0.08); + display: flex; + flex-direction: column; + gap: 10px; +} + +.control-summary-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.control-id { + font-weight: 600; + color: #444; +} + +.control-status { + padding: 3px 8px; + border-radius: 4px; + font-size: 12px; + font-weight: 600; +} + +.control-status.COMPLIANT { + background: #e6f7e6; + color: #2e7d32; +} + +.control-status.NON_COMPLIANT { + background: #fdecea; + color: #c62828; +} + +.control-status.NOT_EVALUATED { + background: #e9e9e9; +} + +.control-name { + margin: 0; + font-size: 17px; + font-weight: 600; + color: #222; +} + +.control-timestamp { + font-size: 13px; + color: #666; +} + +.control-summary-footer { + margin-top: 6px; + font-size: 13px; + color: #555; + border-top: 1px solid #eee; + padding-top: 6px; +} + +.title-label { + font-weight: 600; +} + +.data-not-found { + color: rgba(0, 75, 139, 0.30) !important; + min-height: 100vh +} diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts index 52c13a941..062336ab3 100644 --- a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts +++ b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts @@ -5,13 +5,14 @@ import {UUID} from 'angular2-uuid'; import {NgxSpinnerService} from 'ngx-spinner'; import {Subject} from 'rxjs'; import {filter, takeUntil, tap} from 'rxjs/operators'; -import {rebuildVisualizationFilterTime} from '../../graphic-builder/shared/util/chart-filter/chart-filter.util'; import {TimeFilterBehavior} from '../../shared/behaviors/time-filter.behavior'; import {UtmDashboardType} from '../../shared/chart/types/dashboard/utm-dashboard.type'; import {ExportPdfService} from '../../shared/services/util/export-pdf.service'; -import {ElasticFilterType} from '../../shared/types/filter/elastic-filter.type'; import {ComplianceParamsEnum} from '../shared/enums/compliance-params.enum'; +import {ComplianceStatusExtendedEnum} from '../shared/enums/compliance-status.enum'; +import {ComplianceStrategyEnum} from '../shared/enums/compliance-strategy.enum'; import {CpControlConfigService} from '../shared/services/cp-control-config.service'; +import {ComplianceControlEvaluationType} from '../shared/type/compliance-control-evaluation.type'; import {ComplianceControlEvaluationsType} from '../shared/type/compliance-control-evaluations.type'; @Component({ @@ -20,10 +21,24 @@ import {ComplianceControlEvaluationsType} from '../shared/type/compliance-contro styleUrls: ['./compliance-evaluations-view.component.scss'] }) export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { + + constructor(private activeRoute: ActivatedRoute, + // private cpReportsService: CpReportsService, + private cpControlConfigService: CpControlConfigService, + private timeFilterBehavior: TimeFilterBehavior, + private spinner: NgxSpinnerService, + private exportPdfService: ExportPdfService) { + } @Input() showExport = true; @Input() template: 'default' | 'compliance' = 'default'; controlId: number; - evaluations: ComplianceControlEvaluationsType[]; + currentEvaluation: ComplianceControlEvaluationType; + evaluationsHistory: ComplianceControlEvaluationsType[]; + loading = false; + showDetails = false; + showRemediation = false; + showSolution = false; + selectedEvaluation: ComplianceControlEvaluationsType; UUID = UUID.UUID(); interval: any; dashboard: UtmDashboardType; @@ -51,22 +66,17 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { standardId: number; sectionId: number; configSolution: string; - filtersValues: ElasticFilterType[] = []; destroy$: Subject = new Subject(); showBack = false; chartOption: any = {}; - constructor(private activeRoute: ActivatedRoute, - // private cpReportsService: CpReportsService, - private cpControlConfigService: CpControlConfigService, - private timeFilterBehavior: TimeFilterBehavior, - private spinner: NgxSpinnerService, - private exportPdfService: ExportPdfService) { - } + ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; + ComplianceStrategyEnum = ComplianceStrategyEnum; ngOnInit() { - this.activeRoute.queryParams + this.loading = true; + /*this.activeRoute.queryParams .pipe( takeUntil(this.destroy$), filter((params) => Object.keys(params).length > 0), @@ -74,17 +84,22 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { this.showBack = true; })) .subscribe((params) => { - this.initializeReportParams(params); - }); + //this.initializeReportParams(params); + });*/ this.cpControlConfigService.onLoadControl$ .pipe(takeUntil(this.destroy$), filter(params => !!params), ).subscribe(params => { - this.loadReport(params); + this.currentEvaluation = params.template; + console.log('Current eval: ', this.currentEvaluation); + if (this.currentEvaluation) { + this.loadReport(params); + } + }); - this.timeFilterBehavior.$time + /*this.timeFilterBehavior.$time .pipe(takeUntil(this.destroy$)) .subscribe(time => { if (time) { @@ -92,14 +107,14 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { this.filtersValues = filters; }); } - }); + });*/ } loadReport(params: any) { + this.showDetails = false; this.controlId = params.template && params.template.id ? params.template.id : null; this.standardId = params[ComplianceParamsEnum.STANDARD_ID]; this.sectionId = params[ComplianceParamsEnum.SECTION_ID]; - this.evaluations = params.template; this.getEvaluations(); } @@ -113,10 +128,11 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { getEvaluations() { if (this.controlId) { + this.loading = true; this.cpControlConfigService.evaluationsByControl(this.controlId) .subscribe(response => { - this.evaluations = response.body.evaluations; - this.chartOption = { + this.evaluationsHistory = response.body.evaluations; + /*this.chartOption = { tooltip: { trigger: 'item', formatter: params => { @@ -200,16 +216,17 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { } ] - }; + };*/ - this.chartOption.series[0].data = this.buildChartData(); - this.chartOption = { ...this.chartOption }; + //this.chartOption.series[0].data = this.buildChartData(); + //this.chartOption = { ...this.chartOption }; + this.loading = false; }); } } - private buildChartData() { - return this.evaluations.map(e => ({ + /*private buildChartData() { + return this.evaluationsHistory.map(e => ({ value: [e.timestamp, 0], controlId: e.controlId, status: e.status, @@ -223,7 +240,7 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { color: e.status === 'COMPLIANT' ? '#4CAF50' : '#F44336' } })); - } + }*/ loadVisualizations(dashboardId) { /*this.dashboardId = dashboardId; @@ -264,6 +281,12 @@ export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { this.destroy$.complete(); } + showEvaluationDetails(evaluation: ComplianceControlEvaluationsType) { + this.showDetails = true; + console.log(this.selectedEvaluation); + this.selectedEvaluation = evaluation; + } + onChartInit(chart: any) { /*this.chartInstance = chart; diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html b/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html new file mode 100644 index 000000000..430c0ae3d --- /dev/null +++ b/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html @@ -0,0 +1,94 @@ +
+
+
+
+ Control Status Details +
+ +
+
+

+ {{ evaluation.timestamp | date: 'yyyy-MM-dd HH:mm:ss' }} +

+
+
+
+
+
+
+ {{ evaluations.indexPatternName }} +
+
+
+ + + + + + + + + + + + + + + + +
+ Status + + Query Name + + Description +
+ {{ query.status | complianceStatusLabel }} + + + {{ query.queryName }} + + + + {{ query.queryDescription }} + +
+
+
+
+ + +
+
+
+
+
+ +
+ +
+ +
+
+
diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss b/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss new file mode 100644 index 000000000..387c3c8a0 --- /dev/null +++ b/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss @@ -0,0 +1,38 @@ +.control-status { + padding: 3px 8px; + border-radius: 4px; + font-size: 12px; + font-weight: 600; +} + +.control-status.COMPLIANT { + background: #e6f7e6; + color: #2e7d32; +} + +.control-status.NON_COMPLIANT { + background: #fdecea; + color: #c62828; +} + +.control-status.NOT_EVALUATED { + background: #e9e9e9; +} + +.control-detail-summary-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.border-left-danger { + border-left: 5px solid #dc3545 !important; +} + +.border-left-success{ + border-left: 5px solid #28a745 !important; +} + +.border-left-neutral { + border-left: 5px solid #e9e9e9 !important; +} diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts b/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts new file mode 100644 index 000000000..8fda98475 --- /dev/null +++ b/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts @@ -0,0 +1,28 @@ +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ComplianceStatusExtendedEnum} from '../shared/enums/compliance-status.enum'; +import {ComplianceControlEvaluationsType} from '../shared/type/compliance-control-evaluations.type'; +import {ComplianceQueryEvaluationType} from '../shared/type/compliance-query-evaluation.type'; + +@Component({ + selector: 'app-compliance-query-evaluations-view', + templateUrl: './compliance-query-evaluations-view.component.html', + styleUrls: ['./compliance-query-evaluations-view.component.scss'] +}) +export class ComplianceQueryEvaluationsViewComponent implements OnInit, OnDestroy { + @Input() evaluation: ComplianceControlEvaluationsType; + queryDetail: ComplianceQueryEvaluationType; + + ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; + + constructor() { + } + + ngOnDestroy(): void { + + } + + ngOnInit(): void { + console.log('queryEval', this.evaluation); + } + +} diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css b/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css new file mode 100644 index 000000000..aad4f46d8 --- /dev/null +++ b/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css @@ -0,0 +1,23 @@ +* { + font-size: .75rem !important; +} + +.span-small-icon i { + font-size: 10px !important; +} + +.border-left-danger { + border-left: 5px solid #dc3545 !important; +} + +.border-left-success{ + border-left: 5px solid #28a745 !important; +} + +.border-left-neutral { + border-left: 5px solid #e9e9e9 !important; +} + +button { + white-space: nowrap; +} diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html b/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html new file mode 100644 index 000000000..b4453df02 --- /dev/null +++ b/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html @@ -0,0 +1,48 @@ +
+
+
+
+ Status: + + {{ query.status | complianceStatusLabel }} + +
+ +
+ Evaluation rule: + + {{ ComplianceEvaluationRuleLabels[query.evaluationRule] }} + +
+
+
+ +
+
+ Query description: +
+
+

{{ query.queryDescription }}

+
+
+ +
+ + Evidence: + +
+ + The query returned no results. +
+ +
+
diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.ts b/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.ts new file mode 100644 index 000000000..6a226940c --- /dev/null +++ b/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.ts @@ -0,0 +1,21 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {ComplianceEvaluationRuleLabels} from '../../../shared/enums/compliance-evaluation-rule.enum'; +import {ComplianceStatusExtendedEnum} from '../../../shared/enums/compliance-status.enum'; +import {ComplianceQueryEvaluationType} from '../../../shared/type/compliance-query-evaluation.type'; + +@Component({ + selector: 'app-compliance-query-evaluation-detail', + templateUrl: './compliance-query-evaluation-detail.component.html', + styleUrls: ['./compliance-query-evaluation-detail.component.css'] +}) +export class ComplianceQueryEvaluationDetailComponent implements OnInit { + @Input() query: ComplianceQueryEvaluationType; + ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; + ComplianceEvaluationRuleLabels = ComplianceEvaluationRuleLabels; + + constructor() { } + + ngOnInit() { + + } +} diff --git a/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.html b/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.html index cdc74e88f..95a05887c 100644 --- a/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.html +++ b/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.html @@ -48,13 +48,22 @@
- + + + +
@@ -62,10 +71,13 @@
-
+
- - + + + +
diff --git a/frontend/src/app/compliance/shared/compliance-shared.module.ts b/frontend/src/app/compliance/shared/compliance-shared.module.ts index 46ff57cc2..bc6c1c291 100644 --- a/frontend/src/app/compliance/shared/compliance-shared.module.ts +++ b/frontend/src/app/compliance/shared/compliance-shared.module.ts @@ -3,9 +3,25 @@ import {CUSTOM_ELEMENTS_SCHEMA, NgModule, NO_ERRORS_SCHEMA} from '@angular/core' import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {NgbModule} from '@ng-bootstrap/ng-bootstrap'; import {NgSelectModule} from '@ng-select/ng-select'; +import {NgxEchartsModule} from 'ngx-echarts'; import {NgxJsonViewerModule} from 'ngx-json-viewer'; import {UtmDashboardSharedModule} from '../../dashboard/shared/utm-dashboard-shared.module'; +import { + AlertManagementSharedModule +} from '../../data-management/alert-management/shared/alert-management-shared.module'; +import {GraphicBuilderSharedModule} from '../../graphic-builder/shared/graphic-builder-shared.module'; import {UtmSharedModule} from '../../shared/utm-shared.module'; +import { + ComplianceEvaluationViewDetailComponent +} from '../compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component'; +import {ComplianceEvaluationViewComponent} from '../compliance-evaluation-view/compliance-evaluation-view.component'; +import {ComplianceEvaluationsViewComponent} from '../compliance-evaluations-view/compliance-evaluations-view.component'; +import { + ComplianceQueryEvaluationsViewComponent +} from '../compliance-query-evaluations-view/compliance-query-evaluations-view.component'; +import { + ComplianceQueryEvaluationDetailComponent +} from '../compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component'; import {ComplianceReportsViewComponent} from '../compliance-reports-view/compliance-reports-view.component'; import { CompliancePrintViewComponent @@ -20,12 +36,12 @@ import { ComplianceTimeWindowsComponent } from '../compliance-reports-view/components/compliance-time-window/compliance-time-windows.component'; import {ReportApplyNoteComponent} from './components/report-apply-note/report-apply-note.component'; -import { - UtmComplianceQueryComponent -} from './components/utm-compliance-control-config-create/query-config/utm-compliance-query.component'; import { UtmComplianceQueryListComponent } from './components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component'; +import { + UtmComplianceQueryComponent +} from './components/utm-compliance-control-config-create/query-config/utm-compliance-query.component'; import { UtmComplianceControlConfigCreateComponent } from './components/utm-compliance-control-config-create/utm-compliance-control-config-create.component'; @@ -37,6 +53,8 @@ import { UtmComplianceScheduleDeleteComponent } from './components/utm-compliance-schedule-delete/utm-compliance-schedule-delete.component'; import {UtmComplianceSelectComponent} from './components/utm-compliance-select/utm-compliance-select.component'; +import {ComplianceTimelineComponent} from './components/utm-compliance-timeline/compliance-timeline.component'; +import {UtmCpSectionConfigComponent} from './components/utm-cp-section-config/utm-cp-section-config.component'; import { UtmCpSectionComponent } from './components/utm-cp-section/utm-cp-section.component'; import {UtmCpStSectionSelectComponent} from './components/utm-cp-st-section-select/utm-cp-st-section-select.component'; import {UtmCpStandardCreateComponent} from './components/utm-cp-standard-create/utm-cp-standard-create.component'; @@ -44,7 +62,8 @@ import {UtmCpStandardSectionCreateComponent} from './components/utm-cp-standard- import {UtmCpStandardSelectComponent} from './components/utm-cp-standard-select/utm-cp-standard-select.component'; import {UtmReportInfoViewComponent} from './components/utm-report-info-view/utm-report-info-view.component'; import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/utm-save-as-compliance.component'; -import {GraphicBuilderSharedModule} from "../../graphic-builder/shared/graphic-builder-shared.module"; +import {ComplianceStatusLabelPipe} from './pipes/compliance-status-label.pipe'; + @NgModule({ declarations: [ UtmSaveAsComplianceComponent, @@ -62,11 +81,19 @@ import {GraphicBuilderSharedModule} from "../../graphic-builder/shared/graphic-b ComplianceStatusComponent, ComplianceReportsViewComponent, ComplianceReportDetailComponent, + ComplianceQueryEvaluationDetailComponent, ComplianceTimeWindowsComponent, CompliancePrintViewComponent, UtmComplianceControlConfigCreateComponent, UtmComplianceQueryComponent, - UtmComplianceQueryListComponent + UtmComplianceQueryListComponent, + ComplianceEvaluationViewComponent, + ComplianceEvaluationsViewComponent, + UtmCpSectionConfigComponent, + ComplianceTimelineComponent, + ComplianceQueryEvaluationsViewComponent, + ComplianceEvaluationViewDetailComponent, + ComplianceStatusLabelPipe ], imports: [ CommonModule, @@ -77,7 +104,9 @@ import {GraphicBuilderSharedModule} from "../../graphic-builder/shared/graphic-b NgbModule, UtmDashboardSharedModule, NgxJsonViewerModule, - GraphicBuilderSharedModule + GraphicBuilderSharedModule, + NgxEchartsModule, + AlertManagementSharedModule ], schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA], entryComponents: [ @@ -105,8 +134,13 @@ import {GraphicBuilderSharedModule} from "../../graphic-builder/shared/graphic-b ComplianceStatusComponent, ComplianceReportsViewComponent, ComplianceReportDetailComponent, + ComplianceQueryEvaluationDetailComponent, ComplianceTimeWindowsComponent, - CompliancePrintViewComponent + CompliancePrintViewComponent, + ComplianceEvaluationViewComponent, + ComplianceEvaluationsViewComponent, + UtmCpSectionConfigComponent, + ComplianceStatusLabelPipe ] }) export class ComplianceSharedModule { diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts index 38df0f523..3e4651fc7 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts @@ -2,7 +2,7 @@ import {HttpResponse} from '@angular/common/http'; import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {IndexPatternService} from '../../../../../shared/services/elasticsearch/index-pattern.service'; import {UtmIndexPattern} from '../../../../../shared/types/index-pattern/utm-index-pattern'; -import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; +import {ComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; @Component({ @@ -12,8 +12,8 @@ import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-confi }) export class UtmComplianceQueryListComponent implements OnInit { // tslint:disable-next-line:variable-name - private _queries: UtmComplianceQueryConfigType[] = []; - @Input() set queries(value: UtmComplianceQueryConfigType[]) { + private _queries: ComplianceQueryConfigType[] = []; + @Input() set queries(value: ComplianceQueryConfigType[]) { this._queries = value || []; } @@ -22,7 +22,7 @@ export class UtmComplianceQueryListComponent implements OnInit { } @Output() add = new EventEmitter<{ - query: UtmComplianceQueryConfigType; + query: ComplianceQueryConfigType; index: number | null; }>(); @Output() remove = new EventEmitter(); @@ -45,7 +45,7 @@ export class UtmComplianceQueryListComponent implements OnInit { this.editingIndex = null; } - onQueryAdd(query: UtmComplianceQueryConfigType): void { + onQueryAdd(query: ComplianceQueryConfigType): void { this.add.emit({ query, index: this.editingIndex diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts index 6f987dc8a..d517be0aa 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts @@ -5,8 +5,11 @@ import {ALERT_INDEX_PATTERN, LOG_INDEX_PATTERN} from '../../../../../shared/cons import {SqlValidationService} from '../../../../../shared/services/code-editor/sql-validation.service'; import {LocalFieldService} from '../../../../../shared/services/elasticsearch/local-field.service'; import {UtmIndexPattern} from '../../../../../shared/types/index-pattern/utm-index-pattern'; -import {ComplianceEvaluationRuleEnum} from '../../../enums/compliance-evaluation-rule.enum'; -import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; +import { + ComplianceEvaluationRuleEnum, + ComplianceEvaluationRuleLabels +} from '../../../enums/compliance-evaluation-rule.enum'; +import {ComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; @Component({ selector: 'app-utm-compliance-query', @@ -15,14 +18,17 @@ import {UtmComplianceQueryConfigType} from '../../../type/compliance-query-confi }) export class UtmComplianceQueryComponent implements OnInit { - @Input() query: UtmComplianceQueryConfigType = null; + @Input() query: ComplianceQueryConfigType = null; @Input() indexPatterns: UtmIndexPattern[] = []; @Input() indexPatternNames: string[] = []; - @Output() add = new EventEmitter(); + @Output() add = new EventEmitter(); @Output() cancel = new EventEmitter(); form: FormGroup; - evaluationRules = Object.values(ComplianceEvaluationRuleEnum); + evaluationRules = Object.values(ComplianceEvaluationRuleEnum).map(rule => ({ + id: rule, + evaluationRule: ComplianceEvaluationRuleLabels[rule] + })); codeEditorOptions: ConsoleOptions = {lineNumbers: 'off'}; errorMessage = ''; diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts index 45bade259..9e2194fcc 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts @@ -6,7 +6,7 @@ import {CpReportBehavior} from '../../behavior/cp-report.behavior'; import {ComplianceStrategyEnum} from '../../enums/compliance-strategy.enum'; import {CpControlConfigService} from '../../services/cp-control-config.service'; import {ComplianceControlConfigType} from '../../type/compliance-control-config.type'; -import {UtmComplianceQueryConfigType} from '../../type/compliance-query-config.type'; +import {ComplianceQueryConfigType} from '../../type/compliance-query-config.type'; @Component({ selector: 'app-utm-compliance-control-config-create', @@ -123,7 +123,7 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { return this.queriesConfigs.controls.map(c => c.value); } - onQueryAdd(event: { query: UtmComplianceQueryConfigType ; index: number | null }) { + onQueryAdd(event: { query: ComplianceQueryConfigType ; index: number | null }) { const { query, index } = event; if (index === null) { this.queriesConfigs.push(this.fb.control(query)); diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss index 9ee1e0212..de63c8e9c 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss @@ -1,17 +1,16 @@ .chart-container { width: 100%; height: 200px; - overflow-x: auto; + overflow-x: hidden; overflow-y: hidden; - display: block; /* ← IMPORTANTE */ - white-space: nowrap; /* ← permite crecimiento horizontal */ + display: block; + white-space: nowrap; } - .chart { height: 200px; - width: max-content; /* ← permite que ECharts crezca horizontalmente */ - min-width: 100%; /* ← pero nunca menos que el contenedor */ + width: max-content; + min-width: 100%; } .echarts canvas { diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts index 5032a07ab..14bdab69f 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts @@ -1,5 +1,5 @@ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; -import {ComplianceStatusEnum} from '../../enums/compliance-status.enum'; +import {ComplianceStatusExtendedEnum, getComplianceStatusLabel} from '../../enums/compliance-status.enum'; import {ComplianceControlEvaluationsType} from '../../type/compliance-control-evaluations.type'; @Component({ @@ -29,7 +29,7 @@ export class ComplianceTimelineComponent implements OnInit { COMPLIANT: '#E8F5E9', NON_COMPLIANT: '#FAEBED', }; - cellBorderRadius = 4; + private rawData: any[]; private monthDays: string[] = []; @@ -37,1615 +37,13 @@ export class ComplianceTimelineComponent implements OnInit { } ngOnInit(): void { - this.fetchAndRender(); - } - - private fetchAndRender(): void { this.options = null; - this.evaluations = [ - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'NON_COMPLIANT', - timestamp: '2026-03-06T02:02:12.237900Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 110 - }, - { - col_0: 'Low', - col_1: 1408 - }, - { - col_0: 'High', - col_1: 927 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T02:32:12.149376Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 110 - }, - { - col_0: 'Low', - col_1: 1408 - }, - { - col_0: 'High', - col_1: 927 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T03:02:12.345416Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 110 - }, - { - col_0: 'Low', - col_1: 1408 - }, - { - col_0: 'High', - col_1: 927 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T03:32:12.365162Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 110 - }, - { - col_0: 'Low', - col_1: 1408 - }, - { - col_0: 'High', - col_1: 927 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T04:02:12.408607Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 110 - }, - { - col_0: 'Low', - col_1: 1408 - }, - { - col_0: 'High', - col_1: 927 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T19:32:15.636113Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 111 - }, - { - col_0: 'Low', - col_1: 1460 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T20:02:15.734160Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 111 - }, - { - col_0: 'Low', - col_1: 1460 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T20:32:15.602356Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 111 - }, - { - col_0: 'Low', - col_1: 1460 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T21:02:15.526139Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 111 - }, - { - col_0: 'Low', - col_1: 1462 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T21:32:15.630359Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 111 - }, - { - col_0: 'Low', - col_1: 1463 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T22:02:15.713148Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 111 - }, - { - col_0: 'Low', - col_1: 1463 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T22:32:15.613718Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1465 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T23:02:15.733429Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1467 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-06T23:32:15.629790Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1468 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T00:02:15.789470Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1470 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T00:32:15.772747Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1470 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T01:02:15.642143Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1471 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T01:32:15.709608Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1471 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:02:15.692529Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1474 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - },{ - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] - }, - { - controlId: 1, - controlName: 'Control Test Elena 1', - status: 'COMPLIANT', - timestamp: '2026-03-07T02:32:15.564329Z', - queryEvaluations: [ - { - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - queries: [ - { - queryConfigId: 1, - queryName: 'Test Elena 1', - queryDescription: 'Description', - evaluationRule: 'MIN_HITS_REQUIRED', - indexPatternId: 2, - indexPatternName: 'v11-alert-*', - hits: 3, - status: 'COMPLIANT', - errorMessage: null, - evidence: [ - { - col_0: 'Medium', - col_1: 112 - }, - { - col_0: 'Low', - col_1: 1475 - }, - { - col_0: 'High', - col_1: 931 - } - ] - } - ] - } - ] + if (this.evaluations && this.evaluations.length > 0) { + this.transformResponse(this.evaluations); + if (this.rawData.length > 0) { + this.initChartOptions(); } - ]; - this.transformResponse(this.evaluations); - if (this.rawData.length > 0) { - this.initChartOptions(); } } @@ -1663,8 +61,8 @@ export class ComplianceTimelineComponent implements OnInit { }); this.monthDays.push(dayLabel); - this.rawData.push([index, 0, entry.status === ComplianceStatusEnum.COMPLIANT ? 1 : 0]); - this.rawData.push([index, 1, entry.status === ComplianceStatusEnum.NON_COMPLIANT ? 1 : 0]); + this.rawData.push([index, 0, entry.status === ComplianceStatusExtendedEnum.COMPLIANT ? 1 : 0]); + this.rawData.push([index, 1, entry.status === ComplianceStatusExtendedEnum.NON_COMPLIANT ? 1 : 0]); }); } @@ -1702,9 +100,7 @@ export class ComplianceTimelineComponent implements OnInit { // tslint:disable-next-line:max-line-length const marker = ``; return count !== 0 ? - `${marker} ${day} (${value === ComplianceStatusEnum.COMPLIANT ? - ComplianceStatusEnum.COMPLIANT - : ComplianceStatusEnum.NON_COMPLIANT})` + `${marker} ${day} (${getComplianceStatusLabel(value)})` : ''; }, }, @@ -1714,7 +110,7 @@ export class ComplianceTimelineComponent implements OnInit { left: '10%', right: '3%', bottom: '5%', - width: this.monthDays.length * 30, + width: this.evaluations.length * 30, containLabel: false }, xAxis: { @@ -1760,7 +156,6 @@ export class ComplianceTimelineComponent implements OnInit { const valueIndex = api.value(1) as number; const count = api.value(2) as number; const cellCenterCoord = api.coord([dayIndex, valueIndex]); - const cellSize = api.size ? api.size([1, 1]) : 0; const cellWidth = 25; const cellHeight = 45; const x = cellCenterCoord[0] - cellWidth / 2; @@ -1769,13 +164,12 @@ export class ComplianceTimelineComponent implements OnInit { const baseColor = this.bgColors[value]; const fillColor = count === 0 ? this.lightBgColors[value] : baseColor; const textColor = count > 0 ? this.textColors[value] : undefined; - const rectShape = { x, y, width: cellWidth, height: cellHeight, - r: this.cellBorderRadius, + r: 4, }; const rectStyle = { fill: fillColor, diff --git a/frontend/src/app/compliance/shared/components/utm-cp-section-config/time-windows.service.ts b/frontend/src/app/compliance/shared/components/utm-cp-section-config/time-windows.service.ts new file mode 100644 index 000000000..622725fb9 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-cp-section-config/time-windows.service.ts @@ -0,0 +1,12 @@ +import {BehaviorSubject} from 'rxjs'; +import {Injectable} from '@angular/core'; + +@Injectable() +export class TimeWindowsService { + private timeWindowsSubject = new BehaviorSubject<{reportId: number, time: string}>(null); + onTimeWindows$ = this.timeWindowsSubject.asObservable(); + + changeTimeWindows(reportTimeWindows: {reportId: number, time: string}) { + this.timeWindowsSubject.next(reportTimeWindows); + } +} diff --git a/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.css b/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.css new file mode 100644 index 000000000..7bd911763 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.css @@ -0,0 +1,46 @@ +.section-name { + padding: 8px 16px; + background-color: #f7f7f7; + transition: background-color 0.3s; +} + +.section-title { + font-size: 0.95rem; + color: #333; +} + +.dropdown-btn, .section-item { + text-align: left; + padding: 5px 16px; + font-size: 13px; + line-height: 20px; + text-decoration: none; + border-radius: 6px; +} + +.dropdown-btn.active, +.dropdown-btn:hover, +.section-item:hover, +.section-item.active { + font-weight: 500; + font-size: 0.90rem; + background-color: rgb(233 233 233 / 0.7); +} + +.dropdown-btn span{ + flex-grow: 1; +} + +.submenu { + display: grid; + grid-template-rows: 0fr; + transition: 300ms ease-in-out; +} + +.submenu.show { + grid-template-rows: 1fr; +} + +.submenu .sub-menu-content { + overflow: hidden; +} diff --git a/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.html b/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.html new file mode 100644 index 000000000..36e5ce472 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.html @@ -0,0 +1,21 @@ + + diff --git a/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.ts b/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.ts new file mode 100644 index 000000000..0fe6ed3f0 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.ts @@ -0,0 +1,109 @@ +import {HttpErrorResponse} from '@angular/common/http'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges +} from '@angular/core'; +import {EMPTY, Observable} from 'rxjs'; +import {catchError, concatMap, filter, map, tap} from 'rxjs/operators'; +import {UtmToastService} from '../../../../shared/alert/utm-toast.service'; +import {CpControlConfigService} from '../../services/cp-control-config.service'; +import {ComplianceControlConfigType} from '../../type/compliance-control-config.type'; +import {ComplianceReportType} from '../../type/compliance-report.type'; +import {ComplianceStandardSectionType} from '../../type/compliance-standard-section.type'; + +@Component({ + selector: 'app-utm-cp-section-config', + templateUrl: './utm-cp-section-config.component.html', + styleUrls: ['./utm-cp-section-config.component.css', ], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class UtmCpSectionConfigComponent implements OnInit, OnChanges { + + @Input() section: ComplianceStandardSectionType; + @Input() index: number; + @Output() isActive: EventEmitter = new EventEmitter(); + @Input() loadFirst = false; + @Input() expandable = true; + @Input() action: 'reports' | 'compliance' = 'compliance'; + + controls$: Observable; + selected: number; + + constructor(private cpControlConfigService: CpControlConfigService, + private toastService: UtmToastService) { + } + + ngOnInit() { + this.controls$ = this.cpControlConfigService.onRefresh$ + .pipe(filter(reportRefresh => + !!reportRefresh && reportRefresh.loading && reportRefresh.sectionId === this.section.id && this.expandable), + tap((reportRefresh) => { + this.selected = reportRefresh.reportSelected; + }), + concatMap(() => this.cpControlConfigService.fetchData({ + page: 0, + size: 1000, + standardId: this.section.standardId, + sectionId: this.section.id, + })), + map((res) => { + return res.body.map((r, index) => { + return { + ...r, + selected: index === this.selected + }; + }); + }), + tap((controls) => { + if (this.loadFirst) { + this.loadReport(controls[0]); + this.loadFirst = false; + } + }), + catchError((err: HttpErrorResponse) => { + this.toastService.showError('Error', + 'Unable to retrieve the list of reports. Please try again or contact support.'); + return EMPTY; + })); + } + + ngOnChanges(changes: SimpleChanges): void { + if (this.section.isActive) { + this.cpControlConfigService.notifyRefresh({ + sectionId: this.section.id, + loading: true, + reportSelected: 0 + }); + } + } + + loadControls() { + if (!this.section.isActive) { + this.isActive.emit(this.index); + } else { + this.section.isCollapsed = !this.section.isCollapsed; + } + } + + generateReport(control: ComplianceControlConfigType, controls: ComplianceControlConfigType[]) { + if (this.section.isActive && control) { + controls.forEach(r => r.selected = false); + control.selected = true; + this.loadReport(control); + } + } + + loadReport(report: ComplianceControlConfigType) { + this.cpControlConfigService.loadReport({ + template: report, + sectionId: this.section.id, + standardId: this.section.standardId + }); + } +} diff --git a/frontend/src/app/compliance/shared/enums/compliance-evaluation-rule.enum.ts b/frontend/src/app/compliance/shared/enums/compliance-evaluation-rule.enum.ts index 913244657..3174b5ad8 100644 --- a/frontend/src/app/compliance/shared/enums/compliance-evaluation-rule.enum.ts +++ b/frontend/src/app/compliance/shared/enums/compliance-evaluation-rule.enum.ts @@ -1,6 +1,11 @@ export enum ComplianceEvaluationRuleEnum { NO_HITS_ALLOWED = 'NO_HITS_ALLOWED', MIN_HITS_REQUIRED = 'MIN_HITS_REQUIRED', - THRESHOLD_MAX = 'THRESHOLD_MAX', - MATCH_FIELD_VALUE = 'MATCH_FIELD_VALUE' + //THRESHOLD_MAX = 'THRESHOLD_MAX', + //MATCH_FIELD_VALUE = 'MATCH_FIELD_VALUE' } + +export const ComplianceEvaluationRuleLabels = { + [ComplianceEvaluationRuleEnum.NO_HITS_ALLOWED]: 'NO HITS ALLOWED', + [ComplianceEvaluationRuleEnum.MIN_HITS_REQUIRED]: 'MIN HITS REQUIRED' +}; diff --git a/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts b/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts index 6b6c8f419..a986fc460 100644 --- a/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts +++ b/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts @@ -2,3 +2,23 @@ export enum ComplianceStatusEnum { COMPLIANT = 'COMPLIANT', NON_COMPLIANT = 'NON_COMPLIANT' } + +export enum ComplianceStatusExtendedEnum { + COMPLIANT = 'COMPLIANT', + NON_COMPLIANT = 'NON_COMPLIANT', + NOT_EVALUATED = 'NOT_EVALUATED' +} + +export const ComplianceStatusLabels: Record = { + [ComplianceStatusExtendedEnum.COMPLIANT]: 'Compliant', + [ComplianceStatusExtendedEnum.NON_COMPLIANT]: 'Non Compliant', + [ComplianceStatusExtendedEnum.NOT_EVALUATED]: 'Not Evaluated' +}; + +export function getComplianceStatusLabel( + status: string | ComplianceStatusExtendedEnum +): string { + return ComplianceStatusLabels[status] + || ComplianceStatusLabels[ComplianceStatusExtendedEnum.NOT_EVALUATED]; +} + diff --git a/frontend/src/app/compliance/shared/pipes/compliance-status-label.pipe.ts b/frontend/src/app/compliance/shared/pipes/compliance-status-label.pipe.ts new file mode 100644 index 000000000..8d4234185 --- /dev/null +++ b/frontend/src/app/compliance/shared/pipes/compliance-status-label.pipe.ts @@ -0,0 +1,11 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import {getComplianceStatusLabel} from '../enums/compliance-status.enum'; + +@Pipe({ + name: 'complianceStatusLabel' +}) +export class ComplianceStatusLabelPipe implements PipeTransform { + transform(value: any): string { + return getComplianceStatusLabel(value); + } +} diff --git a/frontend/src/app/compliance/shared/services/cp-control-config.service.ts b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts index 2ef16b069..93b136790 100644 --- a/frontend/src/app/compliance/shared/services/cp-control-config.service.ts +++ b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts @@ -1,11 +1,21 @@ import {HttpClient, HttpResponse} from '@angular/common/http'; import {Injectable} from '@angular/core'; -import {Observable} from 'rxjs'; +import {BehaviorSubject, Observable} from 'rxjs'; import {SERVER_API_URL} from '../../../app.constants'; import {RefreshDataService} from '../../../shared/services/util/refresh-data.service'; import {createRequestOption} from '../../../shared/util/request-util'; import {ComplianceControlConfigType} from '../type/compliance-control-config.type'; +import {ComplianceControlEvaluationType} from '../type/compliance-control-evaluation.type'; +import {ComplianceControlEvaluationsType} from '../type/compliance-control-evaluations.type'; import {ComplianceReportType} from '../type/compliance-report.type'; +import {ReportParams} from "./cp-reports.service"; +import {ComplianceControlEvaluationsResponse} from "../type/compliance-control-evaluations-response.type"; + +export interface ControlParams { // TODO: ELENA para que + template: ComplianceControlConfigType; + sectionId: number; + standardId: number; +} @Injectable({ providedIn: 'root' @@ -14,6 +24,8 @@ export class CpControlConfigService extends RefreshDataService<{ sectionId: numb loading: boolean, reportSelected: number, page?: number }, HttpResponse> { private resourceUrl = SERVER_API_URL + 'api/compliance/control-config'; + private loadControlSubject = new BehaviorSubject(null); + readonly onLoadControl$ = this.loadControlSubject.asObservable(); constructor(private http: HttpClient) { super(); @@ -50,16 +62,28 @@ export class CpControlConfigService extends RefreshDataService<{ sectionId: numb ); } - queryByStandard(req?: any): Observable> { + controlsBySection(req?: any): Observable> { const options = createRequestOption(req); - return this.http.get(this.resourceUrl + '/get-by-filters', { + return this.http.get(this.resourceUrl + '/get-by-section', { params: options, observe: 'response' }); } - fetchData(request: any): Observable> { - return this.queryByStandard(request); + fetchData(request: any): Observable> { + return this.controlsBySection(request); + } + + evaluationsByControl(controlId: number, req?: any): Observable> { + const options = createRequestOption(req); // TODO: ELENA valorar si dejo el req + return this.http.get( + `${this.resourceUrl}/${controlId}/evaluations`, + { params: options, observe: 'response' } + ); + } + + loadReport(params: ControlParams) { + this.loadControlSubject.next(params); } } diff --git a/frontend/src/app/compliance/shared/type/compliance-control-config.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-config.type.ts index e15fd57b3..c0652f52e 100644 --- a/frontend/src/app/compliance/shared/type/compliance-control-config.type.ts +++ b/frontend/src/app/compliance/shared/type/compliance-control-config.type.ts @@ -1,6 +1,6 @@ import {UtmFieldType} from '../../../shared/types/table/utm-field.type'; import {ComplianceStrategyEnum} from '../enums/compliance-strategy.enum'; -import {UtmComplianceQueryConfigType} from './compliance-query-config.type'; +import {ComplianceQueryConfigType} from './compliance-query-config.type'; import {ComplianceStandardSectionType} from './compliance-standard-section.type'; @@ -12,7 +12,7 @@ export class ComplianceControlConfigType { controlSolution?: string; controlRemediation?: string; controlStrategy?: ComplianceStrategyEnum; - queriesConfigs?: UtmComplianceQueryConfigType[]; + queriesConfigs?: ComplianceQueryConfigType[]; columns?: UtmFieldType[]; selected?: boolean; diff --git a/frontend/src/app/compliance/shared/type/compliance-control-evaluation.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-evaluation.type.ts new file mode 100644 index 000000000..307e9f671 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-control-evaluation.type.ts @@ -0,0 +1,21 @@ +import {ComplianceStatusExtendedEnum} from '../enums/compliance-status.enum'; +import {ComplianceStrategyEnum} from '../enums/compliance-strategy.enum'; +import {ComplianceQueryConfigType} from './compliance-query-config.type'; +import {ComplianceStandardSectionType} from './compliance-standard-section.type'; + +export class ComplianceControlEvaluationType { + //TODO: ELENA current evaluation + controlId?: number; + standardSectionId?: number; + section?: ComplianceStandardSectionType; + + controlName?: string; + controlSolution?: string; + controlRemediation?: string; + controlStrategy?: ComplianceStrategyEnum; + + queriesConfigs?: ComplianceQueryConfigType[]; + + lastEvaluationStatus?: ComplianceStatusExtendedEnum; + lastEvaluationTimestamp?: string; +} diff --git a/frontend/src/app/compliance/shared/type/compliance-control-evaluations-response.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-evaluations-response.type.ts new file mode 100644 index 000000000..891f3c6d6 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-control-evaluations-response.type.ts @@ -0,0 +1,7 @@ +import {ComplianceControlEvaluationsType} from './compliance-control-evaluations.type'; + +export interface ComplianceControlEvaluationsResponse { + startDate: string; + endDate: string; + evaluations: ComplianceControlEvaluationsType[]; +} diff --git a/frontend/src/app/compliance/shared/type/compliance-control-evaluations.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-evaluations.type.ts new file mode 100644 index 000000000..e55d58480 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-control-evaluations.type.ts @@ -0,0 +1,13 @@ +import {ComplianceStatusExtendedEnum} from '../enums/compliance-status.enum'; +import {ComplianceIndexPatternQueryGroupEvaluationType} from './compliance-index-pattern-query-group-evaluation.type'; +import {ComplianceQueryEvaluationType} from './compliance-query-evaluation.type'; + +export class ComplianceControlEvaluationsType { + // TODO: ELENA registro historico de evaluaciones + controlId?: number; + controlName?: string; + status?: ComplianceStatusExtendedEnum; + timestamp?: string; + queryEvaluations?: ComplianceQueryEvaluationType[] | ComplianceIndexPatternQueryGroupEvaluationType[]; + groupedQueryEvaluations?: ComplianceIndexPatternQueryGroupEvaluationType[]; // TODO: ELENA quitar +} diff --git a/frontend/src/app/compliance/shared/type/compliance-index-pattern-query-group-evaluation.type.ts b/frontend/src/app/compliance/shared/type/compliance-index-pattern-query-group-evaluation.type.ts new file mode 100644 index 000000000..ac98c938c --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-index-pattern-query-group-evaluation.type.ts @@ -0,0 +1,8 @@ +import {ComplianceQueryEvaluationType} from './compliance-query-evaluation.type'; + +export class ComplianceIndexPatternQueryGroupEvaluationType { + indexPatternId?: number; + indexPatternName?: string; + queries?: ComplianceQueryEvaluationType[]; +} + diff --git a/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts b/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts index 21225d632..f915a5a64 100644 --- a/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts +++ b/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts @@ -1,6 +1,6 @@ import {ComplianceEvaluationRuleEnum} from '../enums/compliance-evaluation-rule.enum'; -export class UtmComplianceQueryConfigType { +export class ComplianceQueryConfigType { id?: number; queryName?: string; queryDescription?: string; diff --git a/frontend/src/app/compliance/shared/type/compliance-query-evaluation.type.ts b/frontend/src/app/compliance/shared/type/compliance-query-evaluation.type.ts new file mode 100644 index 000000000..d4799038e --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-query-evaluation.type.ts @@ -0,0 +1,12 @@ +import {ComplianceEvaluationRuleEnum} from '../enums/compliance-evaluation-rule.enum'; +import {ComplianceStatusExtendedEnum} from '../enums/compliance-status.enum'; +// TODO: ELENA ver si puedo usar ComplianceQueryConfigType +export class ComplianceQueryEvaluationType { + queryName?: string; + queryDescription?: string; + evaluationRule?: ComplianceEvaluationRuleEnum; + indexPatternName?: string; + hits?: number; + status?: ComplianceStatusExtendedEnum; + evidence?: any[]; +} From 2a3489f52b52db5f8de6b3bace977271580e8ca2 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Mon, 16 Mar 2026 18:31:37 -0500 Subject: [PATCH 039/135] feat: implement timeline visualization for compliance evaluations --- ...ce-evaluation-history-view.component.html} | 15 +- ...nce-evaluation-history-view.component.scss | 42 +++ ...iance-evaluation-history-view.component.ts | 72 ++++ ...ance-query-evaluation-detail.component.css | 4 - ...nce-query-evaluation-detail.component.html | 1 - ...iance-query-evaluation-detail.component.ts | 0 ...ance-query-evaluations-view.component.html | 0 ...ance-query-evaluations-view.component.scss | 0 ...liance-query-evaluations-view.component.ts | 16 + ...compliance-evaluations-view.component.scss | 205 ------------ .../compliance-evaluations-view.component.ts | 312 ------------------ ...test-evaluation-view-detail.component.css} | 0 ...est-evaluation-view-detail.component.html} | 0 ...atest-evaluation-view-detail.component.ts} | 13 +- ...nce-latest-evaluations-view.component.css} | 5 - ...ce-latest-evaluations-view.component.html} | 5 +- ...ance-latest-evaluations-view.component.ts} | 49 +-- .../cp-standard-management.component.ts | 6 +- .../utm-cp-control-config-delete.component.ts | 4 +- .../utm-cp-control-config.component.ts | 14 +- ...liance-query-evaluations-view.component.ts | 28 -- .../compliance-report-viewer.component.html | 6 +- .../compliance-reports-view.component.ts | 1 - .../shared/compliance-shared.module.ts | 43 +-- .../utm-compliance-query-list.component.scss | 7 - ...utm-compliance-create-query.component.css} | 0 ...tm-compliance-create-query.component.html} | 0 .../utm-compliance-create-query.component.ts} | 14 +- .../utm-compliance-query-list.component.html | 30 +- .../utm-compliance-query-list.component.scss | 3 + .../utm-compliance-query-list.component.ts | 18 +- ...-compliance-control-create.component.html} | 20 +- ...-compliance-control-create.component.scss} | 0 ...tm-compliance-control-create.component.ts} | 25 +- .../compliance-timeline.component.html | 1 - .../compliance-timeline.component.ts | 10 +- .../time-windows.service.ts | 12 - .../utm-cp-section-config.component.ts | 9 +- .../services/cp-control-config.service.ts | 32 +- ...ype.ts => compliance-control-base.type.ts} | 12 +- ...ontrol-evaluation-history-response.type.ts | 7 + ...pliance-control-evaluation-history.type.ts | 11 + .../compliance-control-evaluation.type.ts | 21 -- ...iance-control-evaluations-response.type.ts | 7 - .../compliance-control-evaluations.type.ts | 13 - ...mpliance-control-latest-evaluation.type.ts | 7 + .../shared/type/compliance-control.type.ts | 5 + ....type.ts => compliance-query-base.type.ts} | 6 +- ...s => compliance-query-evaluation.group.ts} | 2 +- .../type/compliance-query-evaluation.type.ts | 9 +- .../shared/type/compliance-query.type.ts | 8 + 51 files changed, 336 insertions(+), 794 deletions(-) rename frontend/src/app/compliance/{compliance-evaluations-view/compliance-evaluations-view.component.html => compliance-evaluation-history-view/compliance-evaluation-history-view.component.html} (91%) create mode 100644 frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.scss create mode 100644 frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.ts rename frontend/src/app/compliance/{compliance-query-evaluations-view/components => compliance-evaluation-history-view/compliance-query-evaluations-view}/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css (89%) rename frontend/src/app/compliance/{compliance-query-evaluations-view/components => compliance-evaluation-history-view/compliance-query-evaluations-view}/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html (99%) rename frontend/src/app/compliance/{compliance-query-evaluations-view/components => compliance-evaluation-history-view/compliance-query-evaluations-view}/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.ts (100%) rename frontend/src/app/compliance/{ => compliance-evaluation-history-view}/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html (100%) rename frontend/src/app/compliance/{ => compliance-evaluation-history-view}/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss (100%) create mode 100644 frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts delete mode 100644 frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss delete mode 100644 frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts rename frontend/src/app/compliance/{compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.css => compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.css} (100%) rename frontend/src/app/compliance/{compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.html => compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.html} (100%) rename frontend/src/app/compliance/{compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.ts => compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.ts} (58%) rename frontend/src/app/compliance/{compliance-evaluation-view/compliance-evaluation-view.component.css => compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css} (86%) rename frontend/src/app/compliance/{compliance-evaluation-view/compliance-evaluation-view.component.html => compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.html} (96%) rename frontend/src/app/compliance/{compliance-evaluation-view/compliance-evaluation-view.component.ts => compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.ts} (74%) delete mode 100644 frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts delete mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss rename frontend/src/app/compliance/shared/components/{utm-compliance-control-config-create/query-config/utm-compliance-query.component.css => utm-compliance-control-create/query-config/utm-compliance-create-query.component.css} (100%) rename frontend/src/app/compliance/shared/components/{utm-compliance-control-config-create/query-config/utm-compliance-query.component.html => utm-compliance-control-create/query-config/utm-compliance-create-query.component.html} (100%) rename frontend/src/app/compliance/shared/components/{utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts => utm-compliance-control-create/query-config/utm-compliance-create-query.component.ts} (89%) rename frontend/src/app/compliance/shared/components/{utm-compliance-control-config-create => utm-compliance-control-create}/query-config/utm-compliance-query-list.component.html (66%) create mode 100644 frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.scss rename frontend/src/app/compliance/shared/components/{utm-compliance-control-config-create => utm-compliance-control-create}/query-config/utm-compliance-query-list.component.ts (86%) rename frontend/src/app/compliance/shared/components/{utm-compliance-control-config-create/utm-compliance-control-config-create.component.html => utm-compliance-control-create/utm-compliance-control-create.component.html} (86%) rename frontend/src/app/compliance/shared/components/{utm-compliance-control-config-create/utm-compliance-control-config-create.component.scss => utm-compliance-control-create/utm-compliance-control-create.component.scss} (100%) rename frontend/src/app/compliance/shared/components/{utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts => utm-compliance-control-create/utm-compliance-control-create.component.ts} (84%) delete mode 100644 frontend/src/app/compliance/shared/components/utm-cp-section-config/time-windows.service.ts rename frontend/src/app/compliance/shared/type/{compliance-control-config.type.ts => compliance-control-base.type.ts} (54%) create mode 100644 frontend/src/app/compliance/shared/type/compliance-control-evaluation-history-response.type.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-control-evaluation-history.type.ts delete mode 100644 frontend/src/app/compliance/shared/type/compliance-control-evaluation.type.ts delete mode 100644 frontend/src/app/compliance/shared/type/compliance-control-evaluations-response.type.ts delete mode 100644 frontend/src/app/compliance/shared/type/compliance-control-evaluations.type.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-control-latest-evaluation.type.ts create mode 100644 frontend/src/app/compliance/shared/type/compliance-control.type.ts rename frontend/src/app/compliance/shared/type/{compliance-query-config.type.ts => compliance-query-base.type.ts} (59%) rename frontend/src/app/compliance/shared/type/{compliance-index-pattern-query-group-evaluation.type.ts => compliance-query-evaluation.group.ts} (75%) create mode 100644 frontend/src/app/compliance/shared/type/compliance-query.type.ts diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.html similarity index 91% rename from frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html rename to frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.html index 13923068b..c02750549 100644 --- a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.html +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.html @@ -1,13 +1,3 @@ - -
@@ -38,7 +28,6 @@
-

{{ currentEvaluation.controlSolution }}

@@ -49,7 +38,6 @@
-

{{ currentEvaluation.controlRemediation }}

@@ -83,6 +71,7 @@
- No data found
+ No data found +
diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.scss b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.scss new file mode 100644 index 000000000..68f73c69e --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.scss @@ -0,0 +1,42 @@ +.control-summary-card { + border: 1px solid #ddd; + border-radius: 10px; + padding: 14px 18px; + background: #fff; + box-shadow: 0 2px 6px rgba(0,0,0,0.08); + display: flex; + flex-direction: column; + gap: 10px; +} + +.control-summary-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.control-status { + padding: 3px 8px; + border-radius: 4px; + font-size: 12px; + font-weight: 600; +} + +.control-status.COMPLIANT { + background: #e6f7e6; + color: #2e7d32; +} + +.control-status.NON_COMPLIANT { + background: #fdecea; + color: #c62828; +} + +.control-status.NOT_EVALUATED { + background: #e9e9e9; +} + +.data-not-found { + color: rgba(0, 75, 139, 0.30) !important; + min-height: 100vh +} diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.ts b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.ts new file mode 100644 index 000000000..0e87ee341 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.ts @@ -0,0 +1,72 @@ +import {Component, OnDestroy, OnInit} from '@angular/core'; +import {Subject} from 'rxjs'; +import {filter, takeUntil} from 'rxjs/operators'; +import {ComplianceStatusExtendedEnum} from '../shared/enums/compliance-status.enum'; +import {ComplianceStrategyEnum} from '../shared/enums/compliance-strategy.enum'; +import {CpControlConfigService} from '../shared/services/cp-control-config.service'; +import {ComplianceControlEvaluationHistoryType} from '../shared/type/compliance-control-evaluation-history.type'; +import {ComplianceControlLatestEvaluationType} from '../shared/type/compliance-control-latest-evaluation.type'; + +@Component({ + selector: 'app-compliance-evaluation-history-view', + templateUrl: './compliance-evaluation-history-view.component.html', + styleUrls: ['./compliance-evaluation-history-view.component.scss'] +}) +export class ComplianceEvaluationHistoryViewComponent implements OnInit, OnDestroy { + controlId: number; + currentEvaluation: ComplianceControlLatestEvaluationType; + evaluationsHistory: ComplianceControlEvaluationHistoryType[]; + loading = false; + showDetails = false; + showRemediation = false; + showSolution = false; + selectedEvaluation: ComplianceControlEvaluationHistoryType; + destroy$: Subject = new Subject(); + + ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; + ComplianceStrategyEnum = ComplianceStrategyEnum; + + constructor(private cpControlConfigService: CpControlConfigService) { + } + + ngOnInit() { + this.loading = true; + this.cpControlConfigService.onLoadControl$ + .pipe(takeUntil(this.destroy$), + filter(params => !!params), + ).subscribe(params => { + this.currentEvaluation = params.template; + if (this.currentEvaluation) { + this.loadReport(params); + } + + }); + } + + loadReport(params: any) { + this.showDetails = false; + this.controlId = params.template && params.template.id ? params.template.id : null; + this.getEvaluations(); + } + + getEvaluations() { + if (this.controlId) { + this.loading = true; + this.cpControlConfigService.evaluationsByControl(this.controlId) + .subscribe(response => { + this.evaluationsHistory = response.body.evaluations; + this.loading = false; + }); + } + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + + showEvaluationDetails(evaluation: ComplianceControlEvaluationHistoryType) { + this.showDetails = true; + this.selectedEvaluation = evaluation; + } +} diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css similarity index 89% rename from frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css rename to frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css index aad4f46d8..619e8b78c 100644 --- a/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css @@ -17,7 +17,3 @@ .border-left-neutral { border-left: 5px solid #e9e9e9 !important; } - -button { - white-space: nowrap; -} diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html similarity index 99% rename from frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html rename to frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html index b4453df02..90f1319f5 100644 --- a/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html @@ -43,6 +43,5 @@ The query returned no results.
-
diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.ts b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.ts similarity index 100% rename from frontend/src/app/compliance/compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.ts rename to frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.ts diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html similarity index 100% rename from frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html rename to frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss similarity index 100% rename from frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss rename to frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts new file mode 100644 index 000000000..b10c47062 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts @@ -0,0 +1,16 @@ +import {Component, Input} from '@angular/core'; +import {ComplianceStatusExtendedEnum} from '../../shared/enums/compliance-status.enum'; +import {ComplianceControlEvaluationHistoryType} from '../../shared/type/compliance-control-evaluation-history.type'; +import {ComplianceQueryEvaluationType} from '../../shared/type/compliance-query-evaluation.type'; + +@Component({ + selector: 'app-compliance-query-evaluations-view', + templateUrl: './compliance-query-evaluations-view.component.html', + styleUrls: ['./compliance-query-evaluations-view.component.scss'] +}) +export class ComplianceQueryEvaluationsViewComponent { + @Input() evaluation: ComplianceControlEvaluationHistoryType; + queryDetail: ComplianceQueryEvaluationType; + + ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; +} diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss deleted file mode 100644 index 6ee083dcd..000000000 --- a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.scss +++ /dev/null @@ -1,205 +0,0 @@ -.signature-card { - min-width: 245px !important; -} - -.print-logo-img { - img { - width: 40px; - height: 40px; - } -} - -::ng-deep { - .popover-solution { - min-width: 400px; - } -} - -.timeline-chart { - width: 100%; height: 250px; -} - - -//Nuevo TODO: ELENA -.query-card { - border: 1px solid #ddd; - border-radius: 6px; - padding: 10px 12px; - margin-bottom: 10px; - background: #fff; - box-shadow: 0 1px 4px rgba(0,0,0,0.08); -} - -.query-card__header { - display: flex; - justify-content: space-between; - align-items: center; -} - -.query-card__name { - font-weight: 600; - font-size: 14px; -} - -.query-card__status { - padding: 2px 6px; - border-radius: 4px; - font-size: 11px; - text-transform: uppercase; - font-weight: 600; -} - -.query-card__status.COMPLIANT { - background: #e6f7e6; - color: #2e7d32; -} - -.query-card__status.NON_COMPLIANT { - background: #fdecea; - color: #c62828; -} - -.query-card__evidence-title { - margin: 8px 0 4px; - font-size: 12px; - font-weight: 600; - color: #555; -} - -.query-card__evidence ul { - margin: 0; - padding-left: 16px; - font-size: 12px; - color: #666; -} -.query-card { - border: 1px solid #ddd; - border-radius: 6px; - padding: 10px 12px; - margin-bottom: 10px; - background: #fff; - box-shadow: 0 1px 4px rgba(0,0,0,0.08); -} - -.query-card__header { - display: flex; - justify-content: space-between; - align-items: center; -} - -.query-card__name { - font-weight: 600; - font-size: 14px; -} - -.query-card__status { - padding: 2px 6px; - border-radius: 4px; - font-size: 11px; - text-transform: uppercase; - font-weight: 600; -} - -.query-card__status.COMPLIANT { - background: #e6f7e6; - color: #2e7d32; -} - -.query-card__status.NON_COMPLIANT { - background: #fdecea; - color: #c62828; -} - -.query-card__status.NOT_EVALUATED { - background: #e9e9e9; -} - -.query-card__evidence-title { - margin: 8px 0 4px; - font-size: 12px; - font-weight: 600; - color: #555; -} - -.query-card__evidence ul { - margin: 0; - padding-left: 16px; - font-size: 12px; - color: #666; -} - - -// TODO: ELENA mas nuevos - -.control-summary-card { - border: 1px solid #ddd; - border-radius: 10px; - padding: 14px 18px; - //width: 320px; - background: #fff; - box-shadow: 0 2px 6px rgba(0,0,0,0.08); - display: flex; - flex-direction: column; - gap: 10px; -} - -.control-summary-header { - display: flex; - justify-content: space-between; - align-items: center; -} - -.control-id { - font-weight: 600; - color: #444; -} - -.control-status { - padding: 3px 8px; - border-radius: 4px; - font-size: 12px; - font-weight: 600; -} - -.control-status.COMPLIANT { - background: #e6f7e6; - color: #2e7d32; -} - -.control-status.NON_COMPLIANT { - background: #fdecea; - color: #c62828; -} - -.control-status.NOT_EVALUATED { - background: #e9e9e9; -} - -.control-name { - margin: 0; - font-size: 17px; - font-weight: 600; - color: #222; -} - -.control-timestamp { - font-size: 13px; - color: #666; -} - -.control-summary-footer { - margin-top: 6px; - font-size: 13px; - color: #555; - border-top: 1px solid #eee; - padding-top: 6px; -} - -.title-label { - font-weight: 600; -} - -.data-not-found { - color: rgba(0, 75, 139, 0.30) !important; - min-height: 100vh -} diff --git a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts b/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts deleted file mode 100644 index 062336ab3..000000000 --- a/frontend/src/app/compliance/compliance-evaluations-view/compliance-evaluations-view.component.ts +++ /dev/null @@ -1,312 +0,0 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; -import {CompactType, GridsterConfig, GridType} from 'angular-gridster2'; -import {UUID} from 'angular2-uuid'; -import {NgxSpinnerService} from 'ngx-spinner'; -import {Subject} from 'rxjs'; -import {filter, takeUntil, tap} from 'rxjs/operators'; -import {TimeFilterBehavior} from '../../shared/behaviors/time-filter.behavior'; -import {UtmDashboardType} from '../../shared/chart/types/dashboard/utm-dashboard.type'; -import {ExportPdfService} from '../../shared/services/util/export-pdf.service'; -import {ComplianceParamsEnum} from '../shared/enums/compliance-params.enum'; -import {ComplianceStatusExtendedEnum} from '../shared/enums/compliance-status.enum'; -import {ComplianceStrategyEnum} from '../shared/enums/compliance-strategy.enum'; -import {CpControlConfigService} from '../shared/services/cp-control-config.service'; -import {ComplianceControlEvaluationType} from '../shared/type/compliance-control-evaluation.type'; -import {ComplianceControlEvaluationsType} from '../shared/type/compliance-control-evaluations.type'; - -@Component({ - selector: 'app-compliance-evaluations-view', - templateUrl: './compliance-evaluations-view.component.html', - styleUrls: ['./compliance-evaluations-view.component.scss'] -}) -export class ComplianceEvaluationsViewComponent implements OnInit, OnDestroy { - - constructor(private activeRoute: ActivatedRoute, - // private cpReportsService: CpReportsService, - private cpControlConfigService: CpControlConfigService, - private timeFilterBehavior: TimeFilterBehavior, - private spinner: NgxSpinnerService, - private exportPdfService: ExportPdfService) { - } - @Input() showExport = true; - @Input() template: 'default' | 'compliance' = 'default'; - controlId: number; - currentEvaluation: ComplianceControlEvaluationType; - evaluationsHistory: ComplianceControlEvaluationsType[]; - loading = false; - showDetails = false; - showRemediation = false; - showSolution = false; - selectedEvaluation: ComplianceControlEvaluationsType; - UUID = UUID.UUID(); - interval: any; - dashboard: UtmDashboardType; - pdfExport = false; - public options: GridsterConfig = { - gridType: GridType.ScrollVertical, - setGridSize: true, - compactType: CompactType.None, - minCols: 30, - minRows: 1, - minItemRows: 1, - fixedRowHeight: 430, - fixedColWidth: 500, - defaultItemCols: 1, - defaultItemRows: 1, - draggable: { - enabled: false, - }, - resizable: { - enabled: false, - }, - swap: false, - disableWindowResize: false, - }; - standardId: number; - sectionId: number; - configSolution: string; - destroy$: Subject = new Subject(); - showBack = false; - - chartOption: any = {}; - - ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; - ComplianceStrategyEnum = ComplianceStrategyEnum; - - ngOnInit() { - this.loading = true; - /*this.activeRoute.queryParams - .pipe( - takeUntil(this.destroy$), - filter((params) => Object.keys(params).length > 0), - tap(() => { - this.showBack = true; - })) - .subscribe((params) => { - //this.initializeReportParams(params); - });*/ - - this.cpControlConfigService.onLoadControl$ - .pipe(takeUntil(this.destroy$), - filter(params => !!params), - ).subscribe(params => { - this.currentEvaluation = params.template; - console.log('Current eval: ', this.currentEvaluation); - if (this.currentEvaluation) { - this.loadReport(params); - } - - }); - - /*this.timeFilterBehavior.$time - .pipe(takeUntil(this.destroy$)) - .subscribe(time => { - if (time) { - rebuildVisualizationFilterTime({timeFrom: time.from, timeTo: time.to}, this.filtersValues).then(filters => { - this.filtersValues = filters; - }); - } - });*/ - } - - loadReport(params: any) { - this.showDetails = false; - this.controlId = params.template && params.template.id ? params.template.id : null; - this.standardId = params[ComplianceParamsEnum.STANDARD_ID]; - this.sectionId = params[ComplianceParamsEnum.SECTION_ID]; - this.getEvaluations(); - } - - initializeReportParams(params: any) { - this.controlId = params[ComplianceParamsEnum.TEMPLATE]; - this.standardId = params[ComplianceParamsEnum.STANDARD_ID]; - this.sectionId = params[ComplianceParamsEnum.SECTION_ID]; - - this.getEvaluations(); - } - - getEvaluations() { - if (this.controlId) { - this.loading = true; - this.cpControlConfigService.evaluationsByControl(this.controlId) - .subscribe(response => { - this.evaluationsHistory = response.body.evaluations; - /*this.chartOption = { - tooltip: { - trigger: 'item', - formatter: params => { - const e = params.data; - return ` - ${e.dateFormatted}
- Status: ${e.status} - `; - } - }, - xAxis: { - type: 'time', - min: new Date(response.body.startDate).getTime(), - max: new Date(response.body.endDate).getTime(), - axisLabel: { - formatter: value => { - const d = new Date(value); - return d.toLocaleString('en-US', { - month: 'short', - day: '2-digit', - year: 'numeric', - }); - } - }, - axisTick: { - alignWithLabel: true - }, - splitLine: { - show: true - }, - interval: 1000 * 60 * 60 * 24 - }, - yAxis: { show: false }, - dataZoom: [ - { type: 'slider', start: 0, end: 10 }, - { type: 'inside', start: 0, end: 10 } - ], - series: [ - { - type: 'custom', - renderItem: (params, api) => { - const xValue = api.value(0); - const x = api.coord([xValue, 0])[0]; - - const totalWidth = 40; - const margin = 2; - const width = totalWidth - margin * 2; - - const yBottom = api.coord([xValue, 0])[1]; - const yTop = api.coord([xValue, 1])[1]; - const height = yBottom - yTop; - - return { - type: 'group', - children: [ - { - type: 'rect', - shape: { - x: x - totalWidth / 2 + margin, - y: yTop, - width, - height - }, - style: api.style(), - // ⭐ Aquí viene la magia - clipPath: { - type: 'rect', - shape: { - x: x - totalWidth / 2 + margin, - y: yTop, - width, - height, - r: 5 // ⭐ radio de borde redondeado - } - } - } - ] - }; - }, - data: [] - } - ] - - };*/ - - //this.chartOption.series[0].data = this.buildChartData(); - //this.chartOption = { ...this.chartOption }; - this.loading = false; - }); - } - } - - /*private buildChartData() { - return this.evaluationsHistory.map(e => ({ - value: [e.timestamp, 0], - controlId: e.controlId, - status: e.status, - timestamp: e.timestamp, - dateFormatted: new Date(e.timestamp).toLocaleString('en-US', { - month: 'short', - day: '2-digit', - year: 'numeric' - }), - itemStyle: { - color: e.status === 'COMPLIANT' ? '#4CAF50' : '#F44336' - } - })); - }*/ - - loadVisualizations(dashboardId) { - /*this.dashboardId = dashboardId; - if (this.dashboardId) { - const request = { - page: 0, - size: 10000, - 'idDashboard.equals': this.dashboardId, - sort: 'order,asc' - }; - this.utmRenderVisualization.query(request).subscribe(vis => { - this.visualizationRender = vis.body; - this.loadingVisualizations = false; - }); - }*/ - } - exportToPdf() { - /*filtersToStringParam(this.filtersValues).then(queryParams => { - this.spinner.show('buildPrintPDF'); - const params = queryParams !== '' ? '?' + queryParams : ''; - const url = '/dashboard/export-compliance/' + this.controlId + params; - const fileName = this.control.associatedDashboard.name.replace(/ /g, '_'); - this.exportPdfService.getPdf(url, fileName, 'PDF_TYPE_TOKEN').subscribe(response => { - this.spinner.hide('buildPrintPDF').then(() => - this.exportPdfService.handlePdfResponse(response)); - }, error => { - this.spinner.hide('buildPrintPDF').then(() => - this.utmToastService.showError('Error', 'An error occurred while creating a PDF.')); - }); - });*/ - } - viewSolution(solution: string): void { - this.configSolution = solution; - } - - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - } - - showEvaluationDetails(evaluation: ComplianceControlEvaluationsType) { - this.showDetails = true; - console.log(this.selectedEvaluation); - this.selectedEvaluation = evaluation; - } - - onChartInit(chart: any) { - /*this.chartInstance = chart; - - // Limpia listeners previos para evitar duplicados al refrescar datos - this.chartInstance.off('click'); - - // Listener principal - this.chartInstance.on('click', (params: any) => { - const point = params.data; - - // Encuentra la evaluación seleccionada - const evaluation = this.evaluations.find( - e => e.timestamp === point.timestamp - ); - - if (evaluation) { - this.selectedEvaluation = evaluation; - // Aquí puedes abrir panel lateral, modal, etc. - } - }); - */ - } -} diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.css b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.css similarity index 100% rename from frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.css rename to frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.css diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.html b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.html similarity index 100% rename from frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.html rename to frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.html diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.ts b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.ts similarity index 58% rename from frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.ts rename to frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.ts index 26c93f4f3..e5bf23eae 100644 --- a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component.ts +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.ts @@ -3,16 +3,15 @@ import {Observable} from 'rxjs'; import {TimezoneFormatService} from '../../../shared/services/utm-timezone.service'; import {DatePipeDefaultOptions} from '../../../shared/types/date-pipe-default-options'; import {ComplianceStatusExtendedEnum} from '../../shared/enums/compliance-status.enum'; -import {ComplianceControlEvaluationType} from '../../shared/type/compliance-control-evaluation.type'; - +import {ComplianceControlLatestEvaluationType} from '../../shared/type/compliance-control-latest-evaluation.type'; @Component({ - selector: 'app-compliance-evaluation-view-detail', - templateUrl: './compliance-evaluation-view-detail.component.html', - styleUrls: ['./compliance-evaluation-view-detail.component.css'] + selector: 'app-compliance-latest-evaluation-view-detail', + templateUrl: './compliance-latest-evaluation-view-detail.component.html', + styleUrls: ['./compliance-latest-evaluation-view-detail.component.css'] }) -export class ComplianceEvaluationViewDetailComponent implements OnInit { - @Input() control: ComplianceControlEvaluationType; +export class ComplianceLatestEvaluationViewDetailComponent implements OnInit { + @Input() control: ComplianceControlLatestEvaluationType; dateFormat$: Observable; ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; constructor(private timezoneFormatService: TimezoneFormatService) { } diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.css b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css similarity index 86% rename from frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.css rename to frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css index 83edee8e7..a27da03a0 100644 --- a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.css +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css @@ -31,8 +31,3 @@ table { .border-left-neutral { border-left: 5px solid #e9e9e9 !important; } - -.button-pdf { - margin-right: 25px !important; - margin-top: 0; -} diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.html b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.html similarity index 96% rename from frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.html rename to frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.html index dea3615bb..aa150eb72 100644 --- a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.html +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.html @@ -15,7 +15,6 @@
@@ -83,7 +82,7 @@
- + @@ -130,6 +129,6 @@
- +
diff --git a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.ts b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.ts similarity index 74% rename from frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.ts rename to frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.ts index e63b77cfc..0c56253c0 100644 --- a/frontend/src/app/compliance/compliance-evaluation-view/compliance-evaluation-view.component.ts +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.ts @@ -10,31 +10,29 @@ import { Output } from '@angular/core'; import {EMPTY, Observable, Subject} from 'rxjs'; -import {catchError, filter, map, switchMap, takeUntil, tap} from 'rxjs/operators'; +import {catchError, distinctUntilChanged, filter, map, switchMap, takeUntil, tap} from 'rxjs/operators'; import {UtmToastService} from '../../shared/alert/utm-toast.service'; import {SortEvent} from '../../shared/directives/sortable/type/sort-event'; import {TimezoneFormatService} from '../../shared/services/utm-timezone.service'; import {DatePipeDefaultOptions} from '../../shared/types/date-pipe-default-options'; -import {SortByType} from '../../shared/types/sort-by.type'; import {ComplianceStatusExtendedEnum} from '../shared/enums/compliance-status.enum'; import {CpControlConfigService} from '../shared/services/cp-control-config.service'; -import {ComplianceControlEvaluationType} from '../shared/type/compliance-control-evaluation.type'; +import {ComplianceControlLatestEvaluationType} from '../shared/type/compliance-control-latest-evaluation.type'; import {ComplianceStandardSectionType} from '../shared/type/compliance-standard-section.type'; @Component({ - selector: 'app-compliance-evaluation-view', - templateUrl: './compliance-evaluation-view.component.html', - styleUrls: ['./compliance-evaluation-view.component.css'], + selector: 'app-compliance-latest-evaluations-view', + templateUrl: './compliance-latest-evaluations-view.component.html', + styleUrls: ['./compliance-latest-evaluations-view.component.css'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class ComplianceEvaluationViewComponent implements OnInit, OnChanges, OnDestroy { +export class ComplianceLatestEvaluationsViewComponent implements OnInit, OnChanges, OnDestroy { @Input() section: ComplianceStandardSectionType; @Output() pageChange = new EventEmitter<{}>(); - controls$: Observable; + controls$: Observable; selected: number; - fields: SortByType[]; - controlDetail: ComplianceControlEvaluationType; + controlDetail: ComplianceControlLatestEvaluationType; loading = true; noData = false; itemsPerPage = 15; @@ -66,20 +64,32 @@ export class ComplianceEvaluationViewComponent implements OnInit, OnChanges, OnD this.viewportHeight = window.innerHeight; this.dateFormat$ = this.timezoneFormatService.getDateFormatSubject(); this.controls$ = this.controlsService.onRefresh$ - .pipe(takeUntil(this.destroy$), + .pipe( + takeUntil(this.destroy$), + distinctUntilChanged((prev, curr) => + prev && + curr && + prev.loading === curr.loading && + prev.page === curr.page && + prev.reportSelected === curr.reportSelected && + prev.sectionId === curr.sectionId + ), filter(reportRefresh => - !!reportRefresh && reportRefresh.loading), + !!reportRefresh && reportRefresh.loading + ), tap((reportRefresh) => { this.loading = true; this.selected = reportRefresh.reportSelected; }), - switchMap((reportRefresh) => this.controlsService.fetchData({ - page: reportRefresh.page, // TODO: ELENA - check - size: this.itemsPerPage, // ?? - sectionId: this.section.id, - sort: this.sort, // ?? - search: this.search ? this.search : null, // ?? - })), + switchMap((reportRefresh) => { + return this.controlsService.fetchData({ + page: reportRefresh.page, + size: this.itemsPerPage, + sectionId: this.section.id, + sort: this.sort, + search: this.search ? this.search : null, + }); + }), tap(res => this.totalItems = Number(res.headers.get('X-Total-Count'))), map((res) => { return res.body.map((r, index) => { @@ -151,5 +161,4 @@ export class ComplianceEvaluationViewComponent implements OnInit, OnChanges, OnD this.destroy$.next(); this.destroy$.complete(); } - } diff --git a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts index 72bf0f2db..ec26e9b0f 100644 --- a/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts +++ b/frontend/src/app/compliance/compliance-management/cp-standard-management/cp-standard-management.component.ts @@ -5,8 +5,8 @@ import {ADMIN_ROLE} from '../../../shared/constants/global.constant'; import {ActionInitParamsEnum, ActionInitParamsValueEnum} from '../../../shared/enums/action-init-params.enum'; import {CpStandardBehavior} from '../../shared/behavior/cp-standard.behavior'; import { - UtmComplianceControlConfigCreateComponent -} from '../../shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component'; + UtmComplianceControlCreateComponent +} from '../../shared/components/utm-compliance-control-create/utm-compliance-control-create.component'; import {UtmComplianceCreateComponent} from '../../shared/components/utm-compliance-create/utm-compliance-create.component'; import {ComplianceStandardType} from '../../shared/type/compliance-standard.type'; @@ -54,6 +54,6 @@ export class CpStandardManagementComponent implements OnInit { //TODO: ELENA to be checked newCompliance() { //this.modalService.open(UtmComplianceCreateComponent, {centered: true}); - this.modalService.open(UtmComplianceControlConfigCreateComponent, {centered: true, size: 'lg'}); + this.modalService.open(UtmComplianceControlCreateComponent, {centered: true, size: 'lg'}); } } diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.ts b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.ts index 99821b175..71af11a89 100644 --- a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.ts +++ b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config-delete/utm-cp-control-config-delete.component.ts @@ -2,7 +2,7 @@ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; import {UtmToastService} from '../../../../shared/alert/utm-toast.service'; import {CpControlConfigService} from '../../../shared/services/cp-control-config.service'; -import {ComplianceControlConfigType} from '../../../shared/type/compliance-control-config.type'; +import {ComplianceControlType} from '../../../shared/type/compliance-control.type'; @Component({ selector: 'app-utm-cp-control-config-delete', @@ -10,7 +10,7 @@ import {ComplianceControlConfigType} from '../../../shared/type/compliance-contr styleUrls: ['./utm-cp-control-config-delete.component.scss'] }) export class UtmCpControlConfigDeleteComponent implements OnInit { - @Input() control: ComplianceControlConfigType; + @Input() control: ComplianceControlType; @Output() controlDelete = new EventEmitter(); constructor(public activeModal: NgbActiveModal, diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.ts b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.ts index 7e0ce48fb..d45048382 100644 --- a/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.ts +++ b/frontend/src/app/compliance/compliance-management/utm-cp-control-config/utm-cp-control-config.component.ts @@ -3,10 +3,10 @@ import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; import {CpReportBehavior} from '../../shared/behavior/cp-report.behavior'; import {CpStandardSectionBehavior} from '../../shared/behavior/cp-standard-section.behavior'; import { - UtmComplianceControlConfigCreateComponent -} from '../../shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component'; + UtmComplianceControlCreateComponent +} from '../../shared/components/utm-compliance-control-create/utm-compliance-control-create.component'; import {CpControlConfigService} from '../../shared/services/cp-control-config.service'; -import {ComplianceControlConfigType} from '../../shared/type/compliance-control-config.type'; +import {ComplianceControlType} from '../../shared/type/compliance-control.type'; import {ComplianceStandardSectionType} from '../../shared/type/compliance-standard-section.type'; import {UtmCpControlConfigDeleteComponent} from './utm-cp-control-config-delete/utm-cp-control-config-delete.component'; @@ -17,7 +17,7 @@ import {UtmCpControlConfigDeleteComponent} from './utm-cp-control-config-delete/ }) export class UtmCpControlConfigComponent implements OnInit { section: ComplianceStandardSectionType; - complianceControls: ComplianceControlConfigType[] = []; + complianceControls: ComplianceControlType[] = []; loadingTemplates = true; page = 1; solution: string; @@ -70,7 +70,7 @@ export class UtmCpControlConfigComponent implements OnInit { this.getControls(); } - deleteControl(control: ComplianceControlConfigType) { + deleteControl(control: ComplianceControlType) { const modal = this.modalService.open(UtmCpControlConfigDeleteComponent, {centered: true}); modal.componentInstance.control = control; modal.componentInstance.controlDelete.subscribe(() => { @@ -78,8 +78,8 @@ export class UtmCpControlConfigComponent implements OnInit { }); } - editControl(control: ComplianceControlConfigType) { - const controlModal = this.modalService.open(UtmComplianceControlConfigCreateComponent, {centered: true, size: 'lg'}); + editControl(control: ComplianceControlType) { + const controlModal = this.modalService.open(UtmComplianceControlCreateComponent, {centered: true, size: 'lg'}); controlModal.componentInstance.control = control; controlModal.componentInstance.controlCreated.subscribe(() => { this.getControls(); diff --git a/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts b/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts deleted file mode 100644 index 8fda98475..000000000 --- a/frontend/src/app/compliance/compliance-query-evaluations-view/compliance-query-evaluations-view.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; -import {ComplianceStatusExtendedEnum} from '../shared/enums/compliance-status.enum'; -import {ComplianceControlEvaluationsType} from '../shared/type/compliance-control-evaluations.type'; -import {ComplianceQueryEvaluationType} from '../shared/type/compliance-query-evaluation.type'; - -@Component({ - selector: 'app-compliance-query-evaluations-view', - templateUrl: './compliance-query-evaluations-view.component.html', - styleUrls: ['./compliance-query-evaluations-view.component.scss'] -}) -export class ComplianceQueryEvaluationsViewComponent implements OnInit, OnDestroy { - @Input() evaluation: ComplianceControlEvaluationsType; - queryDetail: ComplianceQueryEvaluationType; - - ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; - - constructor() { - } - - ngOnDestroy(): void { - - } - - ngOnInit(): void { - console.log('queryEval', this.evaluation); - } - -} diff --git a/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.html b/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.html index 95a05887c..220f44462 100644 --- a/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.html +++ b/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.html @@ -62,7 +62,7 @@
[loadFirst]="index === activeIndexSection" [index]="index" (isActive)="onChangeSectionActive($event, section, sections)" - [expandable]="action==='reports'"> + [expandable]="action ==='reports'">
@@ -74,8 +74,8 @@
- - + +
diff --git a/frontend/src/app/compliance/compliance-reports-view/compliance-reports-view.component.ts b/frontend/src/app/compliance/compliance-reports-view/compliance-reports-view.component.ts index 4f6625afb..987b28798 100644 --- a/frontend/src/app/compliance/compliance-reports-view/compliance-reports-view.component.ts +++ b/frontend/src/app/compliance/compliance-reports-view/compliance-reports-view.component.ts @@ -141,7 +141,6 @@ export class ComplianceReportsViewComponent implements OnInit, OnChanges, OnDest } getTableHeight() { - console.log('getTableHeight:', 100 - ((350 / this.viewportHeight) * 100) + 'vh'); return 100 - ((350 / this.viewportHeight) * 100) + 'vh'; } diff --git a/frontend/src/app/compliance/shared/compliance-shared.module.ts b/frontend/src/app/compliance/shared/compliance-shared.module.ts index bc6c1c291..385bbcf20 100644 --- a/frontend/src/app/compliance/shared/compliance-shared.module.ts +++ b/frontend/src/app/compliance/shared/compliance-shared.module.ts @@ -11,17 +11,18 @@ import { } from '../../data-management/alert-management/shared/alert-management-shared.module'; import {GraphicBuilderSharedModule} from '../../graphic-builder/shared/graphic-builder-shared.module'; import {UtmSharedModule} from '../../shared/utm-shared.module'; +import {ComplianceEvaluationHistoryViewComponent} from '../compliance-evaluation-history-view/compliance-evaluation-history-view.component'; import { - ComplianceEvaluationViewDetailComponent -} from '../compliance-evaluation-view/compliance-evaluation-view-detail/compliance-evaluation-view-detail.component'; -import {ComplianceEvaluationViewComponent} from '../compliance-evaluation-view/compliance-evaluation-view.component'; -import {ComplianceEvaluationsViewComponent} from '../compliance-evaluations-view/compliance-evaluations-view.component'; + ComplianceQueryEvaluationDetailComponent +// tslint:disable-next-line:max-line-length +} from '../compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component'; import { ComplianceQueryEvaluationsViewComponent -} from '../compliance-query-evaluations-view/compliance-query-evaluations-view.component'; +} from '../compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component'; import { - ComplianceQueryEvaluationDetailComponent -} from '../compliance-query-evaluations-view/components/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component'; + ComplianceLatestEvaluationViewDetailComponent +} from '../compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component'; +import {ComplianceLatestEvaluationsViewComponent} from '../compliance-latest-evaluations-view/compliance-latest-evaluations-view.component'; import {ComplianceReportsViewComponent} from '../compliance-reports-view/compliance-reports-view.component'; import { CompliancePrintViewComponent @@ -37,14 +38,14 @@ import { } from '../compliance-reports-view/components/compliance-time-window/compliance-time-windows.component'; import {ReportApplyNoteComponent} from './components/report-apply-note/report-apply-note.component'; import { - UtmComplianceQueryListComponent -} from './components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component'; + UtmComplianceCreateQueryComponent +} from './components/utm-compliance-control-create/query-config/utm-compliance-create-query.component'; import { - UtmComplianceQueryComponent -} from './components/utm-compliance-control-config-create/query-config/utm-compliance-query.component'; + UtmComplianceQueryListComponent +} from './components/utm-compliance-control-create/query-config/utm-compliance-query-list.component'; import { - UtmComplianceControlConfigCreateComponent -} from './components/utm-compliance-control-config-create/utm-compliance-control-config-create.component'; + UtmComplianceControlCreateComponent +} from './components/utm-compliance-control-create/utm-compliance-control-create.component'; import {UtmComplianceCreateComponent} from './components/utm-compliance-create/utm-compliance-create.component'; import { UtmComplianceScheduleCreateComponent @@ -84,15 +85,15 @@ import {ComplianceStatusLabelPipe} from './pipes/compliance-status-label.pipe'; ComplianceQueryEvaluationDetailComponent, ComplianceTimeWindowsComponent, CompliancePrintViewComponent, - UtmComplianceControlConfigCreateComponent, - UtmComplianceQueryComponent, + UtmComplianceControlCreateComponent, + UtmComplianceCreateQueryComponent, UtmComplianceQueryListComponent, - ComplianceEvaluationViewComponent, - ComplianceEvaluationsViewComponent, + ComplianceLatestEvaluationsViewComponent, + ComplianceEvaluationHistoryViewComponent, UtmCpSectionConfigComponent, ComplianceTimelineComponent, ComplianceQueryEvaluationsViewComponent, - ComplianceEvaluationViewDetailComponent, + ComplianceLatestEvaluationViewDetailComponent, ComplianceStatusLabelPipe ], imports: [ @@ -118,7 +119,7 @@ import {ComplianceStatusLabelPipe} from './pipes/compliance-status-label.pipe'; UtmComplianceCreateComponent, UtmComplianceScheduleCreateComponent, UtmComplianceScheduleDeleteComponent, - UtmComplianceControlConfigCreateComponent + UtmComplianceControlCreateComponent ], exports: [ UtmSaveAsComplianceComponent, @@ -137,8 +138,8 @@ import {ComplianceStatusLabelPipe} from './pipes/compliance-status-label.pipe'; ComplianceQueryEvaluationDetailComponent, ComplianceTimeWindowsComponent, CompliancePrintViewComponent, - ComplianceEvaluationViewComponent, - ComplianceEvaluationsViewComponent, + ComplianceLatestEvaluationsViewComponent, + ComplianceEvaluationHistoryViewComponent, UtmCpSectionConfigComponent, ComplianceStatusLabelPipe ] diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss deleted file mode 100644 index e24d001bf..000000000 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -.query-list-container { - width: 100%; -} - -.table td { - vertical-align: middle; -} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.css b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.css similarity index 100% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.css rename to frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.css diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.html similarity index 100% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.html rename to frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.html diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.ts similarity index 89% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts rename to frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.ts index d517be0aa..b0682e5cf 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.ts @@ -9,19 +9,19 @@ import { ComplianceEvaluationRuleEnum, ComplianceEvaluationRuleLabels } from '../../../enums/compliance-evaluation-rule.enum'; -import {ComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; +import {ComplianceQueryType} from '../../../type/compliance-query.type'; @Component({ - selector: 'app-utm-compliance-query', - templateUrl: './utm-compliance-query.component.html', - styleUrls: ['./utm-compliance-query.component.css'] + selector: 'app-utm-compliance-create-query', + templateUrl: './utm-compliance-create-query.component.html', + styleUrls: ['./utm-compliance-create-query.component.css'] }) -export class UtmComplianceQueryComponent implements OnInit { +export class UtmComplianceCreateQueryComponent implements OnInit { - @Input() query: ComplianceQueryConfigType = null; + @Input() query: ComplianceQueryType = null; @Input() indexPatterns: UtmIndexPattern[] = []; @Input() indexPatternNames: string[] = []; - @Output() add = new EventEmitter(); + @Output() add = new EventEmitter(); @Output() cancel = new EventEmitter(); form: FormGroup; diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.html similarity index 66% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html rename to frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.html index 748485783..8e2519abd 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.html @@ -1,27 +1,27 @@ - - + - - +
- - - - - - - + + + + + + + @@ -33,8 +33,12 @@ - - + +
Query NameSQL QueryEvaluation RuleIndex PatternActions
Query NameSQL QueryEvaluation RuleIndex PatternActions
{{ q.sqlQuery | slice:0:30 }}{{ q.sqlQuery.length > 30 ? '…' : '' }} {{ q.evaluationRule }}{{ getIndexPatternName(q.indexPatternId) }} + {{ q.evaluationRule }} + + {{ getIndexPatternName(q.indexPatternId) }} +
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.scss new file mode 100644 index 000000000..334e1633d --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.scss @@ -0,0 +1,3 @@ +.table td { + vertical-align: middle; +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.ts similarity index 86% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts rename to frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.ts index 3e4651fc7..e5b34a5bc 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/query-config/utm-compliance-query-list.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.ts @@ -2,7 +2,7 @@ import {HttpResponse} from '@angular/common/http'; import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {IndexPatternService} from '../../../../../shared/services/elasticsearch/index-pattern.service'; import {UtmIndexPattern} from '../../../../../shared/types/index-pattern/utm-index-pattern'; -import {ComplianceQueryConfigType} from '../../../type/compliance-query-config.type'; +import {ComplianceQueryType} from '../../../type/compliance-query.type'; @Component({ @@ -12,8 +12,9 @@ import {ComplianceQueryConfigType} from '../../../type/compliance-query-config.t }) export class UtmComplianceQueryListComponent implements OnInit { // tslint:disable-next-line:variable-name - private _queries: ComplianceQueryConfigType[] = []; - @Input() set queries(value: ComplianceQueryConfigType[]) { + private _queries: ComplianceQueryType[] = []; + + @Input() set queries(value: ComplianceQueryType[]) { this._queries = value || []; } @@ -22,16 +23,19 @@ export class UtmComplianceQueryListComponent implements OnInit { } @Output() add = new EventEmitter<{ - query: ComplianceQueryConfigType; + query: ComplianceQueryType; index: number | null; }>(); + @Output() remove = new EventEmitter(); patterns: UtmIndexPattern[]; indexPatternNames = []; editingIndex: number = null; - constructor(private indexPatternService: IndexPatternService) {} + constructor(private indexPatternService: IndexPatternService) { + + } ngOnInit() { this.getIndexPatterns(); @@ -45,7 +49,7 @@ export class UtmComplianceQueryListComponent implements OnInit { this.editingIndex = null; } - onQueryAdd(query: ComplianceQueryConfigType): void { + onQueryAdd(query: ComplianceQueryType): void { this.add.emit({ query, index: this.editingIndex @@ -86,7 +90,7 @@ export class UtmComplianceQueryListComponent implements OnInit { } private onError(error) { - //this.alertService.error(error.error, error.message, null); + // this.alertService.error(error.error, error.message, null); } getIndexPatternName(id: number) { diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.html similarity index 86% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html rename to frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.html index d2f64b0c2..5460bb8f1 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.html @@ -1,4 +1,4 @@ - +
@@ -6,9 +6,9 @@ Report Configuration -
- +
@@ -16,14 +16,14 @@ Queries Configuration -
- +
-
+
@@ -92,7 +92,7 @@
-
+
  Back -
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.scss similarity index 100% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.scss rename to frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.scss diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.ts similarity index 84% rename from frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts rename to frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.ts index 9e2194fcc..0a577fd8f 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-config-create/utm-compliance-control-config-create.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.ts @@ -1,20 +1,20 @@ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {FormArray, FormBuilder, FormGroup, Validators} from '@angular/forms'; -import {NgbActiveModal, NgbModal} from '@ng-bootstrap/ng-bootstrap'; +import {NgbActiveModal} from '@ng-bootstrap/ng-bootstrap'; import {UtmToastService} from '../../../../shared/alert/utm-toast.service'; import {CpReportBehavior} from '../../behavior/cp-report.behavior'; import {ComplianceStrategyEnum} from '../../enums/compliance-strategy.enum'; import {CpControlConfigService} from '../../services/cp-control-config.service'; -import {ComplianceControlConfigType} from '../../type/compliance-control-config.type'; -import {ComplianceQueryConfigType} from '../../type/compliance-query-config.type'; +import {ComplianceControlType} from '../../type/compliance-control.type'; +import {ComplianceQueryType} from '../../type/compliance-query.type'; @Component({ - selector: 'app-utm-compliance-control-config-create', - templateUrl: './utm-compliance-control-config-create.component.html', - styleUrls: ['./utm-compliance-control-config-create.component.scss'] + selector: 'app-utm-compliance-control-create', + templateUrl: './utm-compliance-control-create.component.html', + styleUrls: ['./utm-compliance-control-create.component.scss'] }) -export class UtmComplianceControlConfigCreateComponent implements OnInit { - @Input() control: ComplianceControlConfigType; +export class UtmComplianceControlCreateComponent implements OnInit { + @Input() control: ComplianceControlType; @Output() controlCreated = new EventEmitter(); loading = true; @@ -31,7 +31,6 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { public activeModal: NgbActiveModal, private cpReportBehavior: CpReportBehavior, private utmToastService: UtmToastService, - public modalService: NgbModal, private fb: FormBuilder) { } @@ -83,7 +82,7 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { createCompliance() { this.creating = true; - const controlConfigCompliance: ComplianceControlConfigType = { + const controlConfigCompliance: ComplianceControlType = { standardSectionId: this.standardSectionId, controlName: this.complianceForm.controls.controlName.value, controlSolution: this.complianceForm.controls.solution.value.replace(/\r?\n/g, '
'), @@ -95,7 +94,7 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { if (this.control) { controlConfigCompliance.id = this.control.id; this.cpControlConfigService.update(controlConfigCompliance).subscribe(() => { - this.utmToastService.showSuccessBottom('Compliance report edited successfully'); + this.utmToastService.showSuccessBottom('Compliance report edited successfully'); this.activeModal.close(); this.controlCreated.emit('edited'); }, error1 => { @@ -104,7 +103,7 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { }); } else { this.cpControlConfigService.create(controlConfigCompliance).subscribe(() => { - this.utmToastService.showSuccessBottom('Compliance report created successfully'); + this.utmToastService.showSuccessBottom('Compliance report created successfully'); this.activeModal.close(); this.cpReportBehavior.$reportUpdate.next('update'); this.controlCreated.emit('created'); @@ -123,7 +122,7 @@ export class UtmComplianceControlConfigCreateComponent implements OnInit { return this.queriesConfigs.controls.map(c => c.value); } - onQueryAdd(event: { query: ComplianceQueryConfigType ; index: number | null }) { + onQueryAdd(event: { query: ComplianceQueryType ; index: number | null }) { const { query, index } = event; if (index === null) { this.queriesConfigs.push(this.fb.control(query)); diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html index 42876815c..2bc96e847 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html @@ -8,4 +8,3 @@
(chartClick)="onChartClick($event)">
- diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts index 14bdab69f..a34a0270d 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts @@ -1,6 +1,6 @@ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {ComplianceStatusExtendedEnum, getComplianceStatusLabel} from '../../enums/compliance-status.enum'; -import {ComplianceControlEvaluationsType} from '../../type/compliance-control-evaluations.type'; +import {ComplianceControlEvaluationHistoryType} from '../../type/compliance-control-evaluation-history.type'; @Component({ selector: 'app-compliance-timeline', @@ -8,9 +8,9 @@ import {ComplianceControlEvaluationsType} from '../../type/compliance-control-ev styleUrls: ['./compliance-timeline.component.scss'] }) export class ComplianceTimelineComponent implements OnInit { - @Input() evaluations: ComplianceControlEvaluationsType[]; - @Output() evaluationSelected = new EventEmitter(); - private originalData: ComplianceControlEvaluationsType[] = []; + @Input() evaluations: ComplianceControlEvaluationHistoryType[]; + @Output() evaluationSelected = new EventEmitter(); + private originalData: ComplianceControlEvaluationHistoryType[] = []; options: any; complianceValue = [ @@ -47,7 +47,7 @@ export class ComplianceTimelineComponent implements OnInit { } } - private transformResponse(data: ComplianceControlEvaluationsType[]): void { + private transformResponse(data: ComplianceControlEvaluationHistoryType[]): void { this.rawData = []; this.monthDays = []; this.originalData = this.evaluations; diff --git a/frontend/src/app/compliance/shared/components/utm-cp-section-config/time-windows.service.ts b/frontend/src/app/compliance/shared/components/utm-cp-section-config/time-windows.service.ts deleted file mode 100644 index 622725fb9..000000000 --- a/frontend/src/app/compliance/shared/components/utm-cp-section-config/time-windows.service.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {BehaviorSubject} from 'rxjs'; -import {Injectable} from '@angular/core'; - -@Injectable() -export class TimeWindowsService { - private timeWindowsSubject = new BehaviorSubject<{reportId: number, time: string}>(null); - onTimeWindows$ = this.timeWindowsSubject.asObservable(); - - changeTimeWindows(reportTimeWindows: {reportId: number, time: string}) { - this.timeWindowsSubject.next(reportTimeWindows); - } -} diff --git a/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.ts b/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.ts index 0fe6ed3f0..fb255a124 100644 --- a/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.ts @@ -13,8 +13,7 @@ import {EMPTY, Observable} from 'rxjs'; import {catchError, concatMap, filter, map, tap} from 'rxjs/operators'; import {UtmToastService} from '../../../../shared/alert/utm-toast.service'; import {CpControlConfigService} from '../../services/cp-control-config.service'; -import {ComplianceControlConfigType} from '../../type/compliance-control-config.type'; -import {ComplianceReportType} from '../../type/compliance-report.type'; +import {ComplianceControlType} from '../../type/compliance-control.type'; import {ComplianceStandardSectionType} from '../../type/compliance-standard-section.type'; @Component({ @@ -32,7 +31,7 @@ export class UtmCpSectionConfigComponent implements OnInit, OnChanges { @Input() expandable = true; @Input() action: 'reports' | 'compliance' = 'compliance'; - controls$: Observable; + controls$: Observable; selected: number; constructor(private cpControlConfigService: CpControlConfigService, @@ -91,7 +90,7 @@ export class UtmCpSectionConfigComponent implements OnInit, OnChanges { } } - generateReport(control: ComplianceControlConfigType, controls: ComplianceControlConfigType[]) { + generateReport(control: ComplianceControlType, controls: ComplianceControlType[]) { if (this.section.isActive && control) { controls.forEach(r => r.selected = false); control.selected = true; @@ -99,7 +98,7 @@ export class UtmCpSectionConfigComponent implements OnInit, OnChanges { } } - loadReport(report: ComplianceControlConfigType) { + loadReport(report: ComplianceControlType) { this.cpControlConfigService.loadReport({ template: report, sectionId: this.section.id, diff --git a/frontend/src/app/compliance/shared/services/cp-control-config.service.ts b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts index 93b136790..d89ac5ce4 100644 --- a/frontend/src/app/compliance/shared/services/cp-control-config.service.ts +++ b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts @@ -4,15 +4,13 @@ import {BehaviorSubject, Observable} from 'rxjs'; import {SERVER_API_URL} from '../../../app.constants'; import {RefreshDataService} from '../../../shared/services/util/refresh-data.service'; import {createRequestOption} from '../../../shared/util/request-util'; -import {ComplianceControlConfigType} from '../type/compliance-control-config.type'; -import {ComplianceControlEvaluationType} from '../type/compliance-control-evaluation.type'; -import {ComplianceControlEvaluationsType} from '../type/compliance-control-evaluations.type'; +import {ComplianceControlEvaluationHistoryResponse} from '../type/compliance-control-evaluation-history-response.type'; +import {ComplianceControlLatestEvaluationType} from '../type/compliance-control-latest-evaluation.type'; +import {ComplianceControlType} from '../type/compliance-control.type'; import {ComplianceReportType} from '../type/compliance-report.type'; -import {ReportParams} from "./cp-reports.service"; -import {ComplianceControlEvaluationsResponse} from "../type/compliance-control-evaluations-response.type"; export interface ControlParams { // TODO: ELENA para que - template: ComplianceControlConfigType; + template: ComplianceControlType; sectionId: number; standardId: number; } @@ -31,24 +29,24 @@ export class CpControlConfigService extends RefreshDataService<{ sectionId: numb super(); } - create(control: ComplianceControlConfigType): Observable> { - return this.http.post( + create(control: ComplianceControlType): Observable> { + return this.http.post( this.resourceUrl, control, {observe: 'response'}); } - query(req?: any): Observable> { + query(req?: any): Observable> { const options = createRequestOption(req); - return this.http.get(this.resourceUrl, { + return this.http.get(this.resourceUrl, { params: options, observe: 'response' }); } - update(control: ComplianceControlConfigType): Observable> { - return this.http.put( + update(control: ComplianceControlType): Observable> { + return this.http.put( `${this.resourceUrl}/${control.id}`, control, { observe: 'response' } @@ -62,21 +60,21 @@ export class CpControlConfigService extends RefreshDataService<{ sectionId: numb ); } - controlsBySection(req?: any): Observable> { + controlsBySection(req?: any): Observable> { const options = createRequestOption(req); - return this.http.get(this.resourceUrl + '/get-by-section', { + return this.http.get(this.resourceUrl + '/get-by-section', { params: options, observe: 'response' }); } - fetchData(request: any): Observable> { + fetchData(request: any): Observable> { return this.controlsBySection(request); } - evaluationsByControl(controlId: number, req?: any): Observable> { + evaluationsByControl(controlId: number, req?: any): Observable> { const options = createRequestOption(req); // TODO: ELENA valorar si dejo el req - return this.http.get( + return this.http.get( `${this.resourceUrl}/${controlId}/evaluations`, { params: options, observe: 'response' } ); diff --git a/frontend/src/app/compliance/shared/type/compliance-control-config.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-base.type.ts similarity index 54% rename from frontend/src/app/compliance/shared/type/compliance-control-config.type.ts rename to frontend/src/app/compliance/shared/type/compliance-control-base.type.ts index c0652f52e..c4c533a59 100644 --- a/frontend/src/app/compliance/shared/type/compliance-control-config.type.ts +++ b/frontend/src/app/compliance/shared/type/compliance-control-base.type.ts @@ -1,10 +1,8 @@ -import {UtmFieldType} from '../../../shared/types/table/utm-field.type'; import {ComplianceStrategyEnum} from '../enums/compliance-strategy.enum'; -import {ComplianceQueryConfigType} from './compliance-query-config.type'; +import {ComplianceQueryType} from './compliance-query.type'; import {ComplianceStandardSectionType} from './compliance-standard-section.type'; - -export class ComplianceControlConfigType { +export class ComplianceControlBaseType { id?: number; section?: ComplianceStandardSectionType; standardSectionId?: number; @@ -12,9 +10,5 @@ export class ComplianceControlConfigType { controlSolution?: string; controlRemediation?: string; controlStrategy?: ComplianceStrategyEnum; - queriesConfigs?: ComplianceQueryConfigType[]; - - columns?: UtmFieldType[]; - selected?: boolean; - status?: string; + queriesConfigs?: ComplianceQueryType[]; } diff --git a/frontend/src/app/compliance/shared/type/compliance-control-evaluation-history-response.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-evaluation-history-response.type.ts new file mode 100644 index 000000000..72ff53828 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-control-evaluation-history-response.type.ts @@ -0,0 +1,7 @@ +import {ComplianceControlEvaluationHistoryType} from './compliance-control-evaluation-history.type'; + +export interface ComplianceControlEvaluationHistoryResponse { + startDate: string; + endDate: string; + evaluations: ComplianceControlEvaluationHistoryType[]; +} diff --git a/frontend/src/app/compliance/shared/type/compliance-control-evaluation-history.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-evaluation-history.type.ts new file mode 100644 index 000000000..a7c750ab3 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-control-evaluation-history.type.ts @@ -0,0 +1,11 @@ +import {ComplianceStatusExtendedEnum} from '../enums/compliance-status.enum'; +import {ComplianceQueryEvaluationGroup} from './compliance-query-evaluation.group'; +import {ComplianceQueryEvaluationType} from './compliance-query-evaluation.type'; + +export class ComplianceControlEvaluationHistoryType { + controlId?: number; + controlName?: string; + status?: ComplianceStatusExtendedEnum; + timestamp?: string; + queryEvaluations?: ComplianceQueryEvaluationType[] | ComplianceQueryEvaluationGroup[]; +} diff --git a/frontend/src/app/compliance/shared/type/compliance-control-evaluation.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-evaluation.type.ts deleted file mode 100644 index 307e9f671..000000000 --- a/frontend/src/app/compliance/shared/type/compliance-control-evaluation.type.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {ComplianceStatusExtendedEnum} from '../enums/compliance-status.enum'; -import {ComplianceStrategyEnum} from '../enums/compliance-strategy.enum'; -import {ComplianceQueryConfigType} from './compliance-query-config.type'; -import {ComplianceStandardSectionType} from './compliance-standard-section.type'; - -export class ComplianceControlEvaluationType { - //TODO: ELENA current evaluation - controlId?: number; - standardSectionId?: number; - section?: ComplianceStandardSectionType; - - controlName?: string; - controlSolution?: string; - controlRemediation?: string; - controlStrategy?: ComplianceStrategyEnum; - - queriesConfigs?: ComplianceQueryConfigType[]; - - lastEvaluationStatus?: ComplianceStatusExtendedEnum; - lastEvaluationTimestamp?: string; -} diff --git a/frontend/src/app/compliance/shared/type/compliance-control-evaluations-response.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-evaluations-response.type.ts deleted file mode 100644 index 891f3c6d6..000000000 --- a/frontend/src/app/compliance/shared/type/compliance-control-evaluations-response.type.ts +++ /dev/null @@ -1,7 +0,0 @@ -import {ComplianceControlEvaluationsType} from './compliance-control-evaluations.type'; - -export interface ComplianceControlEvaluationsResponse { - startDate: string; - endDate: string; - evaluations: ComplianceControlEvaluationsType[]; -} diff --git a/frontend/src/app/compliance/shared/type/compliance-control-evaluations.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-evaluations.type.ts deleted file mode 100644 index e55d58480..000000000 --- a/frontend/src/app/compliance/shared/type/compliance-control-evaluations.type.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {ComplianceStatusExtendedEnum} from '../enums/compliance-status.enum'; -import {ComplianceIndexPatternQueryGroupEvaluationType} from './compliance-index-pattern-query-group-evaluation.type'; -import {ComplianceQueryEvaluationType} from './compliance-query-evaluation.type'; - -export class ComplianceControlEvaluationsType { - // TODO: ELENA registro historico de evaluaciones - controlId?: number; - controlName?: string; - status?: ComplianceStatusExtendedEnum; - timestamp?: string; - queryEvaluations?: ComplianceQueryEvaluationType[] | ComplianceIndexPatternQueryGroupEvaluationType[]; - groupedQueryEvaluations?: ComplianceIndexPatternQueryGroupEvaluationType[]; // TODO: ELENA quitar -} diff --git a/frontend/src/app/compliance/shared/type/compliance-control-latest-evaluation.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-latest-evaluation.type.ts new file mode 100644 index 000000000..28e68b9c9 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-control-latest-evaluation.type.ts @@ -0,0 +1,7 @@ +import {ComplianceStatusExtendedEnum} from '../enums/compliance-status.enum'; +import {ComplianceControlBaseType} from './compliance-control-base.type'; + +export class ComplianceControlLatestEvaluationType extends ComplianceControlBaseType { + lastEvaluationStatus?: ComplianceStatusExtendedEnum; + lastEvaluationTimestamp?: string; +} diff --git a/frontend/src/app/compliance/shared/type/compliance-control.type.ts b/frontend/src/app/compliance/shared/type/compliance-control.type.ts new file mode 100644 index 000000000..e15a353b1 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-control.type.ts @@ -0,0 +1,5 @@ +import {ComplianceControlBaseType} from './compliance-control-base.type'; + +export class ComplianceControlType extends ComplianceControlBaseType { + selected?: boolean; +} diff --git a/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts b/frontend/src/app/compliance/shared/type/compliance-query-base.type.ts similarity index 59% rename from frontend/src/app/compliance/shared/type/compliance-query-config.type.ts rename to frontend/src/app/compliance/shared/type/compliance-query-base.type.ts index f915a5a64..bfab68669 100644 --- a/frontend/src/app/compliance/shared/type/compliance-query-config.type.ts +++ b/frontend/src/app/compliance/shared/type/compliance-query-base.type.ts @@ -1,12 +1,8 @@ import {ComplianceEvaluationRuleEnum} from '../enums/compliance-evaluation-rule.enum'; -export class ComplianceQueryConfigType { +export class ComplianceQueryBaseType { id?: number; queryName?: string; queryDescription?: string; - sqlQuery?: string; evaluationRule?: ComplianceEvaluationRuleEnum; - ruleValue?: number; - indexPatternId?: number; - controlConfigId?: number; } diff --git a/frontend/src/app/compliance/shared/type/compliance-index-pattern-query-group-evaluation.type.ts b/frontend/src/app/compliance/shared/type/compliance-query-evaluation.group.ts similarity index 75% rename from frontend/src/app/compliance/shared/type/compliance-index-pattern-query-group-evaluation.type.ts rename to frontend/src/app/compliance/shared/type/compliance-query-evaluation.group.ts index ac98c938c..10cad8d28 100644 --- a/frontend/src/app/compliance/shared/type/compliance-index-pattern-query-group-evaluation.type.ts +++ b/frontend/src/app/compliance/shared/type/compliance-query-evaluation.group.ts @@ -1,6 +1,6 @@ import {ComplianceQueryEvaluationType} from './compliance-query-evaluation.type'; -export class ComplianceIndexPatternQueryGroupEvaluationType { +export class ComplianceQueryEvaluationGroup { indexPatternId?: number; indexPatternName?: string; queries?: ComplianceQueryEvaluationType[]; diff --git a/frontend/src/app/compliance/shared/type/compliance-query-evaluation.type.ts b/frontend/src/app/compliance/shared/type/compliance-query-evaluation.type.ts index d4799038e..1223a0e4c 100644 --- a/frontend/src/app/compliance/shared/type/compliance-query-evaluation.type.ts +++ b/frontend/src/app/compliance/shared/type/compliance-query-evaluation.type.ts @@ -1,10 +1,7 @@ -import {ComplianceEvaluationRuleEnum} from '../enums/compliance-evaluation-rule.enum'; import {ComplianceStatusExtendedEnum} from '../enums/compliance-status.enum'; -// TODO: ELENA ver si puedo usar ComplianceQueryConfigType -export class ComplianceQueryEvaluationType { - queryName?: string; - queryDescription?: string; - evaluationRule?: ComplianceEvaluationRuleEnum; +import {ComplianceQueryBaseType} from './compliance-query-base.type'; + +export class ComplianceQueryEvaluationType extends ComplianceQueryBaseType { indexPatternName?: string; hits?: number; status?: ComplianceStatusExtendedEnum; diff --git a/frontend/src/app/compliance/shared/type/compliance-query.type.ts b/frontend/src/app/compliance/shared/type/compliance-query.type.ts new file mode 100644 index 000000000..c5a8ae8cd --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-query.type.ts @@ -0,0 +1,8 @@ +import {ComplianceQueryBaseType} from './compliance-query-base.type'; + +export class ComplianceQueryType extends ComplianceQueryBaseType { + controlConfigId?: number; + ruleValue?: number; + sqlQuery?: string; + indexPatternId?: number; +} From 42660614febcfd675110c93fcc7f2b8e9257ec96 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Tue, 17 Mar 2026 17:53:07 -0500 Subject: [PATCH 040/135] feat: implement timeline visualization for compliance evaluations --- .../compliance-evaluation-history-view.component.ts | 1 - .../compliance-query-evaluation-detail.component.html | 4 +++- .../utm-compliance-create-query.component.ts | 9 +++++++++ .../compliance/shared/enums/compliance-status.enum.ts | 6 ++++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.ts b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.ts index 0e87ee341..de9881ccd 100644 --- a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.ts +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.ts @@ -39,7 +39,6 @@ export class ComplianceEvaluationHistoryViewComponent implements OnInit, OnDestr if (this.currentEvaluation) { this.loadReport(params); } - }); } diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html index 90f1319f5..e28c38a3b 100644 --- a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html @@ -41,7 +41,9 @@
- The query returned no results. + {{query.status !== ComplianceStatusExtendedEnum.COMPLIANT && query.status !== ComplianceStatusExtendedEnum.NON_COMPLIANT ? + 'The query was not evaluated.' + : 'The query returned no results.'}}
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.ts index b0682e5cf..8eac1b47e 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.ts @@ -80,6 +80,15 @@ export class UtmComplianceCreateQueryComponent implements OnInit { return; } + const control = this.form.get('sqlQuery'); + + if (control) { + const cleaned = control.value + .replace(/(\r\n|\n|\r)/g, ' ') + .replace(/\s+/g, ' '); + control.setValue(cleaned); + } + this.add.emit(this.form.value); this.form.reset(); } diff --git a/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts b/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts index a986fc460..eac66b792 100644 --- a/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts +++ b/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts @@ -6,13 +6,15 @@ export enum ComplianceStatusEnum { export enum ComplianceStatusExtendedEnum { COMPLIANT = 'COMPLIANT', NON_COMPLIANT = 'NON_COMPLIANT', - NOT_EVALUATED = 'NOT_EVALUATED' + NOT_EVALUATED = 'NOT_EVALUATED', + NOT_APPLICABLE = 'NOT_APPLICABLE' } export const ComplianceStatusLabels: Record = { [ComplianceStatusExtendedEnum.COMPLIANT]: 'Compliant', [ComplianceStatusExtendedEnum.NON_COMPLIANT]: 'Non Compliant', - [ComplianceStatusExtendedEnum.NOT_EVALUATED]: 'Not Evaluated' + [ComplianceStatusExtendedEnum.NOT_APPLICABLE]: 'Not Applicable', + [ComplianceStatusExtendedEnum.NOT_EVALUATED]: 'Not Evaluated', }; export function getComplianceStatusLabel( From a3d3d20d9c6196e12d201627c1ebb4db2bbe4507 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Thu, 19 Mar 2026 02:02:02 -0500 Subject: [PATCH 041/135] feat: enrich compliance evaluation details with rule, rule value, and hits --- ...ance-query-evaluation-detail.component.css | 8 ++++++- ...nce-query-evaluation-detail.component.html | 24 ++++++++++++++++++- ...ance-query-evaluations-view.component.html | 2 +- ...ance-query-evaluations-view.component.scss | 2 +- ...atest-evaluation-view-detail.component.css | 2 +- ...ance-latest-evaluations-view.component.css | 2 +- .../compliance-timeline.component.scss | 4 ++-- .../compliance-timeline.component.ts | 17 ++++++++----- .../shared/enums/compliance-status.enum.ts | 4 +++- .../shared/type/compliance-query-base.type.ts | 1 + .../shared/type/compliance-query.type.ts | 1 - 11 files changed, 51 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css index 619e8b78c..3a933288b 100644 --- a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.css @@ -15,5 +15,11 @@ } .border-left-neutral { - border-left: 5px solid #e9e9e9 !important; + border-left: 5px solid #6C757D !important; } + +.border-left { + border-left: 1px solid #ccc; + padding-left: 10px; +} + diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html index e28c38a3b..54f7c21ed 100644 --- a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html @@ -17,7 +17,7 @@ -
+
Evaluation rule: {{ ComplianceEvaluationRuleLabels[query.evaluationRule] }} @@ -25,6 +25,28 @@
+
+
+
+ Rule value: + + {{ query.ruleValue }} + +
+ +
+ Result count: + + {{ query.hits }} + +
+
+
diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html index 430c0ae3d..aa6aa22b2 100644 --- a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss index 387c3c8a0..ef0fff977 100644 --- a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component.scss @@ -34,5 +34,5 @@ } .border-left-neutral { - border-left: 5px solid #e9e9e9 !important; + border-left: 5px solid #6C757D !important; } diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.css b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.css index 470c44de5..2dcc588c1 100644 --- a/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.css +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.css @@ -15,7 +15,7 @@ } .border-left-neutral { - border-left: 5px solid #e9e9e9 !important; + border-left: 5px solid #6C757D !important; } button { diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css index a27da03a0..4af543688 100644 --- a/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css @@ -29,5 +29,5 @@ table { } .border-left-neutral { - border-left: 5px solid #e9e9e9 !important; + border-left: 5px solid #6C757D !important; } diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss index de63c8e9c..cfcbc1b72 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss @@ -1,6 +1,6 @@ .chart-container { width: 100%; - height: 200px; + height: 250px; overflow-x: hidden; overflow-y: hidden; display: block; @@ -8,7 +8,7 @@ } .chart { - height: 200px; + height: 300px; width: max-content; min-width: 100%; } diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts index a34a0270d..f4e74c1b6 100644 --- a/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts @@ -14,20 +14,24 @@ export class ComplianceTimelineComponent implements OnInit { options: any; complianceValue = [ - 'COMPLIANT', + 'NOT_EVALUATED', 'NON_COMPLIANT', + 'COMPLIANT', ]; bgColors = { COMPLIANT: '#28A745', NON_COMPLIANT: '#DC3545', + NOT_EVALUATED: '#6C757D', }; textColors = { COMPLIANT: '#ffffff', NON_COMPLIANT: '#ffffff', + NOT_EVALUATED: '#ffffff', }; lightBgColors = { COMPLIANT: '#E8F5E9', NON_COMPLIANT: '#FAEBED', + NOT_EVALUATED: '#E9E9E9', }; private rawData: any[]; @@ -60,9 +64,9 @@ export class ComplianceTimelineComponent implements OnInit { year: 'numeric', }); this.monthDays.push(dayLabel); - - this.rawData.push([index, 0, entry.status === ComplianceStatusExtendedEnum.COMPLIANT ? 1 : 0]); + this.rawData.push([index, 0, entry.status === ComplianceStatusExtendedEnum.NOT_EVALUATED ? 1 : 0]); this.rawData.push([index, 1, entry.status === ComplianceStatusExtendedEnum.NON_COMPLIANT ? 1 : 0]); + this.rawData.push([index, 2, entry.status === ComplianceStatusExtendedEnum.COMPLIANT ? 1 : 0]); }); } @@ -106,10 +110,10 @@ export class ComplianceTimelineComponent implements OnInit { }, grid: { height: '50%', - top: '15%', + top: '10%', left: '10%', right: '3%', - bottom: '5%', + bottom: '0', width: this.evaluations.length * 30, containLabel: false }, @@ -127,7 +131,8 @@ export class ComplianceTimelineComponent implements OnInit { ), axisLine: { show: false }, axisTick: { show: false }, - axisLabel: { fontSize: 10 } + axisLabel: { fontSize: 10, + formatter: (value: string) => getComplianceStatusLabel(value)} }, series: [ { diff --git a/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts b/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts index eac66b792..53a435071 100644 --- a/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts +++ b/frontend/src/app/compliance/shared/enums/compliance-status.enum.ts @@ -7,7 +7,8 @@ export enum ComplianceStatusExtendedEnum { COMPLIANT = 'COMPLIANT', NON_COMPLIANT = 'NON_COMPLIANT', NOT_EVALUATED = 'NOT_EVALUATED', - NOT_APPLICABLE = 'NOT_APPLICABLE' + NOT_APPLICABLE = 'NOT_APPLICABLE', + ERROR = 'ERROR' } export const ComplianceStatusLabels: Record = { @@ -15,6 +16,7 @@ export const ComplianceStatusLabels: Record Date: Tue, 17 Mar 2026 12:30:47 -0500 Subject: [PATCH 042/135] feat: enhance compliance control evaluation with pagination support --- .../UtmComplianceControlConfigRepository.java | 18 ++++++++++--- .../UtmComplianceControlConfigService.java | 24 +++++++++++++---- ...plianceControlEvaluationLatestService.java | 27 +++++++++++-------- ...lianceControlLatestEvaluationResource.java | 11 +++++--- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java index c9af7b0a2..a5d4f8147 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java @@ -1,6 +1,8 @@ package com.park.utmstack.repository.compliance; import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; @@ -22,11 +24,21 @@ public interface UtmComplianceControlConfigRepository extends JpaRepository findByIdWithQueries(@Param("id") Long id); @Query(""" - SELECT DISTINCT c FROM UtmComplianceControlConfig c + SELECT DISTINCT c + FROM UtmComplianceControlConfig c LEFT JOIN FETCH c.section s LEFT JOIN FETCH c.queriesConfigs q - WHERE c.standardSectionId = :sectionId + WHERE c.id IN :ids """) - List findBySectionIdWithQueries(@Param("sectionId") Long sectionId); + List findWithQueriesByIdIn( + @Param("ids") List ids); + @Query(""" + SELECT c.id + FROM UtmComplianceControlConfig c + WHERE c.standardSectionId = :sectionId + """) + Page findIdsBySectionId( + @Param("sectionId") Long sectionId, + Pageable pageable); } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 66cc7be00..0ca43d005 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -8,6 +8,9 @@ import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; import com.park.utmstack.service.mapper.compliance.UtmComplianceQueryConfigMapper; import com.park.utmstack.web.rest.errors.BadRequestAlertException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -115,11 +118,22 @@ private void validateControlConfig(UtmComplianceControlConfigDto dto) { } } - public List getControlsBySection(Long sectionId) { - var entities = repository.findBySectionIdWithQueries(sectionId); - return entities.stream() - .map(mapper::toDto) - .collect(Collectors.toList()); + public Page findBySection(Long sectionId, Pageable pageable) { + + Page pageIds = repository.findIdsBySectionId(sectionId, pageable); + + if (pageIds.isEmpty()) { + return Page.empty(pageable); + } + + List content = + repository.findWithQueriesByIdIn(pageIds.getContent()); + + return new PageImpl<>( + content, + pageable, + pageIds.getTotalElements() + ); } } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java index 1ca4513ff..faf18cb39 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java @@ -1,35 +1,40 @@ package com.park.utmstack.service.compliance.config; +import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; import com.park.utmstack.service.dto.compliance.UtmComplianceControlLatestEvaluationDto; import com.park.utmstack.service.elasticsearch.ElasticsearchService; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlConfigMapper; import com.park.utmstack.service.mapper.compliance.UtmComplianceControlLatestEvaluationMapper; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.util.List; - @Service public class UtmComplianceControlEvaluationLatestService { private final UtmComplianceControlConfigService configService; private final ElasticsearchService elasticsearchService; + private final UtmComplianceControlConfigMapper controlMapper; public UtmComplianceControlEvaluationLatestService(UtmComplianceControlConfigService configService, - ElasticsearchService elasticsearchService) { + ElasticsearchService elasticsearchService, + UtmComplianceControlConfigMapper controlMapper) { this.configService = configService; this.elasticsearchService = elasticsearchService; + this.controlMapper = controlMapper; } - public List getControlsWithLastEvaluation(Long sectionId) { + public Page getControlsWithLastEvaluation( + Long sectionId, Pageable pageable) { - List controls = configService.getControlsBySection(sectionId); + Page controls = configService.findBySection(sectionId, pageable); - return controls.stream() - .map(control -> { - var lastEval = this.elasticsearchService.getLatestControlEvaluation(control.getId()); - return UtmComplianceControlLatestEvaluationMapper.toDto(control, lastEval); - }) - .toList(); + return controls.map(control -> { + UtmComplianceControlConfigDto controlDto = controlMapper.toDto(control); + var lastEval = elasticsearchService.getLatestControlEvaluation(control.getId()); + return UtmComplianceControlLatestEvaluationMapper.toDto(controlDto, lastEval); + }); } } diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java index 0962b5426..081d8810f 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java @@ -2,6 +2,9 @@ import com.park.utmstack.service.compliance.config.UtmComplianceControlEvaluationLatestService; import com.park.utmstack.service.dto.compliance.UtmComplianceControlLatestEvaluationDto; +import com.park.utmstack.web.rest.util.PaginationUtil; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -19,10 +22,12 @@ public UtmComplianceControlLatestEvaluationResource(UtmComplianceControlEvaluati @GetMapping("/get-by-section") public ResponseEntity> getControlsLatestEvaluationBySection( - @RequestParam Long sectionId) { + @RequestParam Long sectionId, + Pageable pageable) { - var controls = latestEvaluationService.getControlsWithLastEvaluation(sectionId); - return ResponseEntity.ok(controls); + var controls = latestEvaluationService.getControlsWithLastEvaluation(sectionId, pageable); + HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(controls, "/control-config/get-by-section"); + return ResponseEntity.ok().headers(headers).body(controls.getContent()); } } From 467ebdf70e4465b650d340ab74007613b0b617bb Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Wed, 18 Mar 2026 23:20:12 -0500 Subject: [PATCH 043/135] feat: extend control evaluation status with additional states and refine evaluation logic --- .../evaluator/evaluator.go | 74 +++++++++++++++---- .../models/constant.go | 6 +- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/plugins/compliance-orchestrator/evaluator/evaluator.go b/plugins/compliance-orchestrator/evaluator/evaluator.go index d7e68b728..d3968de83 100644 --- a/plugins/compliance-orchestrator/evaluator/evaluator.go +++ b/plugins/compliance-orchestrator/evaluator/evaluator.go @@ -77,7 +77,7 @@ func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) mod } } - const evidenceLimit = 50 + const evidenceLimit = 10 rawRows := res.Rows if len(rawRows) > evidenceLimit { rawRows = rawRows[:evidenceLimit] @@ -140,26 +140,72 @@ func evaluateQueryRule(q models.QueryConfig, hits int) (models.QueryEvaluationSt func computeControlStatus(strategy models.ComplianceStrategy, results []models.QueryEvaluation) models.ControlEvaluationStatus { - switch strategy { - case models.StrategyAll: - for _, r := range results { - if r.Status != models.QueryStatusCompliant { - return models.ControlStatusNonCompliant - } + hasCompliant := false + hasNonCompliant := false + hasError := false + allNotApplicable := true + + applicableCount := 0 + errorCount := 0 + + for _, r := range results { + switch r.Status { + case models.QueryStatusCompliant: + hasCompliant = true + allNotApplicable = false + applicableCount++ + + case models.QueryStatusNonCompliant: + hasNonCompliant = true + allNotApplicable = false + applicableCount++ + + case models.QueryStatusError: + hasError = true + allNotApplicable = false + applicableCount++ + errorCount++ + + case models.QueryStatusNotApplicable: } - return models.ControlStatusCompliant + } + + if allNotApplicable { + return models.ControlStatusNotApplicable + } + if applicableCount > 0 && errorCount == applicableCount { + return models.ControlStatusNotEvaluated + } + + switch strategy { case models.StrategyAny: - for _, r := range results { - if r.Status == models.QueryStatusCompliant { - return models.ControlStatusCompliant - } + if hasCompliant { + return models.ControlStatusCompliant + } + + if hasError { + return models.ControlStatusNonCompliant } - return models.ControlStatusNonCompliant - default: return models.ControlStatusNonCompliant + + case models.StrategyAll: + + if hasNonCompliant { + return models.ControlStatusNonCompliant + } + + if hasError { + return models.ControlStatusNonCompliant + } + + if hasCompliant { + return models.ControlStatusCompliant + } } + + return models.ControlStatusNonCompliant } func patternExists(pattern int, active []models.IndexPattern) bool { diff --git a/plugins/compliance-orchestrator/models/constant.go b/plugins/compliance-orchestrator/models/constant.go index c7ea48aee..6a0eaed5f 100644 --- a/plugins/compliance-orchestrator/models/constant.go +++ b/plugins/compliance-orchestrator/models/constant.go @@ -12,8 +12,10 @@ const ( type ControlEvaluationStatus string const ( - ControlStatusCompliant ControlEvaluationStatus = "COMPLIANT" - ControlStatusNonCompliant ControlEvaluationStatus = "NON_COMPLIANT" + ControlStatusCompliant ControlEvaluationStatus = "COMPLIANT" + ControlStatusNonCompliant ControlEvaluationStatus = "NON_COMPLIANT" + ControlStatusNotApplicable ControlEvaluationStatus = "NOT_APPLICABLE" + ControlStatusNotEvaluated ControlEvaluationStatus = "NOT_EVALUATED" ) type EvaluationRule string From 2d0baf97a7aa775df1241bf83b5733a6a8c909ea Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Thu, 19 Mar 2026 02:02:58 -0500 Subject: [PATCH 044/135] feat: add evaluation rule and rule value to compliance evaluation DTO and service --- .../config/UtmComplianceControlEvaluationHistoryService.java | 1 - .../dto/compliance/UtmComplianceQueryEvaluationDto.java | 1 + .../UtmComplianceControlEvaluationHistoryMapper.java | 5 +++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationHistoryService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationHistoryService.java index 066971433..b032c9469 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationHistoryService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationHistoryService.java @@ -73,7 +73,6 @@ private List enrichQueries( var cfg = configMap.get(queryEval.getQueryConfigId()); if (cfg != null) { queryEval.setQueryDescription(cfg.getQueryDescription()); - queryEval.setEvaluationRule(cfg.getEvaluationRule().name()); queryEval.setIndexPatternId(cfg.getIndexPattern().getId()); queryEval.setIndexPatternName(cfg.getIndexPattern().getPattern()); } diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java index 6e61985a2..8611e8399 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java @@ -14,6 +14,7 @@ public class UtmComplianceQueryEvaluationDto { private String queryName; private String queryDescription; private String evaluationRule; + private Integer ruleValue; private Long indexPatternId; private String indexPatternName; private Integer hits; diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationHistoryMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationHistoryMapper.java index ada707572..70ffa44a2 100644 --- a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationHistoryMapper.java +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationHistoryMapper.java @@ -34,6 +34,11 @@ private static UtmComplianceQueryEvaluationDto mapQueryEval(Map dto.setQueryConfigId(((Number) src.get("queryConfigId")).longValue()); dto.setQueryName((String) src.get("queryName")); + dto.setEvaluationRule((String) src.get("evaluationRule")); + + Object raw = src.get("ruleValue"); + dto.setRuleValue(raw instanceof Number ? ((Number) raw).intValue() : null); + dto.setHits(((Number) src.get("hits")).intValue()); dto.setStatus((String) src.get("status")); dto.setEvidence((List>) src.get("evidence")); From 610228130c3f059e5b0aaa5851aff51a48c172dd Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Thu, 19 Mar 2026 02:03:45 -0500 Subject: [PATCH 045/135] feat: include evaluation rule and rule value in query evaluation model and logic --- .../evaluator/evaluator.go | 40 +++++++++++-------- .../models/query_evaluation.go | 14 ++++--- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/plugins/compliance-orchestrator/evaluator/evaluator.go b/plugins/compliance-orchestrator/evaluator/evaluator.go index d3968de83..fb529462f 100644 --- a/plugins/compliance-orchestrator/evaluator/evaluator.go +++ b/plugins/compliance-orchestrator/evaluator/evaluator.go @@ -35,11 +35,13 @@ func (e *Evaluator) Evaluate(ctx context.Context, cfg models.ControlConfig) (mod if !patternExists(int(q.IndexPatternID), patterns) { reason := "Index pattern not active" qr := models.QueryEvaluation{ - QueryConfigID: q.ID, - QueryName: q.QueryName, - Hits: 0, - Status: models.QueryStatusNotApplicable, - ErrorMessage: &reason, + QueryConfigID: q.ID, + QueryName: q.QueryName, + EvaluationRule: q.EvaluationRule, + RuleValue: q.RuleValue, + Hits: 0, + Status: models.QueryStatusNotApplicable, + ErrorMessage: &reason, } results = append(results, qr) continue @@ -68,12 +70,14 @@ func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) mod if err != nil { msg := fmt.Sprintf("query execution failed: %v", err) return models.QueryEvaluation{ - QueryConfigID: q.ID, - QueryName: q.QueryName, - Hits: 0, - Status: models.QueryStatusError, - ErrorMessage: &msg, - Evidence: nil, + QueryConfigID: q.ID, + QueryName: q.QueryName, + EvaluationRule: q.EvaluationRule, + RuleValue: q.RuleValue, + Hits: 0, + Status: models.QueryStatusError, + ErrorMessage: &msg, + Evidence: nil, } } @@ -95,12 +99,14 @@ func (e *Evaluator) evaluateQuery(ctx context.Context, q models.QueryConfig) mod status, errMsg := evaluateQueryRule(q, res.Count) return models.QueryEvaluation{ - QueryConfigID: q.ID, - QueryName: q.QueryName, - Hits: int64(res.Count), - Status: status, - ErrorMessage: errMsg, - Evidence: evidence, + QueryConfigID: q.ID, + QueryName: q.QueryName, + EvaluationRule: q.EvaluationRule, + RuleValue: q.RuleValue, + Hits: int64(res.Count), + Status: status, + ErrorMessage: errMsg, + Evidence: evidence, } } diff --git a/plugins/compliance-orchestrator/models/query_evaluation.go b/plugins/compliance-orchestrator/models/query_evaluation.go index 02d08539b..f287ab59e 100644 --- a/plugins/compliance-orchestrator/models/query_evaluation.go +++ b/plugins/compliance-orchestrator/models/query_evaluation.go @@ -1,10 +1,12 @@ package models type QueryEvaluation struct { - QueryConfigID int64 `json:"queryConfigId"` - QueryName string `json:"queryName"` - Hits int64 `json:"hits"` - Status QueryEvaluationStatus `json:"status"` - ErrorMessage *string `json:"errorMessage,omitempty"` - Evidence []map[string]any `json:"evidence,omitempty"` + QueryConfigID int64 `json:"queryConfigId"` + QueryName string `json:"queryName"` + EvaluationRule EvaluationRule `json:"evaluationRule"` + RuleValue *int `json:"ruleValue,omitempty"` + Hits int64 `json:"hits"` + Status QueryEvaluationStatus `json:"status"` + ErrorMessage *string `json:"errorMessage,omitempty"` + Evidence []map[string]any `json:"evidence,omitempty"` } From a90403094047e0b226709f5fc97bbd2e6d0bf061 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Mon, 23 Mar 2026 17:31:13 -0500 Subject: [PATCH 046/135] feat: enhance compliance control evaluation with search functionality --- .../com/park/utmstack/config/Constants.java | 2 +- .../UtmComplianceControlConfigRepository.java | 18 +++++++------- .../UtmComplianceControlConfigService.java | 24 +++++++++++-------- ...plianceControlEvaluationLatestService.java | 4 ++-- ...lianceControlLatestEvaluationResource.java | 3 ++- 5 files changed, 29 insertions(+), 22 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/config/Constants.java b/backend/src/main/java/com/park/utmstack/config/Constants.java index 96d7535d0..f4651ee14 100644 --- a/backend/src/main/java/com/park/utmstack/config/Constants.java +++ b/backend/src/main/java/com/park/utmstack/config/Constants.java @@ -164,7 +164,7 @@ public final class Constants { public static final List API_ENDPOINT_IGNORE = Collections.emptyList(); // Application version file - public static final String APP_VERSION_FILE = "/updates/version.json"; + public static final String APP_VERSION_FILE = "/Users/elena/Documents/Work/UTM Stack/version.json"; //TODO: ELENA public static final String ADMIN_EMAIL = "admin@localhost"; diff --git a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java index a5d4f8147..2f9e7b0b6 100644 --- a/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java @@ -3,6 +3,7 @@ import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; @@ -33,12 +34,13 @@ public interface UtmComplianceControlConfigRepository extends JpaRepository findWithQueriesByIdIn( @Param("ids") List ids); - @Query(""" - SELECT c.id - FROM UtmComplianceControlConfig c - WHERE c.standardSectionId = :sectionId - """) - Page findIdsBySectionId( - @Param("sectionId") Long sectionId, - Pageable pageable); + static Specification bySection(Long sectionId) { + return (root, query, cb) -> + cb.equal(root.get("standardSectionId"), sectionId); + } + + static Specification nameContains(String search) { + return (root, query, cb) -> + cb.like(cb.lower(root.get("controlName")), "%" + search.toLowerCase() + "%"); + } } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 0ca43d005..2bafa5f12 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -11,6 +11,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import javax.transaction.Transactional; @@ -118,22 +119,25 @@ private void validateControlConfig(UtmComplianceControlConfigDto dto) { } } - public Page findBySection(Long sectionId, Pageable pageable) { + public Page findBySection(Long sectionId, String search, Pageable pageable) { - Page pageIds = repository.findIdsBySectionId(sectionId, pageable); + Specification spec = Specification.where(UtmComplianceControlConfigRepository.bySection(sectionId)); - if (pageIds.isEmpty()) { + if (search != null && !search.isBlank()) { + spec = spec.and(UtmComplianceControlConfigRepository.nameContains(search)); + } + + Page page = repository.findAll(spec, pageable); + + List ids = page.map(UtmComplianceControlConfig::getId).getContent(); + + if (ids.isEmpty()) { return Page.empty(pageable); } - List content = - repository.findWithQueriesByIdIn(pageIds.getContent()); + List content = repository.findWithQueriesByIdIn(ids); - return new PageImpl<>( - content, - pageable, - pageIds.getTotalElements() - ); + return new PageImpl<>(content, pageable, page.getTotalElements()); } } diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java index faf18cb39..cc6e9c1d8 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java @@ -26,9 +26,9 @@ public UtmComplianceControlEvaluationLatestService(UtmComplianceControlConfigSer } public Page getControlsWithLastEvaluation( - Long sectionId, Pageable pageable) { + Long sectionId, String search, Pageable pageable) { - Page controls = configService.findBySection(sectionId, pageable); + Page controls = configService.findBySection(sectionId, search, pageable); return controls.map(control -> { UtmComplianceControlConfigDto controlDto = controlMapper.toDto(control); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java index 081d8810f..cd6c119b7 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java @@ -23,9 +23,10 @@ public UtmComplianceControlLatestEvaluationResource(UtmComplianceControlEvaluati @GetMapping("/get-by-section") public ResponseEntity> getControlsLatestEvaluationBySection( @RequestParam Long sectionId, + @RequestParam(required = false) String search, Pageable pageable) { - var controls = latestEvaluationService.getControlsWithLastEvaluation(sectionId, pageable); + var controls = latestEvaluationService.getControlsWithLastEvaluation(sectionId, search, pageable); HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(controls, "/control-config/get-by-section"); return ResponseEntity.ok().headers(headers).body(controls.getContent()); } From 01e597a2f9ab200c1d55b38f069c21463283631a Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Mon, 23 Mar 2026 17:32:21 -0500 Subject: [PATCH 047/135] feat: update application version file path for consistency --- backend/src/main/java/com/park/utmstack/config/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/main/java/com/park/utmstack/config/Constants.java b/backend/src/main/java/com/park/utmstack/config/Constants.java index f4651ee14..96d7535d0 100644 --- a/backend/src/main/java/com/park/utmstack/config/Constants.java +++ b/backend/src/main/java/com/park/utmstack/config/Constants.java @@ -164,7 +164,7 @@ public final class Constants { public static final List API_ENDPOINT_IGNORE = Collections.emptyList(); // Application version file - public static final String APP_VERSION_FILE = "/Users/elena/Documents/Work/UTM Stack/version.json"; //TODO: ELENA + public static final String APP_VERSION_FILE = "/updates/version.json"; public static final String ADMIN_EMAIL = "admin@localhost"; From 8ecf6b4cf98a39028b8669ebe8d2d76d3521e627 Mon Sep 17 00:00:00 2001 From: Elena Lopez Milan Date: Mon, 23 Mar 2026 23:28:03 -0500 Subject: [PATCH 048/135] fix: implement sorting logic for compliance evaluations --- .../config/UtmComplianceControlConfigService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java index 2bafa5f12..41d073a20 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -137,7 +137,14 @@ public Page findBySection(Long sectionId, String sea List content = repository.findWithQueriesByIdIn(ids); - return new PageImpl<>(content, pageable, page.getTotalElements()); + if (content.isEmpty()) { + return Page.empty(pageable); + } + + Map map = content.stream().collect(Collectors.toMap(UtmComplianceControlConfig::getId, c -> c)); + List ordered = ids.stream().map(map::get).collect(Collectors.toList()); + + return new PageImpl<>(ordered, pageable, page.getTotalElements()); } } From 88d0d7d78a37634771c51dd5064178d4cdb38457 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Fri, 27 Mar 2026 11:04:56 -0400 Subject: [PATCH 049/135] feat(agent): add native auditd collector for Linux - Implement native auditd collector using go-libaudit v2 with netlink multicast - Add enterprise-ready auditd configuration (50-utmstack.rules) - Respect existing customer audit rules (additive approach) - Add cleanup on agent uninstall (removes UTMStack rules only) - Support automatic auditd installation on Debian/Ubuntu/RHEL/Fedora - Handle migration path for existing auditd installations - Add distro detection for package manager selection - Remove legacy beats/filebeat commented code --- agent/cmd/uninstall.go | 9 + agent/collector/auditd/auditd.go | 23 ++ agent/collector/auditd/auditd_linux.go | 193 ++++++++++ agent/collector/auditd/auditd_other.go | 32 ++ agent/collector/auditd/capabilities.go | 40 ++ agent/collector/auditd/client.go | 38 ++ agent/collector/auditd/parser.go | 180 +++++++++ agent/collector/auditd/stream.go | 54 +++ agent/collector/platform/linux_amd64.go | 3 +- agent/collector/platform/linux_arm64.go | 2 + agent/collector/platform/windows_amd64.go | 1 - agent/dependency/auditd_linux.go | 437 ++++++++++++++++++++++ agent/dependency/auditd_other.go | 18 + agent/dependency/dependency.go | 83 ++-- agent/dependency/deps_linux_amd64.go | 45 +-- agent/dependency/deps_linux_arm64.go | 12 + agent/dependency/deps_windows_amd64.go | 27 -- agent/dependency/distro_linux.go | 142 +++++++ agent/go.mod | 3 +- agent/go.sum | 6 + agent/updater/go.mod | 13 +- agent/updater/go.sum | 17 +- 22 files changed, 1267 insertions(+), 111 deletions(-) create mode 100644 agent/collector/auditd/auditd.go create mode 100644 agent/collector/auditd/auditd_linux.go create mode 100644 agent/collector/auditd/auditd_other.go create mode 100644 agent/collector/auditd/capabilities.go create mode 100644 agent/collector/auditd/client.go create mode 100644 agent/collector/auditd/parser.go create mode 100644 agent/collector/auditd/stream.go create mode 100644 agent/dependency/auditd_linux.go create mode 100644 agent/dependency/auditd_other.go create mode 100644 agent/dependency/distro_linux.go diff --git a/agent/cmd/uninstall.go b/agent/cmd/uninstall.go index 996ad0f49..b388be0e7 100644 --- a/agent/cmd/uninstall.go +++ b/agent/cmd/uninstall.go @@ -47,6 +47,15 @@ var uninstallCmd = &cobra.Command{ if err = pb.DeleteAgent(cnf); err != nil { utils.Logger.ErrorF("error deleting agent: %v", err) } + + // Uninstall dependencies (cleanup auditd rules, etc.) + fmt.Print("Cleaning up dependencies... ") + if err = dependency.UninstallAll(); err != nil { + fmt.Printf("Warning: %v\n", err) + } else { + fmt.Println("[OK]") + } + if err = collector.UninstallAll(); err != nil { fmt.Printf("error uninstalling collectors: %v\n", err) os.Exit(1) diff --git a/agent/collector/auditd/auditd.go b/agent/collector/auditd/auditd.go new file mode 100644 index 000000000..18b32e2d7 --- /dev/null +++ b/agent/collector/auditd/auditd.go @@ -0,0 +1,23 @@ +// Package auditd provides a native collector for Linux Audit Framework events. +// It uses go-libaudit to receive events via netlink multicast and reassembles +// them before sending to the log queue. +package auditd + +import "time" + +const ( + // auditdRestartDelay is the initial delay between reconnection attempts + auditdRestartDelay = 5 * time.Second + + // auditdMaxRestartDelay is the maximum backoff delay for reconnection + auditdMaxRestartDelay = 5 * time.Minute + + // reassemblerMaxInFlight is the maximum number of events held for reassembly + reassemblerMaxInFlight = 50 + + // reassemblerTimeout is how long to wait for related messages before flushing + reassemblerTimeout = 2 * time.Second + + // maintainInterval is how often to run Reassembler.Maintain() to flush stale events + maintainInterval = 500 * time.Millisecond +) diff --git a/agent/collector/auditd/auditd_linux.go b/agent/collector/auditd/auditd_linux.go new file mode 100644 index 000000000..b34168fb6 --- /dev/null +++ b/agent/collector/auditd/auditd_linux.go @@ -0,0 +1,193 @@ +//go:build linux +// +build linux + +package auditd + +import ( + "context" + "os" + "sync" + "time" + + libaudit "github.com/elastic/go-libaudit/v2" + "github.com/elastic/go-libaudit/v2/auparse" + "github.com/threatwinds/go-sdk/plugins" + "github.com/utmstack/UTMStack/agent/utils" +) + +// AuditdCollector collects Linux Audit events via netlink multicast +type AuditdCollector struct { + client auditReceiver + reassembler *libaudit.Reassembler + cancel context.CancelFunc + mu sync.Mutex +} + +// New creates a new AuditdCollector +func New() *AuditdCollector { + return &AuditdCollector{} +} + +// Name returns the collector name +func (a *AuditdCollector) Name() string { + return "auditd" +} + +// Start begins collecting audit events and sending them to the queue +func (a *AuditdCollector) Start(ctx context.Context, queue chan *plugins.Log) { + // Preflight check for audit capability + if err := checkAuditCapability(); err != nil { + utils.Logger.ErrorF("auditd: preflight check failed: %v", err) + return + } + + host, err := os.Hostname() + if err != nil { + utils.Logger.ErrorF("auditd: error getting hostname: %v", err) + host = "unknown" + } + + restartDelay := auditdRestartDelay + + for { + select { + case <-ctx.Done(): + utils.Logger.Info("auditd collector stopping due to context cancellation") + return + default: + } + + exitCode := a.runAuditClient(ctx, host, queue) + + if exitCode == 0 { + utils.Logger.Info("auditd client exited normally") + } else { + utils.Logger.ErrorF("auditd client exited with code %d, restarting in %v", exitCode, restartDelay) + } + + select { + case <-ctx.Done(): + return + case <-time.After(restartDelay): + } + + // Exponential backoff + restartDelay *= 2 + if restartDelay > auditdMaxRestartDelay { + restartDelay = auditdMaxRestartDelay + } + } +} + +// runAuditClient creates the audit client and runs the receive loop +func (a *AuditdCollector) runAuditClient(ctx context.Context, host string, queue chan *plugins.Log) int { + a.mu.Lock() + clientCtx, cancel := context.WithCancel(ctx) + a.cancel = cancel + + // Create multicast audit client + client, err := newAuditClient() + if err != nil { + a.mu.Unlock() + utils.Logger.ErrorF("auditd: error creating audit client: %v", err) + return -1 + } + a.client = client + + // Create event stream for reassembled events + stream := newEventStream(queue, host) + + // Create reassembler + reassembler, err := libaudit.NewReassembler(reassemblerMaxInFlight, reassemblerTimeout, stream) + if err != nil { + client.Close() + a.mu.Unlock() + utils.Logger.ErrorF("auditd: error creating reassembler: %v", err) + return -1 + } + a.reassembler = reassembler + a.mu.Unlock() + + utils.Logger.Info("auditd collector started (netlink multicast)") + + // Start maintenance goroutine for reassembler + go a.runMaintenance(clientCtx) + + // Main receive loop + for { + select { + case <-clientCtx.Done(): + a.cleanup() + return 0 + default: + } + + // Receive with non-blocking to allow checking context + msg, err := client.Receive(false) + if err != nil { + utils.Logger.ErrorF("auditd: error receiving message: %v", err) + a.cleanup() + return -1 + } + + if msg == nil { + // No message available, brief sleep to avoid busy loop + time.Sleep(10 * time.Millisecond) + continue + } + + // Parse message type from raw data + msgType := auparse.AuditMessageType(msg.Type) + + // Push to reassembler for event grouping + if err := reassembler.Push(msgType, msg.Data); err != nil { + utils.Logger.ErrorF("auditd: error pushing to reassembler: %v", err) + } + } +} + +// runMaintenance periodically calls Maintain() to flush stale events +func (a *AuditdCollector) runMaintenance(ctx context.Context) { + ticker := time.NewTicker(maintainInterval) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + a.mu.Lock() + if a.reassembler != nil { + if err := a.reassembler.Maintain(); err != nil { + utils.Logger.ErrorF("auditd: error in reassembler maintenance: %v", err) + } + } + a.mu.Unlock() + } + } +} + +// cleanup closes the client and reassembler +func (a *AuditdCollector) cleanup() { + a.mu.Lock() + defer a.mu.Unlock() + + if a.reassembler != nil { + a.reassembler.Close() + a.reassembler = nil + } + if a.client != nil { + a.client.Close() + a.client = nil + } +} + +// Stop stops the collector +func (a *AuditdCollector) Stop() { + a.mu.Lock() + defer a.mu.Unlock() + + if a.cancel != nil { + a.cancel() + } +} diff --git a/agent/collector/auditd/auditd_other.go b/agent/collector/auditd/auditd_other.go new file mode 100644 index 000000000..91ab06dcc --- /dev/null +++ b/agent/collector/auditd/auditd_other.go @@ -0,0 +1,32 @@ +//go:build !linux +// +build !linux + +package auditd + +import ( + "context" + + "github.com/threatwinds/go-sdk/plugins" + "github.com/utmstack/UTMStack/agent/utils" +) + +// AuditdCollector is a no-op stub for non-Linux platforms +type AuditdCollector struct{} + +// New creates a new AuditdCollector (no-op on non-Linux) +func New() *AuditdCollector { + return &AuditdCollector{} +} + +// Name returns the collector name +func (a *AuditdCollector) Name() string { + return "auditd" +} + +// Start is a no-op on non-Linux platforms +func (a *AuditdCollector) Start(ctx context.Context, queue chan *plugins.Log) { + utils.Logger.Info("auditd collector not supported on this platform, skipping") +} + +// Stop is a no-op on non-Linux platforms +func (a *AuditdCollector) Stop() {} diff --git a/agent/collector/auditd/capabilities.go b/agent/collector/auditd/capabilities.go new file mode 100644 index 000000000..928a9e7c7 --- /dev/null +++ b/agent/collector/auditd/capabilities.go @@ -0,0 +1,40 @@ +//go:build linux +// +build linux + +package auditd + +import ( + "os/exec" + "strings" + + "github.com/utmstack/UTMStack/agent/utils" +) + +// checkAuditCapability checks if the audit system is available and enabled. +// Uses auditctl -s to verify audit status since /proc/sys/kernel/auditing +// doesn't exist on all kernel versions. +func checkAuditCapability() error { + // Check if auditctl exists + auditctlPath, err := exec.LookPath("auditctl") + if err != nil { + utils.Logger.ErrorF("auditd: auditctl not found in PATH: %v", err) + return err + } + + // Run auditctl -s to check audit status + cmd := exec.Command(auditctlPath, "-s") + output, err := cmd.Output() + if err != nil { + utils.Logger.ErrorF("auditd: failed to run auditctl -s: %v", err) + return err + } + + // Check if enabled=1 in output + if !strings.Contains(string(output), "enabled 1") && !strings.Contains(string(output), "enabled=1") { + utils.Logger.Info("auditd: kernel auditing is disabled (enabled != 1), collector will not start") + return nil + } + + utils.Logger.Info("auditd: audit system is enabled and ready") + return nil +} diff --git a/agent/collector/auditd/client.go b/agent/collector/auditd/client.go new file mode 100644 index 000000000..af2843991 --- /dev/null +++ b/agent/collector/auditd/client.go @@ -0,0 +1,38 @@ +//go:build linux +// +build linux + +package auditd + +import ( + libaudit "github.com/elastic/go-libaudit/v2" +) + +// auditReceiver interface wraps the go-libaudit client for testability +type auditReceiver interface { + Receive(nonBlocking bool) (*libaudit.RawAuditMessage, error) + Close() error +} + +// auditClientWrapper wraps the go-libaudit AuditClient to implement auditReceiver +type auditClientWrapper struct { + client *libaudit.AuditClient +} + +// Receive receives a raw audit message from the netlink socket +func (w *auditClientWrapper) Receive(nonBlocking bool) (*libaudit.RawAuditMessage, error) { + return w.client.Receive(nonBlocking) +} + +// Close closes the underlying audit client +func (w *auditClientWrapper) Close() error { + return w.client.Close() +} + +// newAuditClient creates a new multicast audit client wrapped in the auditReceiver interface +func newAuditClient() (auditReceiver, error) { + client, err := libaudit.NewMulticastAuditClient(nil) + if err != nil { + return nil, err + } + return &auditClientWrapper{client: client}, nil +} diff --git a/agent/collector/auditd/parser.go b/agent/collector/auditd/parser.go new file mode 100644 index 000000000..ed6c0128e --- /dev/null +++ b/agent/collector/auditd/parser.go @@ -0,0 +1,180 @@ +//go:build linux +// +build linux + +package auditd + +import ( + "encoding/json" + "strings" + "time" + + "github.com/elastic/go-libaudit/v2/auparse" +) + +// formatAuditEvent converts reassembled audit messages to a FLAT JSON format. +// This ensures ZERO DATA LOSS - every field from every record appears in output. +// +// Flattening rules: +// - SYSCALL: all fields merged directly to root +// - CWD: extracts "cwd" field to root +// - PROCTITLE: extracts "proctitle" field to root +// - EXECVE: all fields in "execve" object (avoids a0-aN collision with SYSCALL) +// - PATH: all records collected in "paths" array +// - SOCKADDR: all fields in "sockaddr" object +// - Any other record type: all fields in "{lowercase_type}" object (fallback) +func formatAuditEvent(msgs []*auparse.AuditMessage) (string, error) { + if len(msgs) == 0 { + return "", nil + } + + // Get timestamp and sequence from first message + firstMsg := msgs[0] + + // Initialize the flat event structure using map for flexibility + event := make(map[string]interface{}) + event["@timestamp"] = firstMsg.Timestamp.Format(time.RFC3339Nano) + event["type"] = "auditd" + event["sequence"] = firstMsg.Sequence + + // Determine category (SYSCALL takes priority, otherwise first record type) + var category string + + // Collect PATH records for the "paths" array + var paths []map[string]interface{} + + // Process each message according to flattening rules + for _, msg := range msgs { + recordType := msg.RecordType + recordTypeName := recordType.String() + + // Set category: SYSCALL takes priority, otherwise use first record type + if category == "" { + category = recordTypeName + } + if recordType == auparse.AUDIT_SYSCALL { + category = "SYSCALL" + } + + // Extract data from message - ZERO DATA LOSS requirement + data, err := msg.Data() + if err != nil { + // Even on error, try to continue with empty data + data = make(map[string]string) + } + + // Apply flattening rules based on record type + switch recordType { + case auparse.AUDIT_SYSCALL: + // SYSCALL: merge ALL fields directly to root + mergeSyscallToRoot(event, data) + + case auparse.AUDIT_CWD: + // CWD: extract "cwd" field to root + if cwd, ok := data["cwd"]; ok { + event["cwd"] = cwd + } + // Also include any other fields from CWD record (ZERO DATA LOSS) + for k, v := range data { + if k != "cwd" { + // Prefix with "cwd_" to avoid collisions + event["cwd_"+k] = v + } + } + + case auparse.AUDIT_PROCTITLE: + // PROCTITLE: extract "proctitle" field to root + if proctitle, ok := data["proctitle"]; ok { + event["proctitle"] = proctitle + } + // Also include any other fields (ZERO DATA LOSS) + for k, v := range data { + if k != "proctitle" { + event["proctitle_"+k] = v + } + } + + case auparse.AUDIT_EXECVE: + // EXECVE: all fields go into "execve" object to avoid a0-aN collision + execveObj := make(map[string]interface{}) + for k, v := range data { + execveObj[k] = v + } + event["execve"] = execveObj + + case auparse.AUDIT_PATH: + // PATH: collect all records into "paths" array + pathRecord := make(map[string]interface{}) + for k, v := range data { + pathRecord[k] = v + } + paths = append(paths, pathRecord) + + case auparse.AUDIT_SOCKADDR: + // SOCKADDR: all fields in "sockaddr" object + sockaddrObj := make(map[string]interface{}) + for k, v := range data { + sockaddrObj[k] = v + } + event["sockaddr"] = sockaddrObj + + default: + // FALLBACK: any other record type goes into "{lowercase_type}" object + // This ensures ZERO DATA LOSS for unknown/future record types + fallbackKey := strings.ToLower(recordTypeName) + // Handle special characters in record type names + fallbackKey = strings.ReplaceAll(fallbackKey, "_", "") + + // Check if we already have this type (could be multiple records of same type) + if existing, ok := event[fallbackKey]; ok { + // Already exists - convert to array if not already + switch v := existing.(type) { + case []map[string]interface{}: + // Already an array, append + record := make(map[string]interface{}) + for k, val := range data { + record[k] = val + } + event[fallbackKey] = append(v, record) + case map[string]interface{}: + // Convert to array + record := make(map[string]interface{}) + for k, val := range data { + record[k] = val + } + event[fallbackKey] = []map[string]interface{}{v, record} + } + } else { + // First occurrence - create object + fallbackObj := make(map[string]interface{}) + for k, v := range data { + fallbackObj[k] = v + } + event[fallbackKey] = fallbackObj + } + } + } + + // Add category to event + event["category"] = category + + // Add paths array if we collected any PATH records + if len(paths) > 0 { + event["paths"] = paths + } + + // Marshal to JSON - deterministic output with sorted keys + jsonBytes, err := json.Marshal(event) + if err != nil { + return "", err + } + + return string(jsonBytes), nil +} + +// mergeSyscallToRoot merges all SYSCALL fields directly to the event root. +// This is the primary record type and its fields become top-level. +func mergeSyscallToRoot(event map[string]interface{}, data map[string]string) { + for k, v := range data { + event[k] = v + } +} diff --git a/agent/collector/auditd/stream.go b/agent/collector/auditd/stream.go new file mode 100644 index 000000000..21a3b8203 --- /dev/null +++ b/agent/collector/auditd/stream.go @@ -0,0 +1,54 @@ +//go:build linux +// +build linux + +package auditd + +import ( + "github.com/elastic/go-libaudit/v2/auparse" + "github.com/threatwinds/go-sdk/plugins" + "github.com/utmstack/UTMStack/agent/config" + "github.com/utmstack/UTMStack/agent/utils" +) + +// eventStream implements libaudit.Stream interface for reassembled events +type eventStream struct { + queue chan *plugins.Log + hostname string +} + +// newEventStream creates a new eventStream +func newEventStream(queue chan *plugins.Log, hostname string) *eventStream { + return &eventStream{ + queue: queue, + hostname: hostname, + } +} + +// ReassemblyComplete is called when a complete group of events has been received +func (s *eventStream) ReassemblyComplete(msgs []*auparse.AuditMessage) { + if len(msgs) == 0 { + return + } + + jsonOutput, err := formatAuditEvent(msgs) + if err != nil { + utils.Logger.ErrorF("auditd: error formatting event: %v", err) + return + } + + s.queue <- &plugins.Log{ + DataType: string(config.DataTypeLinuxAgent), + DataSource: s.hostname, + Raw: jsonOutput, + } +} + +// EventsLost is called when events were lost due to buffer overflow or rate limiting +func (s *eventStream) EventsLost(count int) { + // Ignore invalid counts - large values indicate sequence number rollover/overflow + // not actual lost events. A reasonable max is 100K events lost in one batch. + if count <= 0 || count > 100000 { + return + } + utils.Logger.ErrorF("auditd: %d events lost due to buffer overflow or rate limiting", count) +} diff --git a/agent/collector/platform/linux_amd64.go b/agent/collector/platform/linux_amd64.go index 673319dce..5baf1b070 100644 --- a/agent/collector/platform/linux_amd64.go +++ b/agent/collector/platform/linux_amd64.go @@ -13,6 +13,7 @@ import ( "github.com/threatwinds/go-sdk/entities" "github.com/threatwinds/go-sdk/plugins" + "github.com/utmstack/UTMStack/agent/collector/auditd" "github.com/utmstack/UTMStack/agent/config" "github.com/utmstack/UTMStack/agent/utils" ) @@ -157,6 +158,6 @@ func (l *LinuxSystem) Stop() { func GetCollectors() []Collector { return []Collector{ &LinuxSystem{}, - // Filebeat{}, // TODO: remove after testing native collector + auditd.New(), } } diff --git a/agent/collector/platform/linux_arm64.go b/agent/collector/platform/linux_arm64.go index 1d8e43926..0d5d47784 100644 --- a/agent/collector/platform/linux_arm64.go +++ b/agent/collector/platform/linux_arm64.go @@ -13,6 +13,7 @@ import ( "github.com/threatwinds/go-sdk/entities" "github.com/threatwinds/go-sdk/plugins" + "github.com/utmstack/UTMStack/agent/collector/auditd" "github.com/utmstack/UTMStack/agent/config" "github.com/utmstack/UTMStack/agent/utils" ) @@ -157,5 +158,6 @@ func (l *LinuxSystemArm64) Stop() { func GetCollectors() []Collector { return []Collector{ &LinuxSystemArm64{}, + auditd.New(), } } diff --git a/agent/collector/platform/windows_amd64.go b/agent/collector/platform/windows_amd64.go index 5d3a9b61c..0a356788a 100644 --- a/agent/collector/platform/windows_amd64.go +++ b/agent/collector/platform/windows_amd64.go @@ -247,7 +247,6 @@ var windowsCollector = &Windows{ func GetCollectors() []Collector { return []Collector{ windowsCollector, - // Filebeat{}, // TODO: remove after testing native collector } } diff --git a/agent/dependency/auditd_linux.go b/agent/dependency/auditd_linux.go new file mode 100644 index 000000000..13b33d13c --- /dev/null +++ b/agent/dependency/auditd_linux.go @@ -0,0 +1,437 @@ +//go:build linux +// +build linux + +package dependency + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/utmstack/UTMStack/agent/utils" + sharedExec "github.com/utmstack/UTMStack/shared/exec" + "github.com/utmstack/UTMStack/shared/fs" +) + +// AuditdVersion is the UTMStack audit rules version. +// Bump this when audit rules are updated to trigger rule redeployment. +const AuditdVersion = "1.0.0" + +// auditRulesContent contains the UTMStack security audit rules. +// These rules are deployed to /etc/audit/rules.d/50-utmstack.rules +// NOTE: This is an ADDITIVE configuration - does not delete existing rules +// or modify global settings (-D, -b, -f) to coexist with enterprise policies. +const auditRulesContent = `## UTMStack SIEM Audit Rules +## Managed by UTMStack Agent - Do not edit manually +## Additive rules - does not delete existing configuration + +# Monitor executed commands (critical for SIEM) +-a always,exit -F arch=b64 -S execve -k utmstack_exec +-a always,exit -F arch=b32 -S execve -k utmstack_exec + +# Privilege escalation +-a always,exit -F arch=b64 -S setuid,setgid,setreuid,setregid,setresuid,setresgid -F auid>=1000 -k utmstack_priv +-a always,exit -F arch=b32 -S setuid,setgid,setreuid,setregid,setresuid,setresgid -F auid>=1000 -k utmstack_priv + +# Sensitive file access +-w /etc/shadow -p wa -k utmstack_sensitive +-w /etc/passwd -p wa -k utmstack_sensitive +-w /etc/sudoers -p wa -k utmstack_sensitive +-w /etc/sudoers.d -p wa -k utmstack_sensitive +-w /etc/ssh/sshd_config -p wa -k utmstack_sensitive +-w /root/.ssh -p wa -k utmstack_sensitive + +# Module loading +-a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k utmstack_modules +-a always,exit -F arch=b32 -S init_module,finit_module,delete_module -k utmstack_modules + +# Network connections (may be high volume - consider enabling selectively) +# -a always,exit -F arch=b64 -S connect -F auid>=1000 -k utmstack_network + +# Time changes +-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k utmstack_time +-a always,exit -F arch=b32 -S adjtimex,settimeofday,clock_settime -k utmstack_time + +# Audit configuration changes +-w /etc/audit -p wa -k utmstack_audit_config +-w /etc/audisp -p wa -k utmstack_audit_config +` + +const ( + auditRulesPath = "/etc/audit/rules.d/50-utmstack.rules" +) + +// configureAuditd is called by dependency.Reconcile on first install. +// It orchestrates the full auditd setup: root check → container check → distro detect → install → rules → service +func configureAuditd() error { + // Check if running as root + if !isRoot() { + utils.Logger.Info("auditd setup skipped: root privileges required") + return nil + } + + // Check if running in a container + if isContainer() { + utils.Logger.Info("auditd setup skipped: container environment detected") + return nil + } + + // Detect distribution + distro := DetectDistro() + if distro.PackageManager == "" { + utils.Logger.Info("auditd setup skipped: unknown distribution, no package manager detected") + return nil + } + + utils.Logger.Info("Detected distro: ID=%s, IDLike=%s, PackageManager=%s", distro.ID, distro.IDLike, distro.PackageManager) + + // Install auditd if not already installed + if !isAuditdInstalled() { + utils.Logger.Info("Installing auditd package...") + if err := installAuditd(distro); err != nil { + utils.Logger.ErrorF("Failed to install auditd: %v", err) + return nil // Non-critical, don't fail the agent + } + utils.Logger.Info("auditd package installed successfully") + } else { + utils.Logger.Info("auditd is already installed") + } + + // Pre-flight check: can we modify audit configuration? + if canConfigure, reason := canConfigureAuditd(); !canConfigure { + utils.Logger.Info("auditd rule deployment skipped: %s", reason) + return nil // Non-critical, don't fail the agent + } + + // Deploy audit rules + utils.Logger.Info("Deploying UTMStack audit rules...") + if err := deployRules(); err != nil { + utils.Logger.ErrorF("Failed to deploy audit rules: %v", err) + return nil // Non-critical, don't fail the agent + } + utils.Logger.Info("UTMStack audit rules deployed successfully") + + // Start and enable auditd service + utils.Logger.Info("Starting auditd service...") + if err := startAuditd(); err != nil { + utils.Logger.ErrorF("Failed to start auditd service: %v", err) + return nil // Non-critical, don't fail the agent + } + utils.Logger.Info("auditd service started and enabled") + + // Reload rules + utils.Logger.Info("Reloading audit rules...") + if err := reloadRules(); err != nil { + utils.Logger.ErrorF("Failed to reload audit rules: %v", err) + return nil // Non-critical, don't fail the agent + } + utils.Logger.Info("Audit rules reloaded successfully") + + return nil +} + +// updateAuditdRules is called when AuditdVersion changes. +// It redeploys rules without reinstalling the package. +func updateAuditdRules() error { + // Check if running as root + if !isRoot() { + utils.Logger.Info("auditd rule update skipped: root privileges required") + return nil + } + + // Check if running in a container + if isContainer() { + utils.Logger.Info("auditd rule update skipped: container environment detected") + return nil + } + + // Pre-flight check: can we modify audit configuration? + if canConfigure, reason := canConfigureAuditd(); !canConfigure { + utils.Logger.Info("auditd rule update skipped: %s", reason) + return nil // Non-critical, don't fail the agent + } + + // Deploy updated rules + utils.Logger.Info("Updating UTMStack audit rules...") + if err := deployRules(); err != nil { + utils.Logger.ErrorF("Failed to deploy audit rules: %v", err) + return nil + } + + // Reload rules + if err := reloadRules(); err != nil { + utils.Logger.ErrorF("Failed to reload audit rules: %v", err) + return nil + } + + utils.Logger.Info("UTMStack audit rules updated successfully") + return nil +} + +// isRoot checks if the current process is running as root. +func isRoot() bool { + return os.Geteuid() == 0 +} + +// isContainer checks if the process is running inside a container. +// Checks for Docker, Podman, LXC, and other container runtimes. +func isContainer() bool { + // Check for Docker/Podman environment files + containerFiles := []string{ + "/.dockerenv", + "/run/.containerenv", + } + for _, f := range containerFiles { + if fs.Exists(f) { + return true + } + } + + // Check cgroup for container patterns + cgroupPath := "/proc/1/cgroup" + if content, err := os.ReadFile(cgroupPath); err == nil { + cgroupStr := string(content) + containerPatterns := []string{"docker", "kubepods", "lxc", "containerd"} + for _, pattern := range containerPatterns { + if strings.Contains(cgroupStr, pattern) { + return true + } + } + } + + return false +} + +// canConfigureAuditd performs pre-flight checks to determine if audit rules can be modified. +// Returns (true, "") if configuration is possible, (false, "reason") if not. +// This checks for: +// - Immutable mode (-e 2): audit config is locked until reboot +// - never,task rule: auditing is disabled system-wide +func canConfigureAuditd() (bool, string) { + // Check if auditctl is available + auditctlPath, err := exec.LookPath("auditctl") + if err != nil { + // auditctl not found - this is OK, we'll install auditd first + return true, "" + } + + // Check for immutable mode (-e 2) + // auditctl -s returns status including "enabled X" where X is 0, 1, or 2 + statusCmd := exec.Command(auditctlPath, "-s") + statusOutput, err := statusCmd.Output() + if err == nil { + statusStr := string(statusOutput) + if strings.Contains(statusStr, "enabled 2") { + return false, "audit config is locked (immutable mode -e 2), reboot required to modify" + } + } + + // Check for never,task rule (auditing disabled) + // auditctl -l lists all loaded rules + rulesCmd := exec.Command(auditctlPath, "-l") + rulesOutput, err := rulesCmd.Output() + if err == nil { + rulesStr := string(rulesOutput) + if strings.Contains(rulesStr, "never,task") { + return false, "auditing is disabled by never,task rule" + } + } + + return true, "" +} + +// isAuditdInstalled checks if auditd tools are installed. +func isAuditdInstalled() bool { + // Check common paths for auditctl + paths := []string{ + "/sbin/auditctl", + "/usr/sbin/auditctl", + "/usr/bin/auditctl", + } + for _, p := range paths { + if fs.Exists(p) { + return true + } + } + + // Also try exec.LookPath as fallback + if _, err := exec.LookPath("auditctl"); err == nil { + return true + } + + return false +} + +// isAuditdRunning checks if the auditd service is currently running. +func isAuditdRunning() bool { + // Try systemctl first + if _, err := exec.LookPath("systemctl"); err == nil { + cmd := exec.Command("systemctl", "is-active", "--quiet", "auditd") + if err := cmd.Run(); err == nil { + return true + } + } + + // Fallback: check if auditd process exists + if content, err := os.ReadFile("/proc/1/comm"); err == nil { + if strings.TrimSpace(string(content)) == "auditd" { + return true + } + } + + // Check /var/run/auditd.pid + if fs.Exists("/var/run/auditd.pid") { + return true + } + + return false +} + +// installAuditd installs the auditd package using the appropriate package manager. +func installAuditd(distro *DistroInfo) error { + var cmd *exec.Cmd + + switch distro.PackageManager { + case "apt": + // Debian/Ubuntu: auditd + audispd-plugins + cmd = exec.Command("apt-get", "install", "-y", "auditd", "audispd-plugins") + // Set DEBIAN_FRONTEND to avoid prompts + cmd.Env = append(os.Environ(), "DEBIAN_FRONTEND=noninteractive") + + case "dnf": + // Fedora, RHEL 8+, Rocky, Alma + cmd = exec.Command("dnf", "install", "-y", "audit") + + case "yum": + // RHEL 7, CentOS 7, Amazon Linux + cmd = exec.Command("yum", "install", "-y", "audit") + + case "zypper": + // SUSE, openSUSE + cmd = exec.Command("zypper", "install", "-y", "audit") + + case "pacman": + // Arch, Manjaro + cmd = exec.Command("pacman", "-S", "--noconfirm", "audit") + + default: + return fmt.Errorf("unsupported package manager: %s", distro.PackageManager) + } + + output, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("package installation failed: %v, output: %s", err, string(output)) + } + + return nil +} + +// startAuditd enables and starts the auditd service. +func startAuditd() error { + // Try systemctl first (most common on modern systems) + if _, err := exec.LookPath("systemctl"); err == nil { + // Enable the service + if err := sharedExec.Run("systemctl", "/", "enable", "auditd"); err != nil { + utils.Logger.LogF(400, "Failed to enable auditd service: %v", err) + // Continue anyway, try to start + } + + // Start the service + if err := sharedExec.Run("systemctl", "/", "start", "auditd"); err != nil { + // auditd might already be running, which is fine + if !isAuditdRunning() { + return fmt.Errorf("failed to start auditd service: %v", err) + } + } + return nil + } + + // Fallback to service command + if _, err := exec.LookPath("service"); err == nil { + if err := sharedExec.Run("service", "/", "auditd", "start"); err != nil { + if !isAuditdRunning() { + return fmt.Errorf("failed to start auditd service: %v", err) + } + } + return nil + } + + return fmt.Errorf("no service manager found (systemctl or service)") +} + +// deployRules writes the UTMStack audit rules to the rules.d directory. +func deployRules() error { + // Ensure the rules.d directory exists + rulesDir := filepath.Dir(auditRulesPath) + if err := fs.CreateDirIfNotExist(rulesDir); err != nil { + return fmt.Errorf("failed to create rules directory: %v", err) + } + + // Write the rules file + if err := fs.WriteString(auditRulesPath, auditRulesContent); err != nil { + return fmt.Errorf("failed to write rules file: %v", err) + } + + return nil +} + +// cleanupAuditd removes UTMStack audit rules on agent uninstall. +// It removes the rules file and reloads auditd to clear the rules from kernel. +// Does NOT stop auditd service or uninstall the package. +func cleanupAuditd() error { + // Skip if not root + if !isRoot() { + utils.Logger.Info("skipping auditd cleanup: not running as root") + return nil + } + + // Skip if running in container + if isContainer() { + utils.Logger.Info("skipping auditd cleanup: running in container") + return nil + } + + // Remove our rules file if it exists + if _, err := os.Stat(auditRulesPath); err == nil { + if err := os.Remove(auditRulesPath); err != nil { + utils.Logger.ErrorF("failed to remove auditd rules file: %v", err) + return err + } + utils.Logger.Info("removed UTMStack auditd rules file") + + // Reload auditd rules to clear our rules from kernel + if err := reloadRules(); err != nil { + utils.Logger.ErrorF("failed to reload auditd rules after cleanup: %v", err) + // Don't fail - the file is already removed + } + } + + // Do NOT stop auditd service + // Do NOT uninstall auditd package + + return nil +} + +// reloadRules loads the audit rules into the kernel. +func reloadRules() error { + // Try augenrules first (preferred method for rules.d) + if _, err := exec.LookPath("augenrules"); err == nil { + if err := sharedExec.Run("augenrules", "/", "--load"); err != nil { + utils.Logger.LogF(400, "augenrules --load failed: %v, trying auditctl", err) + } else { + return nil + } + } + + // Fallback to auditctl -R + if _, err := exec.LookPath("auditctl"); err == nil { + if err := sharedExec.Run("auditctl", "/", "-R", auditRulesPath); err != nil { + return fmt.Errorf("failed to load rules with auditctl: %v", err) + } + return nil + } + + return fmt.Errorf("no audit rule loader found (augenrules or auditctl)") +} diff --git a/agent/dependency/auditd_other.go b/agent/dependency/auditd_other.go new file mode 100644 index 000000000..7c8a667a6 --- /dev/null +++ b/agent/dependency/auditd_other.go @@ -0,0 +1,18 @@ +//go:build !linux +// +build !linux + +package dependency + +// AuditdVersion is the UTMStack audit rules version. +// This is a stub for non-Linux systems. +const AuditdVersion = "1.0.0" + +// configureAuditd is a no-op on non-Linux systems. +func configureAuditd() error { + return nil +} + +// updateAuditdRules is a no-op on non-Linux systems. +func updateAuditdRules() error { + return nil +} diff --git a/agent/dependency/dependency.go b/agent/dependency/dependency.go index 47d908f3d..2140def1a 100644 --- a/agent/dependency/dependency.go +++ b/agent/dependency/dependency.go @@ -37,16 +37,16 @@ func UpdaterFile(suffix string) string { // Dependency represents a dependency that the agent needs. type Dependency struct { - Name string // Unique identifier - Version string // Current version in this agent build - BinaryPath string // Path to check if already exists - DownloadURL func(server string) string // URL template to download from - DownloadName string // Filename to save as (if different from BinaryPath basename) - Critical bool // If true, failure blocks agent startup - PostDownload func() error // Run after download (e.g., unzip). Can be nil. - Configure func() error // Run on first install (can be nil) - Update func() error // Run on version change (can be nil, uses Configure) - Uninstall func() error // Run when dependency is removed (can be nil) + Name string // Unique identifier + Version string // Current version in this agent build + BinaryPath string // Path to check if already exists + DownloadURL func(server string) string // URL template to download from + DownloadName string // Filename to save as (if different from BinaryPath basename) + Critical bool // If true, failure blocks agent startup + PostDownload func() error // Run after download (e.g., unzip). Can be nil. + Configure func() error // Run on first install (can be nil) + Update func() error // Run on version change (can be nil, uses Configure) + Uninstall func() error // Run when dependency is removed (can be nil) } // Exists checks if the dependency binary exists on disk. @@ -145,19 +145,31 @@ func Reconcile(server string, skipCertValidation bool) error { if inst == nil { // Not tracked yet if dep.Exists() { - // MIGRATION: Already installed by previous version, just track it + // MIGRATION: Already installed by previous version, configure and track it utils.Logger.Info("Migrating existing dependency: %s (version %s)", dep.Name, dep.Version) + if dep.Configure != nil { + if err := dep.Configure(); err != nil { + errMsg := fmt.Errorf("failed to configure migrated dependency %s: %v", dep.Name, err) + utils.Logger.ErrorF("%v", errMsg) + if dep.Critical { + criticalErrors = append(criticalErrors, errMsg) + } + continue + } + } installed.Add(dep.Name, dep.Version) } else { - // FRESH INSTALL: Download and configure + // FRESH INSTALL: Download (if needed) and configure utils.Logger.Info("Installing new dependency: %s (version %s)", dep.Name, dep.Version) - if err := downloadDependency(dep, server, skipCertValidation); err != nil { - errMsg := fmt.Errorf("failed to download dependency %s: %v", dep.Name, err) - utils.Logger.ErrorF("%v", errMsg) - if dep.Critical { - criticalErrors = append(criticalErrors, errMsg) + if dep.DownloadURL != nil { + if err := downloadDependency(dep, server, skipCertValidation); err != nil { + errMsg := fmt.Errorf("failed to download dependency %s: %v", dep.Name, err) + utils.Logger.ErrorF("%v", errMsg) + if dep.Critical { + criticalErrors = append(criticalErrors, errMsg) + } + continue } - continue } if dep.Configure != nil { @@ -174,15 +186,17 @@ func Reconcile(server string, skipCertValidation bool) error { utils.Logger.Info("Dependency %s installed successfully", dep.Name) } } else if inst.Version != dep.Version { - // VERSION CHANGED: Download and update + // VERSION CHANGED: Download (if needed) and update utils.Logger.Info("Updating dependency: %s (%s -> %s)", dep.Name, inst.Version, dep.Version) - if err := downloadDependency(dep, server, skipCertValidation); err != nil { - errMsg := fmt.Errorf("failed to download dependency update %s: %v", dep.Name, err) - utils.Logger.ErrorF("%v", errMsg) - if dep.Critical { - criticalErrors = append(criticalErrors, errMsg) + if dep.DownloadURL != nil { + if err := downloadDependency(dep, server, skipCertValidation); err != nil { + errMsg := fmt.Errorf("failed to download dependency update %s: %v", dep.Name, err) + utils.Logger.ErrorF("%v", errMsg) + if dep.Critical { + criticalErrors = append(criticalErrors, errMsg) + } + continue } - continue } updateFn := dep.Update @@ -237,6 +251,25 @@ func Reconcile(server string, skipCertValidation bool) error { return nil } +// UninstallAll calls the Uninstall hook for all dependencies that have one. +// This should be called during agent uninstall to clean up dependency artifacts. +func UninstallAll() error { + utils.Logger.Info("Starting dependency uninstall...") + + for _, dep := range GetDependencies() { + if dep.Uninstall != nil { + utils.Logger.Info("Uninstalling dependency: %s", dep.Name) + if err := dep.Uninstall(); err != nil { + utils.Logger.ErrorF("failed to uninstall %s: %v", dep.Name, err) + // Continue with other dependencies even if one fails + } + } + } + + utils.Logger.Info("Dependency uninstall completed") + return nil +} + // downloadDependency downloads the dependency binary. func downloadDependency(dep Dependency, server string, skipCertValidation bool) error { if dep.DownloadURL == nil { diff --git a/agent/dependency/deps_linux_amd64.go b/agent/dependency/deps_linux_amd64.go index 3b552475b..424403353 100644 --- a/agent/dependency/deps_linux_amd64.go +++ b/agent/dependency/deps_linux_amd64.go @@ -13,9 +13,6 @@ import ( "github.com/utmstack/UTMStack/shared/fs" ) -// TODO: Remove after testing native collectors -// const beatsZip = "utmstack_agent_dependencies_linux.zip" - // GetDependencies returns the list of dependencies for Linux amd64. func GetDependencies() []Dependency { basePath := fs.GetExecutablePath() @@ -32,31 +29,6 @@ func GetDependencies() []Dependency { Configure: configureUpdater, Uninstall: uninstallUpdater, }, - // TODO: Remove beats dependency after testing native collectors - // { - // Name: "beats", - // Version: BeatsVersion, - // BinaryPath: filepath.Join(basePath, "beats", "filebeat", "filebeat"), - // DownloadName: beatsZip, - // DownloadURL: func(server string) string { - // return fmt.Sprintf(config.DependUrl, server, config.DependenciesPort, beatsZip) - // }, - // Critical: false, - // PostDownload: func() error { - // zipPath := filepath.Join(basePath, beatsZip) - // if err := archive.Unzip(zipPath, basePath); err != nil { - // return fmt.Errorf("error unzipping beats: %v", err) - // } - // // Remove zip after extraction - // os.Remove(zipPath) - // // Set executable permissions - // beatsPath := filepath.Join(basePath, "beats") - // exec.Run("chmod", basePath, "-R", "755", beatsPath) - // return nil - // }, - // Configure: configureBeats, - // Uninstall: uninstallBeats, - // }, // New beats dependency - only for uninstalling existing filebeat/winlogbeat // No download, no install - native collectors are used instead @@ -66,6 +38,18 @@ func GetDependencies() []Dependency { Critical: false, Uninstall: uninstallBeats, }, + + // Auditd dependency - auto-configures Linux audit daemon + // No download - installs from system package manager + { + Name: "auditd", + Version: AuditdVersion, + BinaryPath: "/sbin/auditctl", // Check if auditd tools exist + Critical: false, + Configure: configureAuditd, + Update: updateAuditdRules, + Uninstall: cleanupAuditd, + }, } } @@ -88,11 +72,6 @@ func uninstallUpdater() error { return exec.Run(updaterPath, fs.GetExecutablePath(), "uninstall") } -// TODO: Remove after testing native collectors -// func configureBeats() error { -// return collector.InstallAll() -// } - func uninstallBeats() error { return collector.UninstallAll() } diff --git a/agent/dependency/deps_linux_arm64.go b/agent/dependency/deps_linux_arm64.go index 66473f04e..18119c2a9 100644 --- a/agent/dependency/deps_linux_arm64.go +++ b/agent/dependency/deps_linux_arm64.go @@ -29,6 +29,18 @@ func GetDependencies() []Dependency { Configure: configureUpdater, Uninstall: uninstallUpdater, }, + + // Auditd dependency - auto-configures Linux audit daemon + // No download - installs from system package manager + { + Name: "auditd", + Version: AuditdVersion, + BinaryPath: "/sbin/auditctl", // Check if auditd tools exist + Critical: false, + Configure: configureAuditd, + Update: updateAuditdRules, + Uninstall: cleanupAuditd, + }, } } diff --git a/agent/dependency/deps_windows_amd64.go b/agent/dependency/deps_windows_amd64.go index 067e6e529..144fb4bbe 100644 --- a/agent/dependency/deps_windows_amd64.go +++ b/agent/dependency/deps_windows_amd64.go @@ -29,28 +29,6 @@ func GetDependencies() []Dependency { Configure: configureUpdater, Uninstall: uninstallUpdater, }, - // TODO: Remove beats dependency after testing native collectors - // { - // Name: "beats", - // Version: BeatsVersion, - // BinaryPath: filepath.Join(basePath, "beats", "filebeat", "filebeat.exe"), - // DownloadName: beatsZip, - // DownloadURL: func(server string) string { - // return fmt.Sprintf(config.DependUrl, server, config.DependenciesPort, beatsZip) - // }, - // Critical: false, - // PostDownload: func() error { - // zipPath := filepath.Join(basePath, beatsZip) - // if err := archive.Unzip(zipPath, basePath); err != nil { - // return fmt.Errorf("error unzipping beats: %v", err) - // } - // // Remove zip after extraction - // os.Remove(zipPath) - // return nil - // }, - // Configure: configureBeats, - // Uninstall: uninstallBeats, - // }, // New beats dependency - only for uninstalling existing filebeat/winlogbeat // No download, no install - native collectors are used instead @@ -76,11 +54,6 @@ func uninstallUpdater() error { return exec.Run(updaterPath, fs.GetExecutablePath(), "uninstall") } -// TODO: Remove after testing native collectors -// func configureBeats() error { -// return collector.InstallAll() -// } - func uninstallBeats() error { return collector.UninstallAll() } diff --git a/agent/dependency/distro_linux.go b/agent/dependency/distro_linux.go new file mode 100644 index 000000000..a9e0d9bca --- /dev/null +++ b/agent/dependency/distro_linux.go @@ -0,0 +1,142 @@ +//go:build linux +// +build linux + +package dependency + +import ( + "bufio" + "os" + "os/exec" + "strings" +) + +// DistroInfo holds Linux distribution details for package manager selection. +type DistroInfo struct { + ID string // Primary distro ID (debian, ubuntu, rhel, centos, fedora, etc.) + IDLike string // Parent distro family (debian, rhel, etc.) + PackageManager string // Package manager to use (apt, dnf, yum, zypper, pacman) +} + +// DetectDistro parses /etc/os-release and determines the package manager to use. +// Falls back to binary detection if os-release parsing fails. +func DetectDistro() *DistroInfo { + info := &DistroInfo{} + + // Try parsing /etc/os-release first + if osRelease, err := parseOSRelease("/etc/os-release"); err == nil { + info.ID = strings.ToLower(osRelease["ID"]) + info.IDLike = strings.ToLower(osRelease["ID_LIKE"]) + } + + // Map to package manager + info.PackageManager = mapPackageManager(info.ID, info.IDLike) + + // Fallback to binary detection if mapping failed + if info.PackageManager == "" { + info.PackageManager = detectPackageManagerBinary() + } + + return info +} + +// parseOSRelease reads and parses /etc/os-release into a key-value map. +func parseOSRelease(path string) (map[string]string, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + result := make(map[string]string) + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + + parts := strings.SplitN(line, "=", 2) + if len(parts) != 2 { + continue + } + + key := parts[0] + value := strings.Trim(parts[1], `"'`) + result[key] = value + } + + return result, scanner.Err() +} + +// mapPackageManager determines the package manager based on distro ID and ID_LIKE. +// Returns empty string if no match is found. +func mapPackageManager(id, idLike string) string { + // Direct ID mapping (highest priority) + switch id { + // apt-based (Debian family) + case "debian", "ubuntu", "linuxmint", "pop", "elementary", "zorin", "kali", "raspbian": + return "apt" + + // dnf-based (modern Red Hat family) + case "fedora", "rocky", "almalinux", "alma": + return "dnf" + + // yum/dnf for RHEL and CentOS (depends on version, but dnf is preferred on modern) + case "rhel", "centos": + // Modern RHEL/CentOS use dnf, but we try dnf first in installPackage + return "dnf" + + // yum-based (legacy Red Hat, Amazon Linux) + case "amzn", "amazon": + return "yum" + + // zypper-based (SUSE family) + case "suse", "opensuse", "opensuse-leap", "opensuse-tumbleweed": + return "zypper" + + // pacman-based (Arch family) + case "arch", "manjaro", "endeavouros", "garuda": + return "pacman" + } + + // Check ID_LIKE for family membership + idLikeParts := strings.Fields(idLike) + for _, like := range idLikeParts { + switch like { + case "debian", "ubuntu": + return "apt" + case "rhel", "fedora", "centos": + return "dnf" + case "suse", "opensuse": + return "zypper" + case "arch": + return "pacman" + } + } + + return "" +} + +// detectPackageManagerBinary tries to find package manager binaries as a fallback. +// Returns empty string if no package manager is found. +func detectPackageManagerBinary() string { + // Check in order of preference + binaries := []struct { + cmd string + pm string + }{ + {"apt-get", "apt"}, + {"dnf", "dnf"}, + {"yum", "yum"}, + {"zypper", "zypper"}, + {"pacman", "pacman"}, + } + + for _, b := range binaries { + if _, err := exec.LookPath(b.cmd); err == nil { + return b.pm + } + } + + return "" +} diff --git a/agent/go.mod b/agent/go.mod index b90c5ee3e..81e03b34f 100644 --- a/agent/go.mod +++ b/agent/go.mod @@ -4,7 +4,9 @@ go 1.25.5 require ( github.com/AtlasInsideCorp/AtlasInsideAES v1.0.0 + github.com/elastic/go-libaudit/v2 v2.6.2 github.com/elastic/go-sysinfo v1.15.4 + github.com/fsnotify/fsnotify v1.9.0 github.com/glebarez/sqlite v1.11.0 github.com/google/uuid v1.6.0 github.com/kardianos/service v1.2.4 @@ -31,7 +33,6 @@ require ( github.com/cloudwego/base64x v0.1.6 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/elastic/go-windows v1.0.2 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/gin-contrib/sse v1.1.0 // indirect github.com/gin-gonic/gin v1.11.0 // indirect diff --git a/agent/go.sum b/agent/go.sum index cfb551e58..4f8d7b56b 100644 --- a/agent/go.sum +++ b/agent/go.sum @@ -21,6 +21,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elastic/go-libaudit/v2 v2.6.2 h1:1PM6wVBTJHJQYsKl8jfA9/Aw9pFty5uUezPiUfKtOI4= +github.com/elastic/go-libaudit/v2 v2.6.2/go.mod h1:8205nkf2oSrXFlO4H5j8/cyVMoSF3Y7jt+FjgS4ubQU= +github.com/elastic/go-licenser v0.4.1 h1:1xDURsc8pL5zYT9R29425J3vkHdt4RT5TNEMeRN48x4= +github.com/elastic/go-licenser v0.4.1/go.mod h1:V56wHMpmdURfibNBggaSBfqgPxyT1Tldns1i87iTEvU= github.com/elastic/go-sysinfo v1.15.4 h1:A3zQcunCxik14MgXu39cXFXcIw2sFXZ0zL886eyiv1Q= github.com/elastic/go-sysinfo v1.15.4/go.mod h1:ZBVXmqS368dOn/jvijV/zHLfakWTYHBZPk3G244lHrU= github.com/elastic/go-windows v1.0.2 h1:yoLLsAsV5cfg9FLhZ9EXZ2n2sQFKeDYrHenkcivY4vI= @@ -77,6 +81,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kardianos/service v1.2.4 h1:XNlGtZOYNx2u91urOdg/Kfmc+gfmuIo1Dd3rEi2OgBk= github.com/kardianos/service v1.2.4/go.mod h1:E4V9ufUuY82F7Ztlu1eN9VXWIQxg8NoLQlmFe0MtrXc= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= diff --git a/agent/updater/go.mod b/agent/updater/go.mod index d9b407d6a..1adb5e102 100644 --- a/agent/updater/go.mod +++ b/agent/updater/go.mod @@ -4,8 +4,6 @@ go 1.25.5 require ( github.com/kardianos/service v1.2.4 - github.com/threatwinds/go-sdk v1.1.14 - github.com/threatwinds/logger v1.2.3 github.com/utmstack/UTMStack/shared v0.0.0 ) @@ -16,6 +14,7 @@ require ( github.com/bytedance/sonic v1.15.0 // indirect github.com/bytedance/sonic/loader v0.5.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/gin-contrib/sse v1.1.0 // indirect github.com/gin-gonic/gin v1.11.0 // indirect @@ -27,19 +26,20 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/quic-go v0.59.0 // indirect - github.com/tidwall/gjson v1.18.0 // indirect - github.com/tidwall/match v1.2.0 // indirect - github.com/tidwall/pretty v1.2.1 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect + github.com/threatwinds/logger v1.2.3 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect + go.uber.org/mock v0.6.0 // indirect golang.org/x/arch v0.23.0 // indirect golang.org/x/crypto v0.47.0 // indirect golang.org/x/net v0.49.0 // indirect @@ -48,5 +48,4 @@ require ( google.golang.org/protobuf v1.36.11 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/agent/updater/go.sum b/agent/updater/go.sum index 455acc4b0..00331a446 100644 --- a/agent/updater/go.sum +++ b/agent/updater/go.sum @@ -6,6 +6,7 @@ github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiD github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -74,28 +75,14 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/threatwinds/go-sdk v1.1.14 h1:9XqqGPZvDHHuJ/XkfMsDl3fe7Adfi1fMh/PpQFkUkJU= -github.com/threatwinds/go-sdk v1.1.14/go.mod h1:Kfu26gkSZDpNNkPvuQbTAW3dWIQ66pVIrNYW1YBG3Kg= github.com/threatwinds/logger v1.2.3 h1:V2SVAXzbq+/huCvIWOfqzMTH+WBHJxankyBgVG2hy1Y= github.com/threatwinds/logger v1.2.3/go.mod h1:N+bJKvF4FQNJZLfQpVYWpr6D8iEAFnAQfHYqH5iR1TI= -github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= -github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= -github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= -go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= -go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= golang.org/x/arch v0.23.0 h1:lKF64A2jF6Zd8L0knGltUnegD62JMFBiCPBmQpToHhg= golang.org/x/arch v0.23.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= @@ -117,5 +104,3 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYs gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= -sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= From 527d7440883ba226d487fe49938616901df40740 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Fri, 27 Mar 2026 11:05:09 -0400 Subject: [PATCH 050/135] feat(filters): add auditd support to linux filter v5.0.0 - Support native auditd collector JSON format (type: auditd) - Map auditd fields to Standard Event Schema: - syscall/category -> action - result -> actionResult - exe/comm -> origin.process - proctitle -> origin.command - subj_user -> origin.user - cwd -> origin.path - exit -> statusCode (cast to int) - Set default severity 'info' for auditd events - Preserve numeric IDs in log.* for correlation rules - Maintain backwards compatibility with journald format --- filters/linux/linux.yml | 526 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 475 insertions(+), 51 deletions(-) diff --git a/filters/linux/linux.yml b/filters/linux/linux.yml index 7dad671a1..3bce4d8b2 100644 --- a/filters/linux/linux.yml +++ b/filters/linux/linux.yml @@ -1,55 +1,479 @@ +# System Linux filter version 5.0.0 +# Support for: +# - systemd/journald JSON format (SCREAMINGSNAKECASE fields) +# - Native auditd collector JSON format (type: "auditd") +# Converts SCREAMINGSNAKECASE and snakecase to camelCase +# Maps to UTMStack Standard Event Schema +# Optimized: Direct mapping to standard schema (no intermediate steps) + pipeline: - dataTypes: - - rsyslog-linux + - linux steps: - # 1. Handle Agent Wrapper (Optional) - - grok: + # ======================================== + # PHASE 1: EXTRACTION + # ======================================== + + # Parse JSON from systemd/journald + - json: source: raw - patterns: - - fieldName: log.wrapper_open - pattern: '\[utm_stack_agent_ds=' - - fieldName: log.datasource_override - pattern: '{{.data}}' - - fieldName: log.wrapper_close - pattern: '\]-' - - fieldName: log.inner_msg - pattern: '{{.greedy}}' - - fieldName: log.inner_msg - pattern: '{{.greedy}}' - - # 2. Parse Syslog - - grok: - source: log.inner_msg - patterns: - - fieldName: log.timestamp - pattern: '{{.monthName}}(\s+){{.monthDay}}(\s+){{.time}}' - - fieldName: log.separator - pattern: '{{.space}}' - - fieldName: log.syslog_host - pattern: '{{.hostname}}' - - fieldName: log.separator - pattern: '{{.space}}' - - fieldName: log.process_info - pattern: '{{.data}}:' - - fieldName: log.message - pattern: '{{.greedy}}' - - # 3. Rename Fields - # Extract PID if present in process info (e.g. sshd[123]) - - grok: - source: log.process_info - patterns: - - fieldName: log.process_name - pattern: '{{.word}}' - - fieldName: log.pid_wrapper - pattern: '\[{{.integer}}\]' - where: 'contains(log.process_info, "[")' - - - rename: - from: [log.process_info] - to: log.process_name - where: '!contains(log.process_info, "[")' - - # 4. Cleanup - - delete: - fields: [log.wrapper_open, log.wrapper_close, log.inner_msg, log.separator, log.pid_wrapper] + where: 'startsWith("raw", "{")' + + # ======================================== + # PHASE 2: FIELD NORMALIZATION (camelCase conversion) + # ======================================== + + # Convert SCREAMINGSNAKECASE to camelCase + - rename: + from: + - log.MESSAGE + to: log.message + where: exists("log.MESSAGE") + + - rename: + from: + - log.PRIORITY + to: log.priority + where: exists("log.PRIORITY") + + - rename: + from: + - log.SYSLOGIDENTIFIER + to: log.syslogIdentifier + where: exists("log.SYSLOGIDENTIFIER") + + - rename: + from: + - log.SYSLOGTIMESTAMP + to: log.syslogTimestamp + where: exists("log.SYSLOGTIMESTAMP") + + - rename: + from: + - log.SYSLOGFACILITY + to: log.syslogFacility + where: exists("log.SYSLOGFACILITY") + + - rename: + from: + - log.SYSLOGPID + to: log.syslogPid + where: exists("log.SYSLOGPID") + + # Convert snakecase to camelCase (only for fields staying in log.*) + - rename: + from: + - log.PID + to: log.pid + where: exists("log.PID") + + - rename: + from: + - log.UID + to: log.uid + where: exists("log.UID") + + - rename: + from: + - log.GID + to: log.gid + where: exists("log.GID") + + - rename: + from: + - log.TID + to: log.tid + where: exists("log.TID") + + - rename: + from: + - log.EXE + to: log.exe + where: exists("log.EXE") + + - rename: + from: + - log.UNIT + to: log.unit + where: exists("log.UNIT") + + - rename: + from: + - log.SYSTEMDUNIT + to: log.systemdUnit + where: exists("log.SYSTEMDUNIT") + + - rename: + from: + - log.SYSTEMDSLICE + to: log.systemdSlice + where: exists("log.SYSTEMDSLICE") + + - rename: + from: + - log.SYSTEMDUSERSLICE + to: log.systemdUserSlice + where: exists("log.SYSTEMDUSERSLICE") + + - rename: + from: + - log.SYSTEMDSESSION + to: log.systemdSession + where: exists("log.SYSTEMDSESSION") + + - rename: + from: + - log.SESSIONID + to: log.sessionId + where: exists("log.SESSIONID") + + - rename: + from: + - log.LEADER + to: log.leader + where: exists("log.LEADER") + + - rename: + from: + - log.SYSTEMDOWNERUID + to: log.systemdOwnerUid + where: exists("log.SYSTEMDOWNERUID") + + - rename: + from: + - log.SYSTEMDCGROUP + to: log.systemdCgroup + where: exists("log.SYSTEMDCGROUP") + + - rename: + from: + - log.BOOTID + to: log.bootId + where: exists("log.BOOTID") + + - rename: + from: + - log.MACHINEID + to: log.machineId + where: exists("log.MACHINEID") + + - rename: + from: + - log.TRANSPORT + to: log.transport + where: exists("log.TRANSPORT") + + - rename: + from: + - log.SELINUXCONTEXT + to: log.selinuxContext + where: exists("log.SELINUXCONTEXT") + + - rename: + from: + - log.AUDITSESSION + to: log.auditSession + where: exists("log.AUDITSESSION") + + - rename: + from: + - log.AUDITLOGINUID + to: log.auditLoginUid + where: exists("log.AUDITLOGINUID") + + - rename: + from: + - log.CAPEFFECTIVE + to: log.capEffective + where: exists("log.CAPEFFECTIVE") + + - rename: + from: + - log.REALTIMETIMESTAMP + to: log.realtimeTimestamp + where: exists("log.REALTIMETIMESTAMP") + + - rename: + from: + - log.SOURCEREALTIMETIMESTAMP + to: log.sourceRealtimeTimestamp + where: exists("log.SOURCEREALTIMETIMESTAMP") + + - rename: + from: + - log.MONOTONICTIMESTAMP + to: log.monotonicTimestamp + where: exists("log.MONOTONICTIMESTAMP") + + - rename: + from: + - log.CURSOR + to: log.cursor + where: exists("log.CURSOR") + + - rename: + from: + - log.SEQNUM + to: log.seqnum + where: exists("log.SEQNUM") + + - rename: + from: + - log.SEQNUMID + to: log.seqnumId + where: exists("log.SEQNUMID") + + - rename: + from: + - log.RUNTIMESCOPE + to: log.runtimeScope + where: exists("log.RUNTIMESCOPE") + + - rename: + from: + - log.STREAMID + to: log.streamId + where: exists("log.STREAMID") + + - rename: + from: + - log.SYSTEMDINVOCATIONID + to: log.systemdInvocationId + where: exists("log.SYSTEMDINVOCATIONID") + + - rename: + from: + - log.CODEFILE + to: log.codeFile + where: exists("log.CODEFILE") + + - rename: + from: + - log.CODELINE + to: log.codeLine + where: exists("log.CODELINE") + + - rename: + from: + - log.CODEFUNC + to: log.codeFunc + where: exists("log.CODEFUNC") + + - rename: + from: + - log.INVOCATIONID + to: log.invocationId + where: exists("log.INVOCATIONID") + + - rename: + from: + - log.JOBID + to: log.jobId + where: exists("log.JOBID") + + - rename: + from: + - log.JOBRESULT + to: actionResult + where: exists("log.JOBRESULT") + + - rename: + from: + - log.JOBTYPE + to: log.jobType + where: exists("log.JOBTYPE") + + - rename: + from: + - log.MESSAGEID + to: log.messageId + where: exists("log.MESSAGEID") + + - rename: + from: + - log.CPUUSAGENSEC + to: log.cpuUsageNsec + where: exists("log.CPUUSAGENSEC") + + - rename: + from: + - log.MEMORYPEAK + to: log.memoryPeak + where: exists("log.MEMORYPEAK") + + - rename: + from: + - log.MEMORYSWAPPEAK + to: log.memorySwapPeak + where: exists("log.MEMORYSWAPPEAK") + + # ======================================== + # PHASE 3: STANDARD SCHEMA MAPPING + # ======================================== + + # Map directly to Standard Event Schema (no intermediate camelCase step) + - rename: + from: + - log.HOSTNAME + to: origin.host + where: exists("log.HOSTNAME") + + - rename: + from: + - log.USERID + to: origin.user + where: exists("log.USERID") + + - rename: + from: + - log.COMM + to: origin.process + where: exists("log.COMM") + + - rename: + from: + - log.CMDLINE + to: origin.command + where: exists("log.CMDLINE") + + # Map syslog priority (0-7) to severity labels + - add: + function: string + params: + key: severity + value: "emergency" + where: 'equals("log.priority", "0")' + + - add: + function: string + params: + key: severity + value: "alert" + where: 'equals("log.priority", "1")' + + - add: + function: string + params: + key: severity + value: "critical" + where: 'equals("log.priority", "2")' + + - add: + function: string + params: + key: severity + value: "error" + where: 'equals("log.priority", "3")' + + - add: + function: string + params: + key: severity + value: "warning" + where: 'equals("log.priority", "4")' + + - add: + function: string + params: + key: severity + value: "notice" + where: 'equals("log.priority", "5")' + + - add: + function: string + params: + key: severity + value: "info" + where: 'equals("log.priority", "6")' + + - add: + function: string + params: + key: severity + value: "debug" + where: 'equals("log.priority", "7")' + + # ======================================== + # PHASE 4: AUDITD NORMALIZATION + # Process only when log.type == "auditd" + # Auditd logs have lowercase fields and type: "auditd" + # ======================================== + + # Map auditd syscall to action (primary action identifier) + - rename: + from: + - log.syscall + to: action + where: 'equals("log.type", "auditd") && exists("log.syscall")' + + # Fallback: map category to action if syscall not present + - rename: + from: + - log.category + to: action + where: 'equals("log.type", "auditd") && !exists("action") && exists("log.category")' + + # Map result to actionResult (success/failure) + - rename: + from: + - log.result + to: actionResult + where: 'equals("log.type", "auditd") && exists("log.result")' + + # Map exe to origin.process (full path to executable) + # Only if journald's COMM didn't already set origin.process + - rename: + from: + - log.exe + to: origin.process + where: 'equals("log.type", "auditd") && exists("log.exe") && !exists("origin.process")' + + # Fallback: map auditd comm to origin.process if exe not mapped + - rename: + from: + - log.comm + to: origin.process + where: 'equals("log.type", "auditd") && !exists("origin.process") && exists("log.comm")' + + # Map proctitle to origin.command (full command line) + - rename: + from: + - log.proctitle + to: origin.command + where: 'equals("log.type", "auditd") && exists("log.proctitle")' + + # Map subj_user to origin.user (SELinux subject user) + - rename: + from: + - log.subj_user + to: origin.user + where: 'equals("log.type", "auditd") && exists("log.subj_user")' + + # Map cwd to origin.path (current working directory) + - rename: + from: + - log.cwd + to: origin.path + where: 'equals("log.type", "auditd") && exists("log.cwd")' + + # Map exit code to statusCode (for correlation and alerting) + - rename: + from: + - log.exit + to: statusCode + where: 'equals("log.type", "auditd") && exists("log.exit")' + + # Cast statusCode to integer (proto schema expects uint32) + - cast: + fields: [statusCode] + to: int + where: 'equals("log.type", "auditd") && exists("statusCode")' + + # Set default severity for auditd events (info level) + # Auditd logs don't have syslog priority, so default to info + - add: + function: string + params: + key: severity + value: "info" + where: 'equals("log.type", "auditd") && !exists("severity")' \ No newline at end of file From f77ef28f0232b98fcbb6415a584287b36fc9512e Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Fri, 27 Mar 2026 11:09:26 -0400 Subject: [PATCH 051/135] refactor(filters): remove deprecated system_linux_module.yml --- filters/filebeat/system_linux_module.yml | 392 ----------------------- 1 file changed, 392 deletions(-) delete mode 100644 filters/filebeat/system_linux_module.yml diff --git a/filters/filebeat/system_linux_module.yml b/filters/filebeat/system_linux_module.yml deleted file mode 100644 index eaac62e6b..000000000 --- a/filters/filebeat/system_linux_module.yml +++ /dev/null @@ -1,392 +0,0 @@ -# System Linux filter version 4.0.0 -# Support for systemd/journald JSON format from filebeat/journald -# Converts SCREAMINGSNAKECASE and snakecase to camelCase -# Maps to UTMStack Standard Event Schema -# Optimized: Direct mapping to standard schema (no intermediate steps) - -pipeline: - - dataTypes: - - linux - steps: - # ======================================== - # PHASE 1: EXTRACTION - # ======================================== - - # Parse JSON from systemd/journald - - json: - source: raw - where: 'startsWith("raw", "{")' - - # ======================================== - # PHASE 2: FIELD NORMALIZATION (camelCase conversion) - # ======================================== - - # Convert SCREAMINGSNAKECASE to camelCase - - rename: - from: - - log.MESSAGE - to: log.message - where: exists("log.MESSAGE") - - - rename: - from: - - log.PRIORITY - to: log.priority - where: exists("log.PRIORITY") - - - rename: - from: - - log.SYSLOGIDENTIFIER - to: log.syslogIdentifier - where: exists("log.SYSLOGIDENTIFIER") - - - rename: - from: - - log.SYSLOGTIMESTAMP - to: log.syslogTimestamp - where: exists("log.SYSLOGTIMESTAMP") - - - rename: - from: - - log.SYSLOGFACILITY - to: log.syslogFacility - where: exists("log.SYSLOGFACILITY") - - - rename: - from: - - log.SYSLOGPID - to: log.syslogPid - where: exists("log.SYSLOGPID") - - # Convert snakecase to camelCase (only for fields staying in log.*) - - rename: - from: - - log.PID - to: log.pid - where: exists("log.PID") - - - rename: - from: - - log.UID - to: log.uid - where: exists("log.UID") - - - rename: - from: - - log.GID - to: log.gid - where: exists("log.GID") - - - rename: - from: - - log.TID - to: log.tid - where: exists("log.TID") - - - rename: - from: - - log.EXE - to: log.exe - where: exists("log.EXE") - - - rename: - from: - - log.UNIT - to: log.unit - where: exists("log.UNIT") - - - rename: - from: - - log.SYSTEMDUNIT - to: log.systemdUnit - where: exists("log.SYSTEMDUNIT") - - - rename: - from: - - log.SYSTEMDSLICE - to: log.systemdSlice - where: exists("log.SYSTEMDSLICE") - - - rename: - from: - - log.SYSTEMDUSERSLICE - to: log.systemdUserSlice - where: exists("log.SYSTEMDUSERSLICE") - - - rename: - from: - - log.SYSTEMDSESSION - to: log.systemdSession - where: exists("log.SYSTEMDSESSION") - - - rename: - from: - - log.SESSIONID - to: log.sessionId - where: exists("log.SESSIONID") - - - rename: - from: - - log.LEADER - to: log.leader - where: exists("log.LEADER") - - - rename: - from: - - log.SYSTEMDOWNERUID - to: log.systemdOwnerUid - where: exists("log.SYSTEMDOWNERUID") - - - rename: - from: - - log.SYSTEMDCGROUP - to: log.systemdCgroup - where: exists("log.SYSTEMDCGROUP") - - - rename: - from: - - log.BOOTID - to: log.bootId - where: exists("log.BOOTID") - - - rename: - from: - - log.MACHINEID - to: log.machineId - where: exists("log.MACHINEID") - - - rename: - from: - - log.TRANSPORT - to: log.transport - where: exists("log.TRANSPORT") - - - rename: - from: - - log.SELINUXCONTEXT - to: log.selinuxContext - where: exists("log.SELINUXCONTEXT") - - - rename: - from: - - log.AUDITSESSION - to: log.auditSession - where: exists("log.AUDITSESSION") - - - rename: - from: - - log.AUDITLOGINUID - to: log.auditLoginUid - where: exists("log.AUDITLOGINUID") - - - rename: - from: - - log.CAPEFFECTIVE - to: log.capEffective - where: exists("log.CAPEFFECTIVE") - - - rename: - from: - - log.REALTIMETIMESTAMP - to: log.realtimeTimestamp - where: exists("log.REALTIMETIMESTAMP") - - - rename: - from: - - log.SOURCEREALTIMETIMESTAMP - to: log.sourceRealtimeTimestamp - where: exists("log.SOURCEREALTIMETIMESTAMP") - - - rename: - from: - - log.MONOTONICTIMESTAMP - to: log.monotonicTimestamp - where: exists("log.MONOTONICTIMESTAMP") - - - rename: - from: - - log.CURSOR - to: log.cursor - where: exists("log.CURSOR") - - - rename: - from: - - log.SEQNUM - to: log.seqnum - where: exists("log.SEQNUM") - - - rename: - from: - - log.SEQNUMID - to: log.seqnumId - where: exists("log.SEQNUMID") - - - rename: - from: - - log.RUNTIMESCOPE - to: log.runtimeScope - where: exists("log.RUNTIMESCOPE") - - - rename: - from: - - log.STREAMID - to: log.streamId - where: exists("log.STREAMID") - - - rename: - from: - - log.SYSTEMDINVOCATIONID - to: log.systemdInvocationId - where: exists("log.SYSTEMDINVOCATIONID") - - - rename: - from: - - log.CODEFILE - to: log.codeFile - where: exists("log.CODEFILE") - - - rename: - from: - - log.CODELINE - to: log.codeLine - where: exists("log.CODELINE") - - - rename: - from: - - log.CODEFUNC - to: log.codeFunc - where: exists("log.CODEFUNC") - - - rename: - from: - - log.INVOCATIONID - to: log.invocationId - where: exists("log.INVOCATIONID") - - - rename: - from: - - log.JOBID - to: log.jobId - where: exists("log.JOBID") - - - rename: - from: - - log.JOBRESULT - to: actionResult - where: exists("log.JOBRESULT") - - - rename: - from: - - log.JOBTYPE - to: log.jobType - where: exists("log.JOBTYPE") - - - rename: - from: - - log.MESSAGEID - to: log.messageId - where: exists("log.MESSAGEID") - - - rename: - from: - - log.CPUUSAGENSEC - to: log.cpuUsageNsec - where: exists("log.CPUUSAGENSEC") - - - rename: - from: - - log.MEMORYPEAK - to: log.memoryPeak - where: exists("log.MEMORYPEAK") - - - rename: - from: - - log.MEMORYSWAPPEAK - to: log.memorySwapPeak - where: exists("log.MEMORYSWAPPEAK") - - # ======================================== - # PHASE 3: STANDARD SCHEMA MAPPING - # ======================================== - - # Map directly to Standard Event Schema (no intermediate camelCase step) - - rename: - from: - - log.HOSTNAME - to: origin.host - where: exists("log.HOSTNAME") - - - rename: - from: - - log.USERID - to: origin.user - where: exists("log.USERID") - - - rename: - from: - - log.COMM - to: origin.process - where: exists("log.COMM") - - - rename: - from: - - log.CMDLINE - to: origin.command - where: exists("log.CMDLINE") - - # Map syslog priority (0-7) to severity labels - - add: - function: string - params: - key: severity - value: "emergency" - where: 'equals("log.priority", "0")' - - - add: - function: string - params: - key: severity - value: "alert" - where: 'equals("log.priority", "1")' - - - add: - function: string - params: - key: severity - value: "critical" - where: 'equals("log.priority", "2")' - - - add: - function: string - params: - key: severity - value: "error" - where: 'equals("log.priority", "3")' - - - add: - function: string - params: - key: severity - value: "warning" - where: 'equals("log.priority", "4")' - - - add: - function: string - params: - key: severity - value: "notice" - where: 'equals("log.priority", "5")' - - - add: - function: string - params: - key: severity - value: "info" - where: 'equals("log.priority", "6")' - - - add: - function: string - params: - key: severity - value: "debug" - where: 'equals("log.priority", "7")' \ No newline at end of file From c2aba9e2af41ea33130449d5f33f1267eb5baec1 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Fri, 27 Mar 2026 11:14:15 -0400 Subject: [PATCH 052/135] fix(filters): adjust auditd event severity handling in linux filter --- filters/linux/linux.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/filters/linux/linux.yml b/filters/linux/linux.yml index 3bce4d8b2..554eae9c8 100644 --- a/filters/linux/linux.yml +++ b/filters/linux/linux.yml @@ -467,13 +467,4 @@ pipeline: - cast: fields: [statusCode] to: int - where: 'equals("log.type", "auditd") && exists("statusCode")' - - # Set default severity for auditd events (info level) - # Auditd logs don't have syslog priority, so default to info - - add: - function: string - params: - key: severity - value: "info" - where: 'equals("log.type", "auditd") && !exists("severity")' \ No newline at end of file + where: 'equals("log.type", "auditd") && exists("statusCode")' \ No newline at end of file From 83eed3e7d204864f0840cd5ecc41481948e2c361 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Fri, 27 Mar 2026 11:15:06 -0400 Subject: [PATCH 053/135] chore(agent): update version to 11.1.5 --- agent/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/version.json b/agent/version.json index b60b61712..8981e0f87 100644 --- a/agent/version.json +++ b/agent/version.json @@ -1,4 +1,4 @@ { - "version": "11.1.4", + "version": "11.1.5", "updater_version": "1.0.4" } From 7dbdce3973c19bb5bbbd61c9be804fc1fbcb36d8 Mon Sep 17 00:00:00 2001 From: AlexSanchez-bit Date: Fri, 27 Mar 2026 11:35:57 -0400 Subject: [PATCH 054/135] changeset[backend](linux): update linux filter --- .../20260327001_update_linux_filter.xml | 493 ++++++++++++++++++ .../resources/config/liquibase/master.xml | 2 + 2 files changed, 495 insertions(+) create mode 100644 backend/src/main/resources/config/liquibase/changelog/20260327001_update_linux_filter.xml diff --git a/backend/src/main/resources/config/liquibase/changelog/20260327001_update_linux_filter.xml b/backend/src/main/resources/config/liquibase/changelog/20260327001_update_linux_filter.xml new file mode 100644 index 000000000..500513b41 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260327001_update_linux_filter.xml @@ -0,0 +1,493 @@ + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/master.xml b/backend/src/main/resources/config/liquibase/master.xml index 86c16ca8f..4784e0330 100644 --- a/backend/src/main/resources/config/liquibase/master.xml +++ b/backend/src/main/resources/config/liquibase/master.xml @@ -537,6 +537,8 @@ + + From 5b7cc19d6f0e29a7eff803d9abe7d0751db7c278 Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Fri, 27 Mar 2026 16:07:31 -0400 Subject: [PATCH 055/135] fix(agent): prevent auditd buffer overflow with backpressure mitigation --- agent/collector/auditd/auditd.go | 3 ++- agent/collector/auditd/auditd_linux.go | 17 +++++++++++++ agent/collector/auditd/client.go | 35 ++++++++++++++++++++++++++ agent/collector/auditd/stream.go | 16 ++++++++++-- 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/agent/collector/auditd/auditd.go b/agent/collector/auditd/auditd.go index 18b32e2d7..9b72c2b3c 100644 --- a/agent/collector/auditd/auditd.go +++ b/agent/collector/auditd/auditd.go @@ -13,7 +13,8 @@ const ( auditdMaxRestartDelay = 5 * time.Minute // reassemblerMaxInFlight is the maximum number of events held for reassembly - reassemblerMaxInFlight = 50 + // Increased from 50 to 2048 to prevent buffer overflow under high event load + reassemblerMaxInFlight = 2048 // reassemblerTimeout is how long to wait for related messages before flushing reassemblerTimeout = 2 * time.Second diff --git a/agent/collector/auditd/auditd_linux.go b/agent/collector/auditd/auditd_linux.go index b34168fb6..71b5d1d0c 100644 --- a/agent/collector/auditd/auditd_linux.go +++ b/agent/collector/auditd/auditd_linux.go @@ -85,6 +85,23 @@ func (a *AuditdCollector) runAuditClient(ctx context.Context, host string, queue clientCtx, cancel := context.WithCancel(ctx) a.cancel = cancel + // Attempt to set kernel backlog limit to prevent event loss under high load. + // This requires CAP_AUDIT_CONTROL; log warning if it fails but continue. + if err := setKernelBacklogLimit(kernelBacklogLimit); err != nil { + utils.Logger.ErrorF("auditd: failed to set kernel backlog limit to %d: %v (continuing with default)", kernelBacklogLimit, err) + } else { + utils.Logger.Info("auditd: kernel backlog limit set to %d", kernelBacklogLimit) + } + + // Set backlog wait time to 0 to prevent audited processes from blocking + // when the audit backlog queue is full. The kernel will drop events instead. + // This is the "kernel" backpressure mitigation strategy from Elastic Auditbeat. + if err := setBacklogWaitTime(0); err != nil { + utils.Logger.ErrorF("auditd: failed to set backlog wait time to 0: %v (continuing)", err) + } else { + utils.Logger.Info("auditd: backlog wait time set to 0 (non-blocking mode)") + } + // Create multicast audit client client, err := newAuditClient() if err != nil { diff --git a/agent/collector/auditd/client.go b/agent/collector/auditd/client.go index af2843991..0b734364f 100644 --- a/agent/collector/auditd/client.go +++ b/agent/collector/auditd/client.go @@ -7,6 +7,12 @@ import ( libaudit "github.com/elastic/go-libaudit/v2" ) +const ( + // kernelBacklogLimit is the audit backlog limit to set in the kernel. + // Higher values prevent event loss under high load. + kernelBacklogLimit uint32 = 8192 +) + // auditReceiver interface wraps the go-libaudit client for testability type auditReceiver interface { Receive(nonBlocking bool) (*libaudit.RawAuditMessage, error) @@ -36,3 +42,32 @@ func newAuditClient() (auditReceiver, error) { } return &auditClientWrapper{client: client}, nil } + +// setKernelBacklogLimit sets the kernel audit backlog limit using a separate +// control client. This requires root/CAP_AUDIT_CONTROL privileges. +// The multicast client cannot set kernel parameters, so we create a temporary +// unicast client specifically for this configuration. +func setKernelBacklogLimit(limit uint32) error { + controlClient, err := libaudit.NewAuditClient(nil) + if err != nil { + return err + } + defer controlClient.Close() + + return controlClient.SetBacklogLimit(limit, libaudit.WaitForReply) +} + +// setBacklogWaitTime configures the kernel to not block processes when the +// audit backlog queue is full. With waitTime=0, the kernel will drop events +// instead of stalling audited processes. This is the "kernel" backpressure +// mitigation strategy used by Elastic Auditbeat. +// Requires CAP_AUDIT_CONTROL and kernel 3.14+. +func setBacklogWaitTime(waitTime int32) error { + controlClient, err := libaudit.NewAuditClient(nil) + if err != nil { + return err + } + defer controlClient.Close() + + return controlClient.SetBacklogWaitTime(waitTime, libaudit.WaitForReply) +} diff --git a/agent/collector/auditd/stream.go b/agent/collector/auditd/stream.go index 21a3b8203..c53e937cf 100644 --- a/agent/collector/auditd/stream.go +++ b/agent/collector/auditd/stream.go @@ -24,7 +24,9 @@ func newEventStream(queue chan *plugins.Log, hostname string) *eventStream { } } -// ReassemblyComplete is called when a complete group of events has been received +// ReassemblyComplete is called when a complete group of events has been received. +// Uses non-blocking send to prevent backpressure from propagating to the kernel. +// If the queue is full, events are dropped rather than blocking. func (s *eventStream) ReassemblyComplete(msgs []*auparse.AuditMessage) { if len(msgs) == 0 { return @@ -36,11 +38,21 @@ func (s *eventStream) ReassemblyComplete(msgs []*auparse.AuditMessage) { return } - s.queue <- &plugins.Log{ + log := &plugins.Log{ DataType: string(config.DataTypeLinuxAgent), DataSource: s.hostname, Raw: jsonOutput, } + + // Non-blocking send: drop events if queue is full to prevent backpressure + // This is the "user-space" backpressure mitigation strategy from Elastic Auditbeat + select { + case s.queue <- log: + // Event sent successfully + default: + // Queue is full - drop event to prevent backpressure to kernel + utils.Logger.ErrorF("auditd: queue full, dropping event (sequence=%d)", msgs[0].Sequence) + } } // EventsLost is called when events were lost due to buffer overflow or rate limiting From 6cb6c41de124005368f42383608cfdb2348e071b Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Sun, 29 Mar 2026 21:16:08 -0400 Subject: [PATCH 056/135] fix(agent): reduce auditd log noise with threshold and execve filter - Add 50 event threshold for EventsLost logging (ignore 1-2 event losses) - Filter execve rules to real users only (auid>=1000, auid!=-1) - Simplify EventsLost function --- agent/collector/auditd/stream.go | 14 ++++++++------ agent/dependency/auditd_linux.go | 5 +++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/agent/collector/auditd/stream.go b/agent/collector/auditd/stream.go index c53e937cf..9f552858b 100644 --- a/agent/collector/auditd/stream.go +++ b/agent/collector/auditd/stream.go @@ -10,6 +10,11 @@ import ( "github.com/utmstack/UTMStack/agent/utils" ) +const ( + // eventsLostThreshold - only log when this many events are lost at once. + eventsLostThreshold = 50 +) + // eventStream implements libaudit.Stream interface for reassembled events type eventStream struct { queue chan *plugins.Log @@ -45,7 +50,6 @@ func (s *eventStream) ReassemblyComplete(msgs []*auparse.AuditMessage) { } // Non-blocking send: drop events if queue is full to prevent backpressure - // This is the "user-space" backpressure mitigation strategy from Elastic Auditbeat select { case s.queue <- log: // Event sent successfully @@ -55,12 +59,10 @@ func (s *eventStream) ReassemblyComplete(msgs []*auparse.AuditMessage) { } } -// EventsLost is called when events were lost due to buffer overflow or rate limiting +// EventsLost is called when events were lost due to buffer overflow func (s *eventStream) EventsLost(count int) { - // Ignore invalid counts - large values indicate sequence number rollover/overflow - // not actual lost events. A reasonable max is 100K events lost in one batch. - if count <= 0 || count > 100000 { + if count < eventsLostThreshold { return } - utils.Logger.ErrorF("auditd: %d events lost due to buffer overflow or rate limiting", count) + utils.Logger.ErrorF("auditd: %d events lost due to buffer overflow", count) } diff --git a/agent/dependency/auditd_linux.go b/agent/dependency/auditd_linux.go index 13b33d13c..8c9e74b61 100644 --- a/agent/dependency/auditd_linux.go +++ b/agent/dependency/auditd_linux.go @@ -28,8 +28,9 @@ const auditRulesContent = `## UTMStack SIEM Audit Rules ## Additive rules - does not delete existing configuration # Monitor executed commands (critical for SIEM) --a always,exit -F arch=b64 -S execve -k utmstack_exec --a always,exit -F arch=b32 -S execve -k utmstack_exec +# Filter: auid>=1000 (real users only), auid!=-1 (valid audit UID, excludes system processes) +-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=-1 -k utmstack_exec +-a always,exit -F arch=b32 -S execve -F auid>=1000 -F auid!=-1 -k utmstack_exec # Privilege escalation -a always,exit -F arch=b64 -S setuid,setgid,setreuid,setregid,setresuid,setresgid -F auid>=1000 -k utmstack_priv From 272d2fa6dba6c0649a8c4457591abb1cb257207b Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Mon, 30 Mar 2026 11:52:27 -0400 Subject: [PATCH 057/135] fix(agent): filter false events lost from go-libaudit sequence rollover --- agent/collector/auditd/stream.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/agent/collector/auditd/stream.go b/agent/collector/auditd/stream.go index 9f552858b..33ba3bf58 100644 --- a/agent/collector/auditd/stream.go +++ b/agent/collector/auditd/stream.go @@ -12,7 +12,11 @@ import ( const ( // eventsLostThreshold - only log when this many events are lost at once. + // Small losses (1-10) are normal under high load and not worth logging. eventsLostThreshold = 50 + + // eventsLostMaxReasonable is the maximum "reasonable" number of lost events. + eventsLostMaxReasonable = 1000000 ) // eventStream implements libaudit.Stream interface for reassembled events @@ -59,10 +63,12 @@ func (s *eventStream) ReassemblyComplete(msgs []*auparse.AuditMessage) { } } -// EventsLost is called when events were lost due to buffer overflow +// EventsLost is called when events were lost due to buffer overflow or rate limiting. +// We filter these out by checking against a reasonable maximum. func (s *eventStream) EventsLost(count int) { - if count < eventsLostThreshold { + // Filter out unreasonable values caused by sequence number rollover bug + if count < eventsLostThreshold || count > eventsLostMaxReasonable { return } - utils.Logger.ErrorF("auditd: %d events lost due to buffer overflow", count) + utils.Logger.ErrorF("auditd: %d events lost due to buffer overflow or rate limiting", count) } From fbbb1afdcc9453722892017d3f5ff794b4cece6f Mon Sep 17 00:00:00 2001 From: Yadian Llada Lopez Date: Mon, 30 Mar 2026 11:53:22 -0400 Subject: [PATCH 058/135] feat(agent): expand auditd rules with log tampering and identity files --- agent/dependency/auditd_linux.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/agent/dependency/auditd_linux.go b/agent/dependency/auditd_linux.go index 8c9e74b61..049137dcb 100644 --- a/agent/dependency/auditd_linux.go +++ b/agent/dependency/auditd_linux.go @@ -28,21 +28,30 @@ const auditRulesContent = `## UTMStack SIEM Audit Rules ## Additive rules - does not delete existing configuration # Monitor executed commands (critical for SIEM) -# Filter: auid>=1000 (real users only), auid!=-1 (valid audit UID, excludes system processes) --a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=-1 -k utmstack_exec --a always,exit -F arch=b32 -S execve -F auid>=1000 -F auid!=-1 -k utmstack_exec +# Filter: auid>=1000 (real users only), auid!=4294967295 (valid audit UID, excludes system processes) +-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=4294967295 -k utmstack_exec +-a always,exit -F arch=b32 -S execve -F auid>=1000 -F auid!=4294967295 -k utmstack_exec # Privilege escalation -a always,exit -F arch=b64 -S setuid,setgid,setreuid,setregid,setresuid,setresgid -F auid>=1000 -k utmstack_priv -a always,exit -F arch=b32 -S setuid,setgid,setreuid,setregid,setresuid,setresgid -F auid>=1000 -k utmstack_priv -# Sensitive file access +# Sensitive file access (Identity) -w /etc/shadow -p wa -k utmstack_sensitive -w /etc/passwd -p wa -k utmstack_sensitive +-w /etc/group -p wa -k utmstack_sensitive +-w /etc/gshadow -p wa -k utmstack_sensitive + +# Sensitive file access (SSH & Sudo) -w /etc/sudoers -p wa -k utmstack_sensitive -w /etc/sudoers.d -p wa -k utmstack_sensitive -w /etc/ssh/sshd_config -p wa -k utmstack_sensitive --w /root/.ssh -p wa -k utmstack_sensitive +-w /root/.ssh -p rwa -k utmstack_sensitive + +# Log Tampering +-w /var/log/wtmp -p wa -k utmstack_log_tampering +-w /var/log/btmp -p wa -k utmstack_log_tampering +-w /var/log/lastlog -p wa -k utmstack_log_tampering # Module loading -a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k utmstack_modules @@ -54,6 +63,7 @@ const auditRulesContent = `## UTMStack SIEM Audit Rules # Time changes -a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k utmstack_time -a always,exit -F arch=b32 -S adjtimex,settimeofday,clock_settime -k utmstack_time +-w /etc/localtime -p wa -k utmstack_time # Audit configuration changes -w /etc/audit -p wa -k utmstack_audit_config From 2cf64e0bd7b80e1621d2f58ea5f111b6ab91d257 Mon Sep 17 00:00:00 2001 From: AlexSanchez-bit Date: Mon, 30 Mar 2026 17:58:42 -0400 Subject: [PATCH 059/135] feat[backend](agent): added shell parameter to agent connection --- backend/pom.xml | 2 +- .../main/java/agent/CollectorOuterClass.java | 8959 +++++++++++++++++ .../main/java/agent/CollectorServiceGrpc.java | 573 ++ .../java/agent/PanelCollectorServiceGrpc.java | 293 + .../service/grpc/AgentManagerGrpc.java | 6 +- .../utmstack/service/grpc/AgentService.java | 44 +- .../service/grpc/AgentServiceGrpc.java | 94 +- .../utmstack/service/grpc/UtmCommand.java | 28 + .../service/grpc/UtmCommandOrBuilder.java | 8 + backend/src/main/proto/agent.proto | 137 +- 10 files changed, 10003 insertions(+), 141 deletions(-) create mode 100644 backend/src/main/java/agent/CollectorOuterClass.java create mode 100644 backend/src/main/java/agent/CollectorServiceGrpc.java create mode 100644 backend/src/main/java/agent/PanelCollectorServiceGrpc.java diff --git a/backend/pom.xml b/backend/pom.xml index 022fdd657..911e7567d 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -8,7 +8,7 @@ com.atlasinside utmstack ${revision} - + war UTMStack-API diff --git a/backend/src/main/java/agent/CollectorOuterClass.java b/backend/src/main/java/agent/CollectorOuterClass.java new file mode 100644 index 000000000..d1e02a0f6 --- /dev/null +++ b/backend/src/main/java/agent/CollectorOuterClass.java @@ -0,0 +1,8959 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// NO CHECKED-IN PROTOBUF GENCODE +// source: collector.proto +// Protobuf Java Version: 4.29.3 + +package agent; + +public final class CollectorOuterClass { + private CollectorOuterClass() {} + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + CollectorOuterClass.class.getName()); + } + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + /** + * Protobuf enum {@code agent.CollectorModule} + */ + public enum CollectorModule + implements com.google.protobuf.ProtocolMessageEnum { + /** + * AS_400 = 0; + */ + AS_400(0), + /** + * UTMSTACK = 1; + */ + UTMSTACK(1), + UNRECOGNIZED(-1), + ; + + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + CollectorModule.class.getName()); + } + /** + * AS_400 = 0; + */ + public static final int AS_400_VALUE = 0; + /** + * UTMSTACK = 1; + */ + public static final int UTMSTACK_VALUE = 1; + + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalArgumentException( + "Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static CollectorModule valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static CollectorModule forNumber(int value) { + switch (value) { + case 0: return AS_400; + case 1: return UTMSTACK; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static final com.google.protobuf.Internal.EnumLiteMap< + CollectorModule> internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public CollectorModule findValueByNumber(int number) { + return CollectorModule.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new java.lang.IllegalStateException( + "Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return agent.CollectorOuterClass.getDescriptor().getEnumTypes().get(0); + } + + private static final CollectorModule[] VALUES = values(); + + public static CollectorModule valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private CollectorModule(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:agent.CollectorModule) + } + + public interface RegisterRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:agent.RegisterRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * string ip = 1; + * @return The ip. + */ + java.lang.String getIp(); + /** + * string ip = 1; + * @return The bytes for ip. + */ + com.google.protobuf.ByteString + getIpBytes(); + + /** + * string hostname = 2; + * @return The hostname. + */ + java.lang.String getHostname(); + /** + * string hostname = 2; + * @return The bytes for hostname. + */ + com.google.protobuf.ByteString + getHostnameBytes(); + + /** + * string version = 3; + * @return The version. + */ + java.lang.String getVersion(); + /** + * string version = 3; + * @return The bytes for version. + */ + com.google.protobuf.ByteString + getVersionBytes(); + + /** + * .agent.CollectorModule collector = 4; + * @return The enum numeric value on the wire for collector. + */ + int getCollectorValue(); + /** + * .agent.CollectorModule collector = 4; + * @return The collector. + */ + agent.CollectorOuterClass.CollectorModule getCollector(); + } + /** + * Protobuf type {@code agent.RegisterRequest} + */ + public static final class RegisterRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:agent.RegisterRequest) + RegisterRequestOrBuilder { + private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + RegisterRequest.class.getName()); + } + // Use RegisterRequest.newBuilder() to construct. + private RegisterRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private RegisterRequest() { + ip_ = ""; + hostname_ = ""; + version_ = ""; + collector_ = 0; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_RegisterRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_RegisterRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.RegisterRequest.class, agent.CollectorOuterClass.RegisterRequest.Builder.class); + } + + public static final int IP_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object ip_ = ""; + /** + * string ip = 1; + * @return The ip. + */ + @java.lang.Override + public java.lang.String getIp() { + java.lang.Object ref = ip_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + ip_ = s; + return s; + } + } + /** + * string ip = 1; + * @return The bytes for ip. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIpBytes() { + java.lang.Object ref = ip_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + ip_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HOSTNAME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object hostname_ = ""; + /** + * string hostname = 2; + * @return The hostname. + */ + @java.lang.Override + public java.lang.String getHostname() { + java.lang.Object ref = hostname_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + hostname_ = s; + return s; + } + } + /** + * string hostname = 2; + * @return The bytes for hostname. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getHostnameBytes() { + java.lang.Object ref = hostname_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + hostname_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int VERSION_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object version_ = ""; + /** + * string version = 3; + * @return The version. + */ + @java.lang.Override + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } + } + /** + * string version = 3; + * @return The bytes for version. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int COLLECTOR_FIELD_NUMBER = 4; + private int collector_ = 0; + /** + * .agent.CollectorModule collector = 4; + * @return The enum numeric value on the wire for collector. + */ + @java.lang.Override public int getCollectorValue() { + return collector_; + } + /** + * .agent.CollectorModule collector = 4; + * @return The collector. + */ + @java.lang.Override public agent.CollectorOuterClass.CollectorModule getCollector() { + agent.CollectorOuterClass.CollectorModule result = agent.CollectorOuterClass.CollectorModule.forNumber(collector_); + return result == null ? agent.CollectorOuterClass.CollectorModule.UNRECOGNIZED : result; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(ip_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, ip_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(hostname_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, hostname_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, version_); + } + if (collector_ != agent.CollectorOuterClass.CollectorModule.AS_400.getNumber()) { + output.writeEnum(4, collector_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(ip_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, ip_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(hostname_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, hostname_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, version_); + } + if (collector_ != agent.CollectorOuterClass.CollectorModule.AS_400.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(4, collector_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof agent.CollectorOuterClass.RegisterRequest)) { + return super.equals(obj); + } + agent.CollectorOuterClass.RegisterRequest other = (agent.CollectorOuterClass.RegisterRequest) obj; + + if (!getIp() + .equals(other.getIp())) return false; + if (!getHostname() + .equals(other.getHostname())) return false; + if (!getVersion() + .equals(other.getVersion())) return false; + if (collector_ != other.collector_) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + IP_FIELD_NUMBER; + hash = (53 * hash) + getIp().hashCode(); + hash = (37 * hash) + HOSTNAME_FIELD_NUMBER; + hash = (53 * hash) + getHostname().hashCode(); + hash = (37 * hash) + VERSION_FIELD_NUMBER; + hash = (53 * hash) + getVersion().hashCode(); + hash = (37 * hash) + COLLECTOR_FIELD_NUMBER; + hash = (53 * hash) + collector_; + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static agent.CollectorOuterClass.RegisterRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.RegisterRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.RegisterRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.RegisterRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.RegisterRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.RegisterRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.RegisterRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.RegisterRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static agent.CollectorOuterClass.RegisterRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static agent.CollectorOuterClass.RegisterRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static agent.CollectorOuterClass.RegisterRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.RegisterRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(agent.CollectorOuterClass.RegisterRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code agent.RegisterRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:agent.RegisterRequest) + agent.CollectorOuterClass.RegisterRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_RegisterRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_RegisterRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.RegisterRequest.class, agent.CollectorOuterClass.RegisterRequest.Builder.class); + } + + // Construct using agent.CollectorOuterClass.RegisterRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + ip_ = ""; + hostname_ = ""; + version_ = ""; + collector_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return agent.CollectorOuterClass.internal_static_agent_RegisterRequest_descriptor; + } + + @java.lang.Override + public agent.CollectorOuterClass.RegisterRequest getDefaultInstanceForType() { + return agent.CollectorOuterClass.RegisterRequest.getDefaultInstance(); + } + + @java.lang.Override + public agent.CollectorOuterClass.RegisterRequest build() { + agent.CollectorOuterClass.RegisterRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public agent.CollectorOuterClass.RegisterRequest buildPartial() { + agent.CollectorOuterClass.RegisterRequest result = new agent.CollectorOuterClass.RegisterRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(agent.CollectorOuterClass.RegisterRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.ip_ = ip_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.hostname_ = hostname_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.version_ = version_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.collector_ = collector_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof agent.CollectorOuterClass.RegisterRequest) { + return mergeFrom((agent.CollectorOuterClass.RegisterRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(agent.CollectorOuterClass.RegisterRequest other) { + if (other == agent.CollectorOuterClass.RegisterRequest.getDefaultInstance()) return this; + if (!other.getIp().isEmpty()) { + ip_ = other.ip_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getHostname().isEmpty()) { + hostname_ = other.hostname_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getVersion().isEmpty()) { + version_ = other.version_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (other.collector_ != 0) { + setCollectorValue(other.getCollectorValue()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + ip_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + hostname_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + version_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 32: { + collector_ = input.readEnum(); + bitField0_ |= 0x00000008; + break; + } // case 32 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object ip_ = ""; + /** + * string ip = 1; + * @return The ip. + */ + public java.lang.String getIp() { + java.lang.Object ref = ip_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + ip_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string ip = 1; + * @return The bytes for ip. + */ + public com.google.protobuf.ByteString + getIpBytes() { + java.lang.Object ref = ip_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + ip_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string ip = 1; + * @param value The ip to set. + * @return This builder for chaining. + */ + public Builder setIp( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ip_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * string ip = 1; + * @return This builder for chaining. + */ + public Builder clearIp() { + ip_ = getDefaultInstance().getIp(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + * string ip = 1; + * @param value The bytes for ip to set. + * @return This builder for chaining. + */ + public Builder setIpBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ip_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object hostname_ = ""; + /** + * string hostname = 2; + * @return The hostname. + */ + public java.lang.String getHostname() { + java.lang.Object ref = hostname_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + hostname_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string hostname = 2; + * @return The bytes for hostname. + */ + public com.google.protobuf.ByteString + getHostnameBytes() { + java.lang.Object ref = hostname_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + hostname_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string hostname = 2; + * @param value The hostname to set. + * @return This builder for chaining. + */ + public Builder setHostname( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + hostname_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * string hostname = 2; + * @return This builder for chaining. + */ + public Builder clearHostname() { + hostname_ = getDefaultInstance().getHostname(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + * string hostname = 2; + * @param value The bytes for hostname to set. + * @return This builder for chaining. + */ + public Builder setHostnameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + hostname_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object version_ = ""; + /** + * string version = 3; + * @return The version. + */ + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string version = 3; + * @return The bytes for version. + */ + public com.google.protobuf.ByteString + getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string version = 3; + * @param value The version to set. + * @return This builder for chaining. + */ + public Builder setVersion( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + version_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * string version = 3; + * @return This builder for chaining. + */ + public Builder clearVersion() { + version_ = getDefaultInstance().getVersion(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + * string version = 3; + * @param value The bytes for version to set. + * @return This builder for chaining. + */ + public Builder setVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + version_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private int collector_ = 0; + /** + * .agent.CollectorModule collector = 4; + * @return The enum numeric value on the wire for collector. + */ + @java.lang.Override public int getCollectorValue() { + return collector_; + } + /** + * .agent.CollectorModule collector = 4; + * @param value The enum numeric value on the wire for collector to set. + * @return This builder for chaining. + */ + public Builder setCollectorValue(int value) { + collector_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + * .agent.CollectorModule collector = 4; + * @return The collector. + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorModule getCollector() { + agent.CollectorOuterClass.CollectorModule result = agent.CollectorOuterClass.CollectorModule.forNumber(collector_); + return result == null ? agent.CollectorOuterClass.CollectorModule.UNRECOGNIZED : result; + } + /** + * .agent.CollectorModule collector = 4; + * @param value The collector to set. + * @return This builder for chaining. + */ + public Builder setCollector(agent.CollectorOuterClass.CollectorModule value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + collector_ = value.getNumber(); + onChanged(); + return this; + } + /** + * .agent.CollectorModule collector = 4; + * @return This builder for chaining. + */ + public Builder clearCollector() { + bitField0_ = (bitField0_ & ~0x00000008); + collector_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:agent.RegisterRequest) + } + + // @@protoc_insertion_point(class_scope:agent.RegisterRequest) + private static final agent.CollectorOuterClass.RegisterRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new agent.CollectorOuterClass.RegisterRequest(); + } + + public static agent.CollectorOuterClass.RegisterRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public RegisterRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public agent.CollectorOuterClass.RegisterRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface ListCollectorResponseOrBuilder extends + // @@protoc_insertion_point(interface_extends:agent.ListCollectorResponse) + com.google.protobuf.MessageOrBuilder { + + /** + * repeated .agent.Collector rows = 1; + */ + java.util.List + getRowsList(); + /** + * repeated .agent.Collector rows = 1; + */ + agent.CollectorOuterClass.Collector getRows(int index); + /** + * repeated .agent.Collector rows = 1; + */ + int getRowsCount(); + /** + * repeated .agent.Collector rows = 1; + */ + java.util.List + getRowsOrBuilderList(); + /** + * repeated .agent.Collector rows = 1; + */ + agent.CollectorOuterClass.CollectorOrBuilder getRowsOrBuilder( + int index); + + /** + * int32 total = 2; + * @return The total. + */ + int getTotal(); + } + /** + * Protobuf type {@code agent.ListCollectorResponse} + */ + public static final class ListCollectorResponse extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:agent.ListCollectorResponse) + ListCollectorResponseOrBuilder { + private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + ListCollectorResponse.class.getName()); + } + // Use ListCollectorResponse.newBuilder() to construct. + private ListCollectorResponse(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ListCollectorResponse() { + rows_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_ListCollectorResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_ListCollectorResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.ListCollectorResponse.class, agent.CollectorOuterClass.ListCollectorResponse.Builder.class); + } + + public static final int ROWS_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private java.util.List rows_; + /** + * repeated .agent.Collector rows = 1; + */ + @java.lang.Override + public java.util.List getRowsList() { + return rows_; + } + /** + * repeated .agent.Collector rows = 1; + */ + @java.lang.Override + public java.util.List + getRowsOrBuilderList() { + return rows_; + } + /** + * repeated .agent.Collector rows = 1; + */ + @java.lang.Override + public int getRowsCount() { + return rows_.size(); + } + /** + * repeated .agent.Collector rows = 1; + */ + @java.lang.Override + public agent.CollectorOuterClass.Collector getRows(int index) { + return rows_.get(index); + } + /** + * repeated .agent.Collector rows = 1; + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorOrBuilder getRowsOrBuilder( + int index) { + return rows_.get(index); + } + + public static final int TOTAL_FIELD_NUMBER = 2; + private int total_ = 0; + /** + * int32 total = 2; + * @return The total. + */ + @java.lang.Override + public int getTotal() { + return total_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + for (int i = 0; i < rows_.size(); i++) { + output.writeMessage(1, rows_.get(i)); + } + if (total_ != 0) { + output.writeInt32(2, total_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + for (int i = 0; i < rows_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, rows_.get(i)); + } + if (total_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, total_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof agent.CollectorOuterClass.ListCollectorResponse)) { + return super.equals(obj); + } + agent.CollectorOuterClass.ListCollectorResponse other = (agent.CollectorOuterClass.ListCollectorResponse) obj; + + if (!getRowsList() + .equals(other.getRowsList())) return false; + if (getTotal() + != other.getTotal()) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + if (getRowsCount() > 0) { + hash = (37 * hash) + ROWS_FIELD_NUMBER; + hash = (53 * hash) + getRowsList().hashCode(); + } + hash = (37 * hash) + TOTAL_FIELD_NUMBER; + hash = (53 * hash) + getTotal(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static agent.CollectorOuterClass.ListCollectorResponse parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static agent.CollectorOuterClass.ListCollectorResponse parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.ListCollectorResponse parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(agent.CollectorOuterClass.ListCollectorResponse prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code agent.ListCollectorResponse} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:agent.ListCollectorResponse) + agent.CollectorOuterClass.ListCollectorResponseOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_ListCollectorResponse_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_ListCollectorResponse_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.ListCollectorResponse.class, agent.CollectorOuterClass.ListCollectorResponse.Builder.class); + } + + // Construct using agent.CollectorOuterClass.ListCollectorResponse.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (rowsBuilder_ == null) { + rows_ = java.util.Collections.emptyList(); + } else { + rows_ = null; + rowsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + total_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return agent.CollectorOuterClass.internal_static_agent_ListCollectorResponse_descriptor; + } + + @java.lang.Override + public agent.CollectorOuterClass.ListCollectorResponse getDefaultInstanceForType() { + return agent.CollectorOuterClass.ListCollectorResponse.getDefaultInstance(); + } + + @java.lang.Override + public agent.CollectorOuterClass.ListCollectorResponse build() { + agent.CollectorOuterClass.ListCollectorResponse result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public agent.CollectorOuterClass.ListCollectorResponse buildPartial() { + agent.CollectorOuterClass.ListCollectorResponse result = new agent.CollectorOuterClass.ListCollectorResponse(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(agent.CollectorOuterClass.ListCollectorResponse result) { + if (rowsBuilder_ == null) { + if (((bitField0_ & 0x00000001) != 0)) { + rows_ = java.util.Collections.unmodifiableList(rows_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.rows_ = rows_; + } else { + result.rows_ = rowsBuilder_.build(); + } + } + + private void buildPartial0(agent.CollectorOuterClass.ListCollectorResponse result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000002) != 0)) { + result.total_ = total_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof agent.CollectorOuterClass.ListCollectorResponse) { + return mergeFrom((agent.CollectorOuterClass.ListCollectorResponse)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(agent.CollectorOuterClass.ListCollectorResponse other) { + if (other == agent.CollectorOuterClass.ListCollectorResponse.getDefaultInstance()) return this; + if (rowsBuilder_ == null) { + if (!other.rows_.isEmpty()) { + if (rows_.isEmpty()) { + rows_ = other.rows_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureRowsIsMutable(); + rows_.addAll(other.rows_); + } + onChanged(); + } + } else { + if (!other.rows_.isEmpty()) { + if (rowsBuilder_.isEmpty()) { + rowsBuilder_.dispose(); + rowsBuilder_ = null; + rows_ = other.rows_; + bitField0_ = (bitField0_ & ~0x00000001); + rowsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + getRowsFieldBuilder() : null; + } else { + rowsBuilder_.addAllMessages(other.rows_); + } + } + } + if (other.getTotal() != 0) { + setTotal(other.getTotal()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + agent.CollectorOuterClass.Collector m = + input.readMessage( + agent.CollectorOuterClass.Collector.parser(), + extensionRegistry); + if (rowsBuilder_ == null) { + ensureRowsIsMutable(); + rows_.add(m); + } else { + rowsBuilder_.addMessage(m); + } + break; + } // case 10 + case 16: { + total_ = input.readInt32(); + bitField0_ |= 0x00000002; + break; + } // case 16 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.util.List rows_ = + java.util.Collections.emptyList(); + private void ensureRowsIsMutable() { + if (!((bitField0_ & 0x00000001) != 0)) { + rows_ = new java.util.ArrayList(rows_); + bitField0_ |= 0x00000001; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + agent.CollectorOuterClass.Collector, agent.CollectorOuterClass.Collector.Builder, agent.CollectorOuterClass.CollectorOrBuilder> rowsBuilder_; + + /** + * repeated .agent.Collector rows = 1; + */ + public java.util.List getRowsList() { + if (rowsBuilder_ == null) { + return java.util.Collections.unmodifiableList(rows_); + } else { + return rowsBuilder_.getMessageList(); + } + } + /** + * repeated .agent.Collector rows = 1; + */ + public int getRowsCount() { + if (rowsBuilder_ == null) { + return rows_.size(); + } else { + return rowsBuilder_.getCount(); + } + } + /** + * repeated .agent.Collector rows = 1; + */ + public agent.CollectorOuterClass.Collector getRows(int index) { + if (rowsBuilder_ == null) { + return rows_.get(index); + } else { + return rowsBuilder_.getMessage(index); + } + } + /** + * repeated .agent.Collector rows = 1; + */ + public Builder setRows( + int index, agent.CollectorOuterClass.Collector value) { + if (rowsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureRowsIsMutable(); + rows_.set(index, value); + onChanged(); + } else { + rowsBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .agent.Collector rows = 1; + */ + public Builder setRows( + int index, agent.CollectorOuterClass.Collector.Builder builderForValue) { + if (rowsBuilder_ == null) { + ensureRowsIsMutable(); + rows_.set(index, builderForValue.build()); + onChanged(); + } else { + rowsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .agent.Collector rows = 1; + */ + public Builder addRows(agent.CollectorOuterClass.Collector value) { + if (rowsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureRowsIsMutable(); + rows_.add(value); + onChanged(); + } else { + rowsBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .agent.Collector rows = 1; + */ + public Builder addRows( + int index, agent.CollectorOuterClass.Collector value) { + if (rowsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureRowsIsMutable(); + rows_.add(index, value); + onChanged(); + } else { + rowsBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .agent.Collector rows = 1; + */ + public Builder addRows( + agent.CollectorOuterClass.Collector.Builder builderForValue) { + if (rowsBuilder_ == null) { + ensureRowsIsMutable(); + rows_.add(builderForValue.build()); + onChanged(); + } else { + rowsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .agent.Collector rows = 1; + */ + public Builder addRows( + int index, agent.CollectorOuterClass.Collector.Builder builderForValue) { + if (rowsBuilder_ == null) { + ensureRowsIsMutable(); + rows_.add(index, builderForValue.build()); + onChanged(); + } else { + rowsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .agent.Collector rows = 1; + */ + public Builder addAllRows( + java.lang.Iterable values) { + if (rowsBuilder_ == null) { + ensureRowsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, rows_); + onChanged(); + } else { + rowsBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .agent.Collector rows = 1; + */ + public Builder clearRows() { + if (rowsBuilder_ == null) { + rows_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + } else { + rowsBuilder_.clear(); + } + return this; + } + /** + * repeated .agent.Collector rows = 1; + */ + public Builder removeRows(int index) { + if (rowsBuilder_ == null) { + ensureRowsIsMutable(); + rows_.remove(index); + onChanged(); + } else { + rowsBuilder_.remove(index); + } + return this; + } + /** + * repeated .agent.Collector rows = 1; + */ + public agent.CollectorOuterClass.Collector.Builder getRowsBuilder( + int index) { + return getRowsFieldBuilder().getBuilder(index); + } + /** + * repeated .agent.Collector rows = 1; + */ + public agent.CollectorOuterClass.CollectorOrBuilder getRowsOrBuilder( + int index) { + if (rowsBuilder_ == null) { + return rows_.get(index); } else { + return rowsBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .agent.Collector rows = 1; + */ + public java.util.List + getRowsOrBuilderList() { + if (rowsBuilder_ != null) { + return rowsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(rows_); + } + } + /** + * repeated .agent.Collector rows = 1; + */ + public agent.CollectorOuterClass.Collector.Builder addRowsBuilder() { + return getRowsFieldBuilder().addBuilder( + agent.CollectorOuterClass.Collector.getDefaultInstance()); + } + /** + * repeated .agent.Collector rows = 1; + */ + public agent.CollectorOuterClass.Collector.Builder addRowsBuilder( + int index) { + return getRowsFieldBuilder().addBuilder( + index, agent.CollectorOuterClass.Collector.getDefaultInstance()); + } + /** + * repeated .agent.Collector rows = 1; + */ + public java.util.List + getRowsBuilderList() { + return getRowsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + agent.CollectorOuterClass.Collector, agent.CollectorOuterClass.Collector.Builder, agent.CollectorOuterClass.CollectorOrBuilder> + getRowsFieldBuilder() { + if (rowsBuilder_ == null) { + rowsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + agent.CollectorOuterClass.Collector, agent.CollectorOuterClass.Collector.Builder, agent.CollectorOuterClass.CollectorOrBuilder>( + rows_, + ((bitField0_ & 0x00000001) != 0), + getParentForChildren(), + isClean()); + rows_ = null; + } + return rowsBuilder_; + } + + private int total_ ; + /** + * int32 total = 2; + * @return The total. + */ + @java.lang.Override + public int getTotal() { + return total_; + } + /** + * int32 total = 2; + * @param value The total to set. + * @return This builder for chaining. + */ + public Builder setTotal(int value) { + + total_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * int32 total = 2; + * @return This builder for chaining. + */ + public Builder clearTotal() { + bitField0_ = (bitField0_ & ~0x00000002); + total_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:agent.ListCollectorResponse) + } + + // @@protoc_insertion_point(class_scope:agent.ListCollectorResponse) + private static final agent.CollectorOuterClass.ListCollectorResponse DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new agent.CollectorOuterClass.ListCollectorResponse(); + } + + public static agent.CollectorOuterClass.ListCollectorResponse getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ListCollectorResponse parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public agent.CollectorOuterClass.ListCollectorResponse getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface CollectorOrBuilder extends + // @@protoc_insertion_point(interface_extends:agent.Collector) + com.google.protobuf.MessageOrBuilder { + + /** + * int32 id = 1; + * @return The id. + */ + int getId(); + + /** + * .agent.Status status = 2; + * @return The enum numeric value on the wire for status. + */ + int getStatusValue(); + /** + * .agent.Status status = 2; + * @return The status. + */ + com.park.utmstack.service.grpc.Status getStatus(); + + /** + * string collector_key = 3; + * @return The collectorKey. + */ + java.lang.String getCollectorKey(); + /** + * string collector_key = 3; + * @return The bytes for collectorKey. + */ + com.google.protobuf.ByteString + getCollectorKeyBytes(); + + /** + * string ip = 4; + * @return The ip. + */ + java.lang.String getIp(); + /** + * string ip = 4; + * @return The bytes for ip. + */ + com.google.protobuf.ByteString + getIpBytes(); + + /** + * string hostname = 5; + * @return The hostname. + */ + java.lang.String getHostname(); + /** + * string hostname = 5; + * @return The bytes for hostname. + */ + com.google.protobuf.ByteString + getHostnameBytes(); + + /** + * string version = 6; + * @return The version. + */ + java.lang.String getVersion(); + /** + * string version = 6; + * @return The bytes for version. + */ + com.google.protobuf.ByteString + getVersionBytes(); + + /** + * .agent.CollectorModule module = 7; + * @return The enum numeric value on the wire for module. + */ + int getModuleValue(); + /** + * .agent.CollectorModule module = 7; + * @return The module. + */ + agent.CollectorOuterClass.CollectorModule getModule(); + + /** + * string last_seen = 8; + * @return The lastSeen. + */ + java.lang.String getLastSeen(); + /** + * string last_seen = 8; + * @return The bytes for lastSeen. + */ + com.google.protobuf.ByteString + getLastSeenBytes(); + } + /** + * Protobuf type {@code agent.Collector} + */ + public static final class Collector extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:agent.Collector) + CollectorOrBuilder { + private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + Collector.class.getName()); + } + // Use Collector.newBuilder() to construct. + private Collector(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private Collector() { + status_ = 0; + collectorKey_ = ""; + ip_ = ""; + hostname_ = ""; + version_ = ""; + module_ = 0; + lastSeen_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_Collector_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_Collector_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.Collector.class, agent.CollectorOuterClass.Collector.Builder.class); + } + + public static final int ID_FIELD_NUMBER = 1; + private int id_ = 0; + /** + * int32 id = 1; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + + public static final int STATUS_FIELD_NUMBER = 2; + private int status_ = 0; + /** + * .agent.Status status = 2; + * @return The enum numeric value on the wire for status. + */ + @java.lang.Override public int getStatusValue() { + return status_; + } + /** + * .agent.Status status = 2; + * @return The status. + */ + @java.lang.Override public com.park.utmstack.service.grpc.Status getStatus() { + com.park.utmstack.service.grpc.Status result = com.park.utmstack.service.grpc.Status.forNumber(status_); + return result == null ? com.park.utmstack.service.grpc.Status.UNRECOGNIZED : result; + } + + public static final int COLLECTOR_KEY_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object collectorKey_ = ""; + /** + * string collector_key = 3; + * @return The collectorKey. + */ + @java.lang.Override + public java.lang.String getCollectorKey() { + java.lang.Object ref = collectorKey_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + collectorKey_ = s; + return s; + } + } + /** + * string collector_key = 3; + * @return The bytes for collectorKey. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getCollectorKeyBytes() { + java.lang.Object ref = collectorKey_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + collectorKey_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int IP_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private volatile java.lang.Object ip_ = ""; + /** + * string ip = 4; + * @return The ip. + */ + @java.lang.Override + public java.lang.String getIp() { + java.lang.Object ref = ip_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + ip_ = s; + return s; + } + } + /** + * string ip = 4; + * @return The bytes for ip. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getIpBytes() { + java.lang.Object ref = ip_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + ip_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int HOSTNAME_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private volatile java.lang.Object hostname_ = ""; + /** + * string hostname = 5; + * @return The hostname. + */ + @java.lang.Override + public java.lang.String getHostname() { + java.lang.Object ref = hostname_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + hostname_ = s; + return s; + } + } + /** + * string hostname = 5; + * @return The bytes for hostname. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getHostnameBytes() { + java.lang.Object ref = hostname_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + hostname_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int VERSION_FIELD_NUMBER = 6; + @SuppressWarnings("serial") + private volatile java.lang.Object version_ = ""; + /** + * string version = 6; + * @return The version. + */ + @java.lang.Override + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } + } + /** + * string version = 6; + * @return The bytes for version. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int MODULE_FIELD_NUMBER = 7; + private int module_ = 0; + /** + * .agent.CollectorModule module = 7; + * @return The enum numeric value on the wire for module. + */ + @java.lang.Override public int getModuleValue() { + return module_; + } + /** + * .agent.CollectorModule module = 7; + * @return The module. + */ + @java.lang.Override public agent.CollectorOuterClass.CollectorModule getModule() { + agent.CollectorOuterClass.CollectorModule result = agent.CollectorOuterClass.CollectorModule.forNumber(module_); + return result == null ? agent.CollectorOuterClass.CollectorModule.UNRECOGNIZED : result; + } + + public static final int LAST_SEEN_FIELD_NUMBER = 8; + @SuppressWarnings("serial") + private volatile java.lang.Object lastSeen_ = ""; + /** + * string last_seen = 8; + * @return The lastSeen. + */ + @java.lang.Override + public java.lang.String getLastSeen() { + java.lang.Object ref = lastSeen_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + lastSeen_ = s; + return s; + } + } + /** + * string last_seen = 8; + * @return The bytes for lastSeen. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getLastSeenBytes() { + java.lang.Object ref = lastSeen_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + lastSeen_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (id_ != 0) { + output.writeInt32(1, id_); + } + if (status_ != com.park.utmstack.service.grpc.Status.ONLINE.getNumber()) { + output.writeEnum(2, status_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(collectorKey_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, collectorKey_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(ip_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 4, ip_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(hostname_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 5, hostname_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 6, version_); + } + if (module_ != agent.CollectorOuterClass.CollectorModule.AS_400.getNumber()) { + output.writeEnum(7, module_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(lastSeen_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 8, lastSeen_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (id_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(1, id_); + } + if (status_ != com.park.utmstack.service.grpc.Status.ONLINE.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, status_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(collectorKey_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, collectorKey_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(ip_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(4, ip_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(hostname_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(5, hostname_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(version_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(6, version_); + } + if (module_ != agent.CollectorOuterClass.CollectorModule.AS_400.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(7, module_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(lastSeen_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(8, lastSeen_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof agent.CollectorOuterClass.Collector)) { + return super.equals(obj); + } + agent.CollectorOuterClass.Collector other = (agent.CollectorOuterClass.Collector) obj; + + if (getId() + != other.getId()) return false; + if (status_ != other.status_) return false; + if (!getCollectorKey() + .equals(other.getCollectorKey())) return false; + if (!getIp() + .equals(other.getIp())) return false; + if (!getHostname() + .equals(other.getHostname())) return false; + if (!getVersion() + .equals(other.getVersion())) return false; + if (module_ != other.module_) return false; + if (!getLastSeen() + .equals(other.getLastSeen())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId(); + hash = (37 * hash) + STATUS_FIELD_NUMBER; + hash = (53 * hash) + status_; + hash = (37 * hash) + COLLECTOR_KEY_FIELD_NUMBER; + hash = (53 * hash) + getCollectorKey().hashCode(); + hash = (37 * hash) + IP_FIELD_NUMBER; + hash = (53 * hash) + getIp().hashCode(); + hash = (37 * hash) + HOSTNAME_FIELD_NUMBER; + hash = (53 * hash) + getHostname().hashCode(); + hash = (37 * hash) + VERSION_FIELD_NUMBER; + hash = (53 * hash) + getVersion().hashCode(); + hash = (37 * hash) + MODULE_FIELD_NUMBER; + hash = (53 * hash) + module_; + hash = (37 * hash) + LAST_SEEN_FIELD_NUMBER; + hash = (53 * hash) + getLastSeen().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static agent.CollectorOuterClass.Collector parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.Collector parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.Collector parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.Collector parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.Collector parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.Collector parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.Collector parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.Collector parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static agent.CollectorOuterClass.Collector parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static agent.CollectorOuterClass.Collector parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static agent.CollectorOuterClass.Collector parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.Collector parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(agent.CollectorOuterClass.Collector prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code agent.Collector} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:agent.Collector) + agent.CollectorOuterClass.CollectorOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_Collector_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_Collector_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.Collector.class, agent.CollectorOuterClass.Collector.Builder.class); + } + + // Construct using agent.CollectorOuterClass.Collector.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = 0; + status_ = 0; + collectorKey_ = ""; + ip_ = ""; + hostname_ = ""; + version_ = ""; + module_ = 0; + lastSeen_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return agent.CollectorOuterClass.internal_static_agent_Collector_descriptor; + } + + @java.lang.Override + public agent.CollectorOuterClass.Collector getDefaultInstanceForType() { + return agent.CollectorOuterClass.Collector.getDefaultInstance(); + } + + @java.lang.Override + public agent.CollectorOuterClass.Collector build() { + agent.CollectorOuterClass.Collector result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public agent.CollectorOuterClass.Collector buildPartial() { + agent.CollectorOuterClass.Collector result = new agent.CollectorOuterClass.Collector(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(agent.CollectorOuterClass.Collector result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.status_ = status_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.collectorKey_ = collectorKey_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.ip_ = ip_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.hostname_ = hostname_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.version_ = version_; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + result.module_ = module_; + } + if (((from_bitField0_ & 0x00000080) != 0)) { + result.lastSeen_ = lastSeen_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof agent.CollectorOuterClass.Collector) { + return mergeFrom((agent.CollectorOuterClass.Collector)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(agent.CollectorOuterClass.Collector other) { + if (other == agent.CollectorOuterClass.Collector.getDefaultInstance()) return this; + if (other.getId() != 0) { + setId(other.getId()); + } + if (other.status_ != 0) { + setStatusValue(other.getStatusValue()); + } + if (!other.getCollectorKey().isEmpty()) { + collectorKey_ = other.collectorKey_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (!other.getIp().isEmpty()) { + ip_ = other.ip_; + bitField0_ |= 0x00000008; + onChanged(); + } + if (!other.getHostname().isEmpty()) { + hostname_ = other.hostname_; + bitField0_ |= 0x00000010; + onChanged(); + } + if (!other.getVersion().isEmpty()) { + version_ = other.version_; + bitField0_ |= 0x00000020; + onChanged(); + } + if (other.module_ != 0) { + setModuleValue(other.getModuleValue()); + } + if (!other.getLastSeen().isEmpty()) { + lastSeen_ = other.lastSeen_; + bitField0_ |= 0x00000080; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + id_ = input.readInt32(); + bitField0_ |= 0x00000001; + break; + } // case 8 + case 16: { + status_ = input.readEnum(); + bitField0_ |= 0x00000002; + break; + } // case 16 + case 26: { + collectorKey_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + ip_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000008; + break; + } // case 34 + case 42: { + hostname_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 50: { + version_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000020; + break; + } // case 50 + case 56: { + module_ = input.readEnum(); + bitField0_ |= 0x00000040; + break; + } // case 56 + case 66: { + lastSeen_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000080; + break; + } // case 66 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private int id_ ; + /** + * int32 id = 1; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + /** + * int32 id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId(int value) { + + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * int32 id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0; + onChanged(); + return this; + } + + private int status_ = 0; + /** + * .agent.Status status = 2; + * @return The enum numeric value on the wire for status. + */ + @java.lang.Override public int getStatusValue() { + return status_; + } + /** + * .agent.Status status = 2; + * @param value The enum numeric value on the wire for status to set. + * @return This builder for chaining. + */ + public Builder setStatusValue(int value) { + status_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * .agent.Status status = 2; + * @return The status. + */ + @java.lang.Override + public com.park.utmstack.service.grpc.Status getStatus() { + com.park.utmstack.service.grpc.Status result = com.park.utmstack.service.grpc.Status.forNumber(status_); + return result == null ? com.park.utmstack.service.grpc.Status.UNRECOGNIZED : result; + } + /** + * .agent.Status status = 2; + * @param value The status to set. + * @return This builder for chaining. + */ + public Builder setStatus(com.park.utmstack.service.grpc.Status value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + status_ = value.getNumber(); + onChanged(); + return this; + } + /** + * .agent.Status status = 2; + * @return This builder for chaining. + */ + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000002); + status_ = 0; + onChanged(); + return this; + } + + private java.lang.Object collectorKey_ = ""; + /** + * string collector_key = 3; + * @return The collectorKey. + */ + public java.lang.String getCollectorKey() { + java.lang.Object ref = collectorKey_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + collectorKey_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string collector_key = 3; + * @return The bytes for collectorKey. + */ + public com.google.protobuf.ByteString + getCollectorKeyBytes() { + java.lang.Object ref = collectorKey_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + collectorKey_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string collector_key = 3; + * @param value The collectorKey to set. + * @return This builder for chaining. + */ + public Builder setCollectorKey( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + collectorKey_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * string collector_key = 3; + * @return This builder for chaining. + */ + public Builder clearCollectorKey() { + collectorKey_ = getDefaultInstance().getCollectorKey(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + * string collector_key = 3; + * @param value The bytes for collectorKey to set. + * @return This builder for chaining. + */ + public Builder setCollectorKeyBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + collectorKey_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.lang.Object ip_ = ""; + /** + * string ip = 4; + * @return The ip. + */ + public java.lang.String getIp() { + java.lang.Object ref = ip_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + ip_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string ip = 4; + * @return The bytes for ip. + */ + public com.google.protobuf.ByteString + getIpBytes() { + java.lang.Object ref = ip_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + ip_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string ip = 4; + * @param value The ip to set. + * @return This builder for chaining. + */ + public Builder setIp( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + ip_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + * string ip = 4; + * @return This builder for chaining. + */ + public Builder clearIp() { + ip_ = getDefaultInstance().getIp(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + return this; + } + /** + * string ip = 4; + * @param value The bytes for ip to set. + * @return This builder for chaining. + */ + public Builder setIpBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + ip_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + private java.lang.Object hostname_ = ""; + /** + * string hostname = 5; + * @return The hostname. + */ + public java.lang.String getHostname() { + java.lang.Object ref = hostname_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + hostname_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string hostname = 5; + * @return The bytes for hostname. + */ + public com.google.protobuf.ByteString + getHostnameBytes() { + java.lang.Object ref = hostname_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + hostname_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string hostname = 5; + * @param value The hostname to set. + * @return This builder for chaining. + */ + public Builder setHostname( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + hostname_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + * string hostname = 5; + * @return This builder for chaining. + */ + public Builder clearHostname() { + hostname_ = getDefaultInstance().getHostname(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + return this; + } + /** + * string hostname = 5; + * @param value The bytes for hostname to set. + * @return This builder for chaining. + */ + public Builder setHostnameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + hostname_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private java.lang.Object version_ = ""; + /** + * string version = 6; + * @return The version. + */ + public java.lang.String getVersion() { + java.lang.Object ref = version_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + version_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string version = 6; + * @return The bytes for version. + */ + public com.google.protobuf.ByteString + getVersionBytes() { + java.lang.Object ref = version_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string version = 6; + * @param value The version to set. + * @return This builder for chaining. + */ + public Builder setVersion( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + version_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + * string version = 6; + * @return This builder for chaining. + */ + public Builder clearVersion() { + version_ = getDefaultInstance().getVersion(); + bitField0_ = (bitField0_ & ~0x00000020); + onChanged(); + return this; + } + /** + * string version = 6; + * @param value The bytes for version to set. + * @return This builder for chaining. + */ + public Builder setVersionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + version_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + private int module_ = 0; + /** + * .agent.CollectorModule module = 7; + * @return The enum numeric value on the wire for module. + */ + @java.lang.Override public int getModuleValue() { + return module_; + } + /** + * .agent.CollectorModule module = 7; + * @param value The enum numeric value on the wire for module to set. + * @return This builder for chaining. + */ + public Builder setModuleValue(int value) { + module_ = value; + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + * .agent.CollectorModule module = 7; + * @return The module. + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorModule getModule() { + agent.CollectorOuterClass.CollectorModule result = agent.CollectorOuterClass.CollectorModule.forNumber(module_); + return result == null ? agent.CollectorOuterClass.CollectorModule.UNRECOGNIZED : result; + } + /** + * .agent.CollectorModule module = 7; + * @param value The module to set. + * @return This builder for chaining. + */ + public Builder setModule(agent.CollectorOuterClass.CollectorModule value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000040; + module_ = value.getNumber(); + onChanged(); + return this; + } + /** + * .agent.CollectorModule module = 7; + * @return This builder for chaining. + */ + public Builder clearModule() { + bitField0_ = (bitField0_ & ~0x00000040); + module_ = 0; + onChanged(); + return this; + } + + private java.lang.Object lastSeen_ = ""; + /** + * string last_seen = 8; + * @return The lastSeen. + */ + public java.lang.String getLastSeen() { + java.lang.Object ref = lastSeen_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + lastSeen_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string last_seen = 8; + * @return The bytes for lastSeen. + */ + public com.google.protobuf.ByteString + getLastSeenBytes() { + java.lang.Object ref = lastSeen_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + lastSeen_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string last_seen = 8; + * @param value The lastSeen to set. + * @return This builder for chaining. + */ + public Builder setLastSeen( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + lastSeen_ = value; + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + /** + * string last_seen = 8; + * @return This builder for chaining. + */ + public Builder clearLastSeen() { + lastSeen_ = getDefaultInstance().getLastSeen(); + bitField0_ = (bitField0_ & ~0x00000080); + onChanged(); + return this; + } + /** + * string last_seen = 8; + * @param value The bytes for lastSeen to set. + * @return This builder for chaining. + */ + public Builder setLastSeenBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + lastSeen_ = value; + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:agent.Collector) + } + + // @@protoc_insertion_point(class_scope:agent.Collector) + private static final agent.CollectorOuterClass.Collector DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new agent.CollectorOuterClass.Collector(); + } + + public static agent.CollectorOuterClass.Collector getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public Collector parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public agent.CollectorOuterClass.Collector getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface CollectorMessagesOrBuilder extends + // @@protoc_insertion_point(interface_extends:agent.CollectorMessages) + com.google.protobuf.MessageOrBuilder { + + /** + * .agent.CollectorConfig config = 1; + * @return Whether the config field is set. + */ + boolean hasConfig(); + /** + * .agent.CollectorConfig config = 1; + * @return The config. + */ + agent.CollectorOuterClass.CollectorConfig getConfig(); + /** + * .agent.CollectorConfig config = 1; + */ + agent.CollectorOuterClass.CollectorConfigOrBuilder getConfigOrBuilder(); + + /** + * .agent.ConfigKnowledge result = 2; + * @return Whether the result field is set. + */ + boolean hasResult(); + /** + * .agent.ConfigKnowledge result = 2; + * @return The result. + */ + agent.CollectorOuterClass.ConfigKnowledge getResult(); + /** + * .agent.ConfigKnowledge result = 2; + */ + agent.CollectorOuterClass.ConfigKnowledgeOrBuilder getResultOrBuilder(); + + agent.CollectorOuterClass.CollectorMessages.StreamMessageCase getStreamMessageCase(); + } + /** + * Protobuf type {@code agent.CollectorMessages} + */ + public static final class CollectorMessages extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:agent.CollectorMessages) + CollectorMessagesOrBuilder { + private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + CollectorMessages.class.getName()); + } + // Use CollectorMessages.newBuilder() to construct. + private CollectorMessages(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private CollectorMessages() { + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_CollectorMessages_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_CollectorMessages_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.CollectorMessages.class, agent.CollectorOuterClass.CollectorMessages.Builder.class); + } + + private int streamMessageCase_ = 0; + @SuppressWarnings("serial") + private java.lang.Object streamMessage_; + public enum StreamMessageCase + implements com.google.protobuf.Internal.EnumLite, + com.google.protobuf.AbstractMessage.InternalOneOfEnum { + CONFIG(1), + RESULT(2), + STREAMMESSAGE_NOT_SET(0); + private final int value; + private StreamMessageCase(int value) { + this.value = value; + } + /** + * @param value The number of the enum to look for. + * @return The enum associated with the given number. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @java.lang.Deprecated + public static StreamMessageCase valueOf(int value) { + return forNumber(value); + } + + public static StreamMessageCase forNumber(int value) { + switch (value) { + case 1: return CONFIG; + case 2: return RESULT; + case 0: return STREAMMESSAGE_NOT_SET; + default: return null; + } + } + public int getNumber() { + return this.value; + } + }; + + public StreamMessageCase + getStreamMessageCase() { + return StreamMessageCase.forNumber( + streamMessageCase_); + } + + public static final int CONFIG_FIELD_NUMBER = 1; + /** + * .agent.CollectorConfig config = 1; + * @return Whether the config field is set. + */ + @java.lang.Override + public boolean hasConfig() { + return streamMessageCase_ == 1; + } + /** + * .agent.CollectorConfig config = 1; + * @return The config. + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfig getConfig() { + if (streamMessageCase_ == 1) { + return (agent.CollectorOuterClass.CollectorConfig) streamMessage_; + } + return agent.CollectorOuterClass.CollectorConfig.getDefaultInstance(); + } + /** + * .agent.CollectorConfig config = 1; + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfigOrBuilder getConfigOrBuilder() { + if (streamMessageCase_ == 1) { + return (agent.CollectorOuterClass.CollectorConfig) streamMessage_; + } + return agent.CollectorOuterClass.CollectorConfig.getDefaultInstance(); + } + + public static final int RESULT_FIELD_NUMBER = 2; + /** + * .agent.ConfigKnowledge result = 2; + * @return Whether the result field is set. + */ + @java.lang.Override + public boolean hasResult() { + return streamMessageCase_ == 2; + } + /** + * .agent.ConfigKnowledge result = 2; + * @return The result. + */ + @java.lang.Override + public agent.CollectorOuterClass.ConfigKnowledge getResult() { + if (streamMessageCase_ == 2) { + return (agent.CollectorOuterClass.ConfigKnowledge) streamMessage_; + } + return agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance(); + } + /** + * .agent.ConfigKnowledge result = 2; + */ + @java.lang.Override + public agent.CollectorOuterClass.ConfigKnowledgeOrBuilder getResultOrBuilder() { + if (streamMessageCase_ == 2) { + return (agent.CollectorOuterClass.ConfigKnowledge) streamMessage_; + } + return agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance(); + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (streamMessageCase_ == 1) { + output.writeMessage(1, (agent.CollectorOuterClass.CollectorConfig) streamMessage_); + } + if (streamMessageCase_ == 2) { + output.writeMessage(2, (agent.CollectorOuterClass.ConfigKnowledge) streamMessage_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (streamMessageCase_ == 1) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, (agent.CollectorOuterClass.CollectorConfig) streamMessage_); + } + if (streamMessageCase_ == 2) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, (agent.CollectorOuterClass.ConfigKnowledge) streamMessage_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof agent.CollectorOuterClass.CollectorMessages)) { + return super.equals(obj); + } + agent.CollectorOuterClass.CollectorMessages other = (agent.CollectorOuterClass.CollectorMessages) obj; + + if (!getStreamMessageCase().equals(other.getStreamMessageCase())) return false; + switch (streamMessageCase_) { + case 1: + if (!getConfig() + .equals(other.getConfig())) return false; + break; + case 2: + if (!getResult() + .equals(other.getResult())) return false; + break; + case 0: + default: + } + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + switch (streamMessageCase_) { + case 1: + hash = (37 * hash) + CONFIG_FIELD_NUMBER; + hash = (53 * hash) + getConfig().hashCode(); + break; + case 2: + hash = (37 * hash) + RESULT_FIELD_NUMBER; + hash = (53 * hash) + getResult().hashCode(); + break; + case 0: + default: + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static agent.CollectorOuterClass.CollectorMessages parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorMessages parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorMessages parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorMessages parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorMessages parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorMessages parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorMessages parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.CollectorMessages parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static agent.CollectorOuterClass.CollectorMessages parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static agent.CollectorOuterClass.CollectorMessages parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorMessages parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.CollectorMessages parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(agent.CollectorOuterClass.CollectorMessages prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code agent.CollectorMessages} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:agent.CollectorMessages) + agent.CollectorOuterClass.CollectorMessagesOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_CollectorMessages_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_CollectorMessages_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.CollectorMessages.class, agent.CollectorOuterClass.CollectorMessages.Builder.class); + } + + // Construct using agent.CollectorOuterClass.CollectorMessages.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + if (configBuilder_ != null) { + configBuilder_.clear(); + } + if (resultBuilder_ != null) { + resultBuilder_.clear(); + } + streamMessageCase_ = 0; + streamMessage_ = null; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return agent.CollectorOuterClass.internal_static_agent_CollectorMessages_descriptor; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorMessages getDefaultInstanceForType() { + return agent.CollectorOuterClass.CollectorMessages.getDefaultInstance(); + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorMessages build() { + agent.CollectorOuterClass.CollectorMessages result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorMessages buildPartial() { + agent.CollectorOuterClass.CollectorMessages result = new agent.CollectorOuterClass.CollectorMessages(this); + if (bitField0_ != 0) { buildPartial0(result); } + buildPartialOneofs(result); + onBuilt(); + return result; + } + + private void buildPartial0(agent.CollectorOuterClass.CollectorMessages result) { + int from_bitField0_ = bitField0_; + } + + private void buildPartialOneofs(agent.CollectorOuterClass.CollectorMessages result) { + result.streamMessageCase_ = streamMessageCase_; + result.streamMessage_ = this.streamMessage_; + if (streamMessageCase_ == 1 && + configBuilder_ != null) { + result.streamMessage_ = configBuilder_.build(); + } + if (streamMessageCase_ == 2 && + resultBuilder_ != null) { + result.streamMessage_ = resultBuilder_.build(); + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof agent.CollectorOuterClass.CollectorMessages) { + return mergeFrom((agent.CollectorOuterClass.CollectorMessages)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(agent.CollectorOuterClass.CollectorMessages other) { + if (other == agent.CollectorOuterClass.CollectorMessages.getDefaultInstance()) return this; + switch (other.getStreamMessageCase()) { + case CONFIG: { + mergeConfig(other.getConfig()); + break; + } + case RESULT: { + mergeResult(other.getResult()); + break; + } + case STREAMMESSAGE_NOT_SET: { + break; + } + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + input.readMessage( + getConfigFieldBuilder().getBuilder(), + extensionRegistry); + streamMessageCase_ = 1; + break; + } // case 10 + case 18: { + input.readMessage( + getResultFieldBuilder().getBuilder(), + extensionRegistry); + streamMessageCase_ = 2; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int streamMessageCase_ = 0; + private java.lang.Object streamMessage_; + public StreamMessageCase + getStreamMessageCase() { + return StreamMessageCase.forNumber( + streamMessageCase_); + } + + public Builder clearStreamMessage() { + streamMessageCase_ = 0; + streamMessage_ = null; + onChanged(); + return this; + } + + private int bitField0_; + + private com.google.protobuf.SingleFieldBuilder< + agent.CollectorOuterClass.CollectorConfig, agent.CollectorOuterClass.CollectorConfig.Builder, agent.CollectorOuterClass.CollectorConfigOrBuilder> configBuilder_; + /** + * .agent.CollectorConfig config = 1; + * @return Whether the config field is set. + */ + @java.lang.Override + public boolean hasConfig() { + return streamMessageCase_ == 1; + } + /** + * .agent.CollectorConfig config = 1; + * @return The config. + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfig getConfig() { + if (configBuilder_ == null) { + if (streamMessageCase_ == 1) { + return (agent.CollectorOuterClass.CollectorConfig) streamMessage_; + } + return agent.CollectorOuterClass.CollectorConfig.getDefaultInstance(); + } else { + if (streamMessageCase_ == 1) { + return configBuilder_.getMessage(); + } + return agent.CollectorOuterClass.CollectorConfig.getDefaultInstance(); + } + } + /** + * .agent.CollectorConfig config = 1; + */ + public Builder setConfig(agent.CollectorOuterClass.CollectorConfig value) { + if (configBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + streamMessage_ = value; + onChanged(); + } else { + configBuilder_.setMessage(value); + } + streamMessageCase_ = 1; + return this; + } + /** + * .agent.CollectorConfig config = 1; + */ + public Builder setConfig( + agent.CollectorOuterClass.CollectorConfig.Builder builderForValue) { + if (configBuilder_ == null) { + streamMessage_ = builderForValue.build(); + onChanged(); + } else { + configBuilder_.setMessage(builderForValue.build()); + } + streamMessageCase_ = 1; + return this; + } + /** + * .agent.CollectorConfig config = 1; + */ + public Builder mergeConfig(agent.CollectorOuterClass.CollectorConfig value) { + if (configBuilder_ == null) { + if (streamMessageCase_ == 1 && + streamMessage_ != agent.CollectorOuterClass.CollectorConfig.getDefaultInstance()) { + streamMessage_ = agent.CollectorOuterClass.CollectorConfig.newBuilder((agent.CollectorOuterClass.CollectorConfig) streamMessage_) + .mergeFrom(value).buildPartial(); + } else { + streamMessage_ = value; + } + onChanged(); + } else { + if (streamMessageCase_ == 1) { + configBuilder_.mergeFrom(value); + } else { + configBuilder_.setMessage(value); + } + } + streamMessageCase_ = 1; + return this; + } + /** + * .agent.CollectorConfig config = 1; + */ + public Builder clearConfig() { + if (configBuilder_ == null) { + if (streamMessageCase_ == 1) { + streamMessageCase_ = 0; + streamMessage_ = null; + onChanged(); + } + } else { + if (streamMessageCase_ == 1) { + streamMessageCase_ = 0; + streamMessage_ = null; + } + configBuilder_.clear(); + } + return this; + } + /** + * .agent.CollectorConfig config = 1; + */ + public agent.CollectorOuterClass.CollectorConfig.Builder getConfigBuilder() { + return getConfigFieldBuilder().getBuilder(); + } + /** + * .agent.CollectorConfig config = 1; + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfigOrBuilder getConfigOrBuilder() { + if ((streamMessageCase_ == 1) && (configBuilder_ != null)) { + return configBuilder_.getMessageOrBuilder(); + } else { + if (streamMessageCase_ == 1) { + return (agent.CollectorOuterClass.CollectorConfig) streamMessage_; + } + return agent.CollectorOuterClass.CollectorConfig.getDefaultInstance(); + } + } + /** + * .agent.CollectorConfig config = 1; + */ + private com.google.protobuf.SingleFieldBuilder< + agent.CollectorOuterClass.CollectorConfig, agent.CollectorOuterClass.CollectorConfig.Builder, agent.CollectorOuterClass.CollectorConfigOrBuilder> + getConfigFieldBuilder() { + if (configBuilder_ == null) { + if (!(streamMessageCase_ == 1)) { + streamMessage_ = agent.CollectorOuterClass.CollectorConfig.getDefaultInstance(); + } + configBuilder_ = new com.google.protobuf.SingleFieldBuilder< + agent.CollectorOuterClass.CollectorConfig, agent.CollectorOuterClass.CollectorConfig.Builder, agent.CollectorOuterClass.CollectorConfigOrBuilder>( + (agent.CollectorOuterClass.CollectorConfig) streamMessage_, + getParentForChildren(), + isClean()); + streamMessage_ = null; + } + streamMessageCase_ = 1; + onChanged(); + return configBuilder_; + } + + private com.google.protobuf.SingleFieldBuilder< + agent.CollectorOuterClass.ConfigKnowledge, agent.CollectorOuterClass.ConfigKnowledge.Builder, agent.CollectorOuterClass.ConfigKnowledgeOrBuilder> resultBuilder_; + /** + * .agent.ConfigKnowledge result = 2; + * @return Whether the result field is set. + */ + @java.lang.Override + public boolean hasResult() { + return streamMessageCase_ == 2; + } + /** + * .agent.ConfigKnowledge result = 2; + * @return The result. + */ + @java.lang.Override + public agent.CollectorOuterClass.ConfigKnowledge getResult() { + if (resultBuilder_ == null) { + if (streamMessageCase_ == 2) { + return (agent.CollectorOuterClass.ConfigKnowledge) streamMessage_; + } + return agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance(); + } else { + if (streamMessageCase_ == 2) { + return resultBuilder_.getMessage(); + } + return agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance(); + } + } + /** + * .agent.ConfigKnowledge result = 2; + */ + public Builder setResult(agent.CollectorOuterClass.ConfigKnowledge value) { + if (resultBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + streamMessage_ = value; + onChanged(); + } else { + resultBuilder_.setMessage(value); + } + streamMessageCase_ = 2; + return this; + } + /** + * .agent.ConfigKnowledge result = 2; + */ + public Builder setResult( + agent.CollectorOuterClass.ConfigKnowledge.Builder builderForValue) { + if (resultBuilder_ == null) { + streamMessage_ = builderForValue.build(); + onChanged(); + } else { + resultBuilder_.setMessage(builderForValue.build()); + } + streamMessageCase_ = 2; + return this; + } + /** + * .agent.ConfigKnowledge result = 2; + */ + public Builder mergeResult(agent.CollectorOuterClass.ConfigKnowledge value) { + if (resultBuilder_ == null) { + if (streamMessageCase_ == 2 && + streamMessage_ != agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance()) { + streamMessage_ = agent.CollectorOuterClass.ConfigKnowledge.newBuilder((agent.CollectorOuterClass.ConfigKnowledge) streamMessage_) + .mergeFrom(value).buildPartial(); + } else { + streamMessage_ = value; + } + onChanged(); + } else { + if (streamMessageCase_ == 2) { + resultBuilder_.mergeFrom(value); + } else { + resultBuilder_.setMessage(value); + } + } + streamMessageCase_ = 2; + return this; + } + /** + * .agent.ConfigKnowledge result = 2; + */ + public Builder clearResult() { + if (resultBuilder_ == null) { + if (streamMessageCase_ == 2) { + streamMessageCase_ = 0; + streamMessage_ = null; + onChanged(); + } + } else { + if (streamMessageCase_ == 2) { + streamMessageCase_ = 0; + streamMessage_ = null; + } + resultBuilder_.clear(); + } + return this; + } + /** + * .agent.ConfigKnowledge result = 2; + */ + public agent.CollectorOuterClass.ConfigKnowledge.Builder getResultBuilder() { + return getResultFieldBuilder().getBuilder(); + } + /** + * .agent.ConfigKnowledge result = 2; + */ + @java.lang.Override + public agent.CollectorOuterClass.ConfigKnowledgeOrBuilder getResultOrBuilder() { + if ((streamMessageCase_ == 2) && (resultBuilder_ != null)) { + return resultBuilder_.getMessageOrBuilder(); + } else { + if (streamMessageCase_ == 2) { + return (agent.CollectorOuterClass.ConfigKnowledge) streamMessage_; + } + return agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance(); + } + } + /** + * .agent.ConfigKnowledge result = 2; + */ + private com.google.protobuf.SingleFieldBuilder< + agent.CollectorOuterClass.ConfigKnowledge, agent.CollectorOuterClass.ConfigKnowledge.Builder, agent.CollectorOuterClass.ConfigKnowledgeOrBuilder> + getResultFieldBuilder() { + if (resultBuilder_ == null) { + if (!(streamMessageCase_ == 2)) { + streamMessage_ = agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance(); + } + resultBuilder_ = new com.google.protobuf.SingleFieldBuilder< + agent.CollectorOuterClass.ConfigKnowledge, agent.CollectorOuterClass.ConfigKnowledge.Builder, agent.CollectorOuterClass.ConfigKnowledgeOrBuilder>( + (agent.CollectorOuterClass.ConfigKnowledge) streamMessage_, + getParentForChildren(), + isClean()); + streamMessage_ = null; + } + streamMessageCase_ = 2; + onChanged(); + return resultBuilder_; + } + + // @@protoc_insertion_point(builder_scope:agent.CollectorMessages) + } + + // @@protoc_insertion_point(class_scope:agent.CollectorMessages) + private static final agent.CollectorOuterClass.CollectorMessages DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new agent.CollectorOuterClass.CollectorMessages(); + } + + public static agent.CollectorOuterClass.CollectorMessages getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public CollectorMessages parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorMessages getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface CollectorConfigOrBuilder extends + // @@protoc_insertion_point(interface_extends:agent.CollectorConfig) + com.google.protobuf.MessageOrBuilder { + + /** + * string collector_id = 1; + * @return The collectorId. + */ + java.lang.String getCollectorId(); + /** + * string collector_id = 1; + * @return The bytes for collectorId. + */ + com.google.protobuf.ByteString + getCollectorIdBytes(); + + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + java.util.List + getGroupsList(); + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + agent.CollectorOuterClass.CollectorConfigGroup getGroups(int index); + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + int getGroupsCount(); + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + java.util.List + getGroupsOrBuilderList(); + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + agent.CollectorOuterClass.CollectorConfigGroupOrBuilder getGroupsOrBuilder( + int index); + + /** + * string request_id = 3; + * @return The requestId. + */ + java.lang.String getRequestId(); + /** + * string request_id = 3; + * @return The bytes for requestId. + */ + com.google.protobuf.ByteString + getRequestIdBytes(); + } + /** + * Protobuf type {@code agent.CollectorConfig} + */ + public static final class CollectorConfig extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:agent.CollectorConfig) + CollectorConfigOrBuilder { + private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + CollectorConfig.class.getName()); + } + // Use CollectorConfig.newBuilder() to construct. + private CollectorConfig(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private CollectorConfig() { + collectorId_ = ""; + groups_ = java.util.Collections.emptyList(); + requestId_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfig_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfig_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.CollectorConfig.class, agent.CollectorOuterClass.CollectorConfig.Builder.class); + } + + public static final int COLLECTOR_ID_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object collectorId_ = ""; + /** + * string collector_id = 1; + * @return The collectorId. + */ + @java.lang.Override + public java.lang.String getCollectorId() { + java.lang.Object ref = collectorId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + collectorId_ = s; + return s; + } + } + /** + * string collector_id = 1; + * @return The bytes for collectorId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getCollectorIdBytes() { + java.lang.Object ref = collectorId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + collectorId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int GROUPS_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private java.util.List groups_; + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + @java.lang.Override + public java.util.List getGroupsList() { + return groups_; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + @java.lang.Override + public java.util.List + getGroupsOrBuilderList() { + return groups_; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + @java.lang.Override + public int getGroupsCount() { + return groups_.size(); + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfigGroup getGroups(int index) { + return groups_.get(index); + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfigGroupOrBuilder getGroupsOrBuilder( + int index) { + return groups_.get(index); + } + + public static final int REQUEST_ID_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object requestId_ = ""; + /** + * string request_id = 3; + * @return The requestId. + */ + @java.lang.Override + public java.lang.String getRequestId() { + java.lang.Object ref = requestId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + requestId_ = s; + return s; + } + } + /** + * string request_id = 3; + * @return The bytes for requestId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRequestIdBytes() { + java.lang.Object ref = requestId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + requestId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(collectorId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, collectorId_); + } + for (int i = 0; i < groups_.size(); i++) { + output.writeMessage(2, groups_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(requestId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, requestId_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(collectorId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, collectorId_); + } + for (int i = 0; i < groups_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, groups_.get(i)); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(requestId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, requestId_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof agent.CollectorOuterClass.CollectorConfig)) { + return super.equals(obj); + } + agent.CollectorOuterClass.CollectorConfig other = (agent.CollectorOuterClass.CollectorConfig) obj; + + if (!getCollectorId() + .equals(other.getCollectorId())) return false; + if (!getGroupsList() + .equals(other.getGroupsList())) return false; + if (!getRequestId() + .equals(other.getRequestId())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + COLLECTOR_ID_FIELD_NUMBER; + hash = (53 * hash) + getCollectorId().hashCode(); + if (getGroupsCount() > 0) { + hash = (37 * hash) + GROUPS_FIELD_NUMBER; + hash = (53 * hash) + getGroupsList().hashCode(); + } + hash = (37 * hash) + REQUEST_ID_FIELD_NUMBER; + hash = (53 * hash) + getRequestId().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static agent.CollectorOuterClass.CollectorConfig parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorConfig parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorConfig parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorConfig parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorConfig parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorConfig parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorConfig parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.CollectorConfig parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static agent.CollectorOuterClass.CollectorConfig parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static agent.CollectorOuterClass.CollectorConfig parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorConfig parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.CollectorConfig parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(agent.CollectorOuterClass.CollectorConfig prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code agent.CollectorConfig} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:agent.CollectorConfig) + agent.CollectorOuterClass.CollectorConfigOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfig_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfig_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.CollectorConfig.class, agent.CollectorOuterClass.CollectorConfig.Builder.class); + } + + // Construct using agent.CollectorOuterClass.CollectorConfig.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + collectorId_ = ""; + if (groupsBuilder_ == null) { + groups_ = java.util.Collections.emptyList(); + } else { + groups_ = null; + groupsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + requestId_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfig_descriptor; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfig getDefaultInstanceForType() { + return agent.CollectorOuterClass.CollectorConfig.getDefaultInstance(); + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfig build() { + agent.CollectorOuterClass.CollectorConfig result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfig buildPartial() { + agent.CollectorOuterClass.CollectorConfig result = new agent.CollectorOuterClass.CollectorConfig(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(agent.CollectorOuterClass.CollectorConfig result) { + if (groupsBuilder_ == null) { + if (((bitField0_ & 0x00000002) != 0)) { + groups_ = java.util.Collections.unmodifiableList(groups_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.groups_ = groups_; + } else { + result.groups_ = groupsBuilder_.build(); + } + } + + private void buildPartial0(agent.CollectorOuterClass.CollectorConfig result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.collectorId_ = collectorId_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.requestId_ = requestId_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof agent.CollectorOuterClass.CollectorConfig) { + return mergeFrom((agent.CollectorOuterClass.CollectorConfig)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(agent.CollectorOuterClass.CollectorConfig other) { + if (other == agent.CollectorOuterClass.CollectorConfig.getDefaultInstance()) return this; + if (!other.getCollectorId().isEmpty()) { + collectorId_ = other.collectorId_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (groupsBuilder_ == null) { + if (!other.groups_.isEmpty()) { + if (groups_.isEmpty()) { + groups_ = other.groups_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureGroupsIsMutable(); + groups_.addAll(other.groups_); + } + onChanged(); + } + } else { + if (!other.groups_.isEmpty()) { + if (groupsBuilder_.isEmpty()) { + groupsBuilder_.dispose(); + groupsBuilder_ = null; + groups_ = other.groups_; + bitField0_ = (bitField0_ & ~0x00000002); + groupsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + getGroupsFieldBuilder() : null; + } else { + groupsBuilder_.addAllMessages(other.groups_); + } + } + } + if (!other.getRequestId().isEmpty()) { + requestId_ = other.requestId_; + bitField0_ |= 0x00000004; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + collectorId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + agent.CollectorOuterClass.CollectorConfigGroup m = + input.readMessage( + agent.CollectorOuterClass.CollectorConfigGroup.parser(), + extensionRegistry); + if (groupsBuilder_ == null) { + ensureGroupsIsMutable(); + groups_.add(m); + } else { + groupsBuilder_.addMessage(m); + } + break; + } // case 18 + case 26: { + requestId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object collectorId_ = ""; + /** + * string collector_id = 1; + * @return The collectorId. + */ + public java.lang.String getCollectorId() { + java.lang.Object ref = collectorId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + collectorId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string collector_id = 1; + * @return The bytes for collectorId. + */ + public com.google.protobuf.ByteString + getCollectorIdBytes() { + java.lang.Object ref = collectorId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + collectorId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string collector_id = 1; + * @param value The collectorId to set. + * @return This builder for chaining. + */ + public Builder setCollectorId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + collectorId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * string collector_id = 1; + * @return This builder for chaining. + */ + public Builder clearCollectorId() { + collectorId_ = getDefaultInstance().getCollectorId(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + * string collector_id = 1; + * @param value The bytes for collectorId to set. + * @return This builder for chaining. + */ + public Builder setCollectorIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + collectorId_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.util.List groups_ = + java.util.Collections.emptyList(); + private void ensureGroupsIsMutable() { + if (!((bitField0_ & 0x00000002) != 0)) { + groups_ = new java.util.ArrayList(groups_); + bitField0_ |= 0x00000002; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + agent.CollectorOuterClass.CollectorConfigGroup, agent.CollectorOuterClass.CollectorConfigGroup.Builder, agent.CollectorOuterClass.CollectorConfigGroupOrBuilder> groupsBuilder_; + + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public java.util.List getGroupsList() { + if (groupsBuilder_ == null) { + return java.util.Collections.unmodifiableList(groups_); + } else { + return groupsBuilder_.getMessageList(); + } + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public int getGroupsCount() { + if (groupsBuilder_ == null) { + return groups_.size(); + } else { + return groupsBuilder_.getCount(); + } + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public agent.CollectorOuterClass.CollectorConfigGroup getGroups(int index) { + if (groupsBuilder_ == null) { + return groups_.get(index); + } else { + return groupsBuilder_.getMessage(index); + } + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public Builder setGroups( + int index, agent.CollectorOuterClass.CollectorConfigGroup value) { + if (groupsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupsIsMutable(); + groups_.set(index, value); + onChanged(); + } else { + groupsBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public Builder setGroups( + int index, agent.CollectorOuterClass.CollectorConfigGroup.Builder builderForValue) { + if (groupsBuilder_ == null) { + ensureGroupsIsMutable(); + groups_.set(index, builderForValue.build()); + onChanged(); + } else { + groupsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public Builder addGroups(agent.CollectorOuterClass.CollectorConfigGroup value) { + if (groupsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupsIsMutable(); + groups_.add(value); + onChanged(); + } else { + groupsBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public Builder addGroups( + int index, agent.CollectorOuterClass.CollectorConfigGroup value) { + if (groupsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureGroupsIsMutable(); + groups_.add(index, value); + onChanged(); + } else { + groupsBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public Builder addGroups( + agent.CollectorOuterClass.CollectorConfigGroup.Builder builderForValue) { + if (groupsBuilder_ == null) { + ensureGroupsIsMutable(); + groups_.add(builderForValue.build()); + onChanged(); + } else { + groupsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public Builder addGroups( + int index, agent.CollectorOuterClass.CollectorConfigGroup.Builder builderForValue) { + if (groupsBuilder_ == null) { + ensureGroupsIsMutable(); + groups_.add(index, builderForValue.build()); + onChanged(); + } else { + groupsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public Builder addAllGroups( + java.lang.Iterable values) { + if (groupsBuilder_ == null) { + ensureGroupsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, groups_); + onChanged(); + } else { + groupsBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public Builder clearGroups() { + if (groupsBuilder_ == null) { + groups_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + } else { + groupsBuilder_.clear(); + } + return this; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public Builder removeGroups(int index) { + if (groupsBuilder_ == null) { + ensureGroupsIsMutable(); + groups_.remove(index); + onChanged(); + } else { + groupsBuilder_.remove(index); + } + return this; + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public agent.CollectorOuterClass.CollectorConfigGroup.Builder getGroupsBuilder( + int index) { + return getGroupsFieldBuilder().getBuilder(index); + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public agent.CollectorOuterClass.CollectorConfigGroupOrBuilder getGroupsOrBuilder( + int index) { + if (groupsBuilder_ == null) { + return groups_.get(index); } else { + return groupsBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public java.util.List + getGroupsOrBuilderList() { + if (groupsBuilder_ != null) { + return groupsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(groups_); + } + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public agent.CollectorOuterClass.CollectorConfigGroup.Builder addGroupsBuilder() { + return getGroupsFieldBuilder().addBuilder( + agent.CollectorOuterClass.CollectorConfigGroup.getDefaultInstance()); + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public agent.CollectorOuterClass.CollectorConfigGroup.Builder addGroupsBuilder( + int index) { + return getGroupsFieldBuilder().addBuilder( + index, agent.CollectorOuterClass.CollectorConfigGroup.getDefaultInstance()); + } + /** + * repeated .agent.CollectorConfigGroup groups = 2; + */ + public java.util.List + getGroupsBuilderList() { + return getGroupsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + agent.CollectorOuterClass.CollectorConfigGroup, agent.CollectorOuterClass.CollectorConfigGroup.Builder, agent.CollectorOuterClass.CollectorConfigGroupOrBuilder> + getGroupsFieldBuilder() { + if (groupsBuilder_ == null) { + groupsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + agent.CollectorOuterClass.CollectorConfigGroup, agent.CollectorOuterClass.CollectorConfigGroup.Builder, agent.CollectorOuterClass.CollectorConfigGroupOrBuilder>( + groups_, + ((bitField0_ & 0x00000002) != 0), + getParentForChildren(), + isClean()); + groups_ = null; + } + return groupsBuilder_; + } + + private java.lang.Object requestId_ = ""; + /** + * string request_id = 3; + * @return The requestId. + */ + public java.lang.String getRequestId() { + java.lang.Object ref = requestId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + requestId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string request_id = 3; + * @return The bytes for requestId. + */ + public com.google.protobuf.ByteString + getRequestIdBytes() { + java.lang.Object ref = requestId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + requestId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string request_id = 3; + * @param value The requestId to set. + * @return This builder for chaining. + */ + public Builder setRequestId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + requestId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * string request_id = 3; + * @return This builder for chaining. + */ + public Builder clearRequestId() { + requestId_ = getDefaultInstance().getRequestId(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + * string request_id = 3; + * @param value The bytes for requestId to set. + * @return This builder for chaining. + */ + public Builder setRequestIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + requestId_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:agent.CollectorConfig) + } + + // @@protoc_insertion_point(class_scope:agent.CollectorConfig) + private static final agent.CollectorOuterClass.CollectorConfig DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new agent.CollectorOuterClass.CollectorConfig(); + } + + public static agent.CollectorOuterClass.CollectorConfig getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public CollectorConfig parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfig getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface CollectorConfigGroupOrBuilder extends + // @@protoc_insertion_point(interface_extends:agent.CollectorConfigGroup) + com.google.protobuf.MessageOrBuilder { + + /** + * int32 id = 1; + * @return The id. + */ + int getId(); + + /** + * string group_name = 2; + * @return The groupName. + */ + java.lang.String getGroupName(); + /** + * string group_name = 2; + * @return The bytes for groupName. + */ + com.google.protobuf.ByteString + getGroupNameBytes(); + + /** + * string group_description = 3; + * @return The groupDescription. + */ + java.lang.String getGroupDescription(); + /** + * string group_description = 3; + * @return The bytes for groupDescription. + */ + com.google.protobuf.ByteString + getGroupDescriptionBytes(); + + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + java.util.List + getConfigurationsList(); + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + agent.CollectorOuterClass.CollectorGroupConfigurations getConfigurations(int index); + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + int getConfigurationsCount(); + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + java.util.List + getConfigurationsOrBuilderList(); + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + agent.CollectorOuterClass.CollectorGroupConfigurationsOrBuilder getConfigurationsOrBuilder( + int index); + + /** + * int32 collector_id = 5; + * @return The collectorId. + */ + int getCollectorId(); + } + /** + * Protobuf type {@code agent.CollectorConfigGroup} + */ + public static final class CollectorConfigGroup extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:agent.CollectorConfigGroup) + CollectorConfigGroupOrBuilder { + private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + CollectorConfigGroup.class.getName()); + } + // Use CollectorConfigGroup.newBuilder() to construct. + private CollectorConfigGroup(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private CollectorConfigGroup() { + groupName_ = ""; + groupDescription_ = ""; + configurations_ = java.util.Collections.emptyList(); + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfigGroup_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfigGroup_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.CollectorConfigGroup.class, agent.CollectorOuterClass.CollectorConfigGroup.Builder.class); + } + + public static final int ID_FIELD_NUMBER = 1; + private int id_ = 0; + /** + * int32 id = 1; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + + public static final int GROUP_NAME_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object groupName_ = ""; + /** + * string group_name = 2; + * @return The groupName. + */ + @java.lang.Override + public java.lang.String getGroupName() { + java.lang.Object ref = groupName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + groupName_ = s; + return s; + } + } + /** + * string group_name = 2; + * @return The bytes for groupName. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getGroupNameBytes() { + java.lang.Object ref = groupName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int GROUP_DESCRIPTION_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object groupDescription_ = ""; + /** + * string group_description = 3; + * @return The groupDescription. + */ + @java.lang.Override + public java.lang.String getGroupDescription() { + java.lang.Object ref = groupDescription_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + groupDescription_ = s; + return s; + } + } + /** + * string group_description = 3; + * @return The bytes for groupDescription. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getGroupDescriptionBytes() { + java.lang.Object ref = groupDescription_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupDescription_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONFIGURATIONS_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private java.util.List configurations_; + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + @java.lang.Override + public java.util.List getConfigurationsList() { + return configurations_; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + @java.lang.Override + public java.util.List + getConfigurationsOrBuilderList() { + return configurations_; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + @java.lang.Override + public int getConfigurationsCount() { + return configurations_.size(); + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorGroupConfigurations getConfigurations(int index) { + return configurations_.get(index); + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorGroupConfigurationsOrBuilder getConfigurationsOrBuilder( + int index) { + return configurations_.get(index); + } + + public static final int COLLECTOR_ID_FIELD_NUMBER = 5; + private int collectorId_ = 0; + /** + * int32 collector_id = 5; + * @return The collectorId. + */ + @java.lang.Override + public int getCollectorId() { + return collectorId_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (id_ != 0) { + output.writeInt32(1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(groupName_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, groupName_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(groupDescription_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, groupDescription_); + } + for (int i = 0; i < configurations_.size(); i++) { + output.writeMessage(4, configurations_.get(i)); + } + if (collectorId_ != 0) { + output.writeInt32(5, collectorId_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (id_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(1, id_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(groupName_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, groupName_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(groupDescription_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, groupDescription_); + } + for (int i = 0; i < configurations_.size(); i++) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, configurations_.get(i)); + } + if (collectorId_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(5, collectorId_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof agent.CollectorOuterClass.CollectorConfigGroup)) { + return super.equals(obj); + } + agent.CollectorOuterClass.CollectorConfigGroup other = (agent.CollectorOuterClass.CollectorConfigGroup) obj; + + if (getId() + != other.getId()) return false; + if (!getGroupName() + .equals(other.getGroupName())) return false; + if (!getGroupDescription() + .equals(other.getGroupDescription())) return false; + if (!getConfigurationsList() + .equals(other.getConfigurationsList())) return false; + if (getCollectorId() + != other.getCollectorId()) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId(); + hash = (37 * hash) + GROUP_NAME_FIELD_NUMBER; + hash = (53 * hash) + getGroupName().hashCode(); + hash = (37 * hash) + GROUP_DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getGroupDescription().hashCode(); + if (getConfigurationsCount() > 0) { + hash = (37 * hash) + CONFIGURATIONS_FIELD_NUMBER; + hash = (53 * hash) + getConfigurationsList().hashCode(); + } + hash = (37 * hash) + COLLECTOR_ID_FIELD_NUMBER; + hash = (53 * hash) + getCollectorId(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static agent.CollectorOuterClass.CollectorConfigGroup parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static agent.CollectorOuterClass.CollectorConfigGroup parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.CollectorConfigGroup parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(agent.CollectorOuterClass.CollectorConfigGroup prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code agent.CollectorConfigGroup} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:agent.CollectorConfigGroup) + agent.CollectorOuterClass.CollectorConfigGroupOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfigGroup_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfigGroup_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.CollectorConfigGroup.class, agent.CollectorOuterClass.CollectorConfigGroup.Builder.class); + } + + // Construct using agent.CollectorOuterClass.CollectorConfigGroup.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = 0; + groupName_ = ""; + groupDescription_ = ""; + if (configurationsBuilder_ == null) { + configurations_ = java.util.Collections.emptyList(); + } else { + configurations_ = null; + configurationsBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); + collectorId_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return agent.CollectorOuterClass.internal_static_agent_CollectorConfigGroup_descriptor; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfigGroup getDefaultInstanceForType() { + return agent.CollectorOuterClass.CollectorConfigGroup.getDefaultInstance(); + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfigGroup build() { + agent.CollectorOuterClass.CollectorConfigGroup result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfigGroup buildPartial() { + agent.CollectorOuterClass.CollectorConfigGroup result = new agent.CollectorOuterClass.CollectorConfigGroup(this); + buildPartialRepeatedFields(result); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartialRepeatedFields(agent.CollectorOuterClass.CollectorConfigGroup result) { + if (configurationsBuilder_ == null) { + if (((bitField0_ & 0x00000008) != 0)) { + configurations_ = java.util.Collections.unmodifiableList(configurations_); + bitField0_ = (bitField0_ & ~0x00000008); + } + result.configurations_ = configurations_; + } else { + result.configurations_ = configurationsBuilder_.build(); + } + } + + private void buildPartial0(agent.CollectorOuterClass.CollectorConfigGroup result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.groupName_ = groupName_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.groupDescription_ = groupDescription_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.collectorId_ = collectorId_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof agent.CollectorOuterClass.CollectorConfigGroup) { + return mergeFrom((agent.CollectorOuterClass.CollectorConfigGroup)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(agent.CollectorOuterClass.CollectorConfigGroup other) { + if (other == agent.CollectorOuterClass.CollectorConfigGroup.getDefaultInstance()) return this; + if (other.getId() != 0) { + setId(other.getId()); + } + if (!other.getGroupName().isEmpty()) { + groupName_ = other.groupName_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.getGroupDescription().isEmpty()) { + groupDescription_ = other.groupDescription_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (configurationsBuilder_ == null) { + if (!other.configurations_.isEmpty()) { + if (configurations_.isEmpty()) { + configurations_ = other.configurations_; + bitField0_ = (bitField0_ & ~0x00000008); + } else { + ensureConfigurationsIsMutable(); + configurations_.addAll(other.configurations_); + } + onChanged(); + } + } else { + if (!other.configurations_.isEmpty()) { + if (configurationsBuilder_.isEmpty()) { + configurationsBuilder_.dispose(); + configurationsBuilder_ = null; + configurations_ = other.configurations_; + bitField0_ = (bitField0_ & ~0x00000008); + configurationsBuilder_ = + com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? + getConfigurationsFieldBuilder() : null; + } else { + configurationsBuilder_.addAllMessages(other.configurations_); + } + } + } + if (other.getCollectorId() != 0) { + setCollectorId(other.getCollectorId()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + id_ = input.readInt32(); + bitField0_ |= 0x00000001; + break; + } // case 8 + case 18: { + groupName_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + groupDescription_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + agent.CollectorOuterClass.CollectorGroupConfigurations m = + input.readMessage( + agent.CollectorOuterClass.CollectorGroupConfigurations.parser(), + extensionRegistry); + if (configurationsBuilder_ == null) { + ensureConfigurationsIsMutable(); + configurations_.add(m); + } else { + configurationsBuilder_.addMessage(m); + } + break; + } // case 34 + case 40: { + collectorId_ = input.readInt32(); + bitField0_ |= 0x00000010; + break; + } // case 40 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private int id_ ; + /** + * int32 id = 1; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + /** + * int32 id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId(int value) { + + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * int32 id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0; + onChanged(); + return this; + } + + private java.lang.Object groupName_ = ""; + /** + * string group_name = 2; + * @return The groupName. + */ + public java.lang.String getGroupName() { + java.lang.Object ref = groupName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + groupName_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string group_name = 2; + * @return The bytes for groupName. + */ + public com.google.protobuf.ByteString + getGroupNameBytes() { + java.lang.Object ref = groupName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string group_name = 2; + * @param value The groupName to set. + * @return This builder for chaining. + */ + public Builder setGroupName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + groupName_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * string group_name = 2; + * @return This builder for chaining. + */ + public Builder clearGroupName() { + groupName_ = getDefaultInstance().getGroupName(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + * string group_name = 2; + * @param value The bytes for groupName to set. + * @return This builder for chaining. + */ + public Builder setGroupNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + groupName_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private java.lang.Object groupDescription_ = ""; + /** + * string group_description = 3; + * @return The groupDescription. + */ + public java.lang.String getGroupDescription() { + java.lang.Object ref = groupDescription_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + groupDescription_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string group_description = 3; + * @return The bytes for groupDescription. + */ + public com.google.protobuf.ByteString + getGroupDescriptionBytes() { + java.lang.Object ref = groupDescription_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + groupDescription_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string group_description = 3; + * @param value The groupDescription to set. + * @return This builder for chaining. + */ + public Builder setGroupDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + groupDescription_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * string group_description = 3; + * @return This builder for chaining. + */ + public Builder clearGroupDescription() { + groupDescription_ = getDefaultInstance().getGroupDescription(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + * string group_description = 3; + * @param value The bytes for groupDescription to set. + * @return This builder for chaining. + */ + public Builder setGroupDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + groupDescription_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.util.List configurations_ = + java.util.Collections.emptyList(); + private void ensureConfigurationsIsMutable() { + if (!((bitField0_ & 0x00000008) != 0)) { + configurations_ = new java.util.ArrayList(configurations_); + bitField0_ |= 0x00000008; + } + } + + private com.google.protobuf.RepeatedFieldBuilder< + agent.CollectorOuterClass.CollectorGroupConfigurations, agent.CollectorOuterClass.CollectorGroupConfigurations.Builder, agent.CollectorOuterClass.CollectorGroupConfigurationsOrBuilder> configurationsBuilder_; + + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public java.util.List getConfigurationsList() { + if (configurationsBuilder_ == null) { + return java.util.Collections.unmodifiableList(configurations_); + } else { + return configurationsBuilder_.getMessageList(); + } + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public int getConfigurationsCount() { + if (configurationsBuilder_ == null) { + return configurations_.size(); + } else { + return configurationsBuilder_.getCount(); + } + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public agent.CollectorOuterClass.CollectorGroupConfigurations getConfigurations(int index) { + if (configurationsBuilder_ == null) { + return configurations_.get(index); + } else { + return configurationsBuilder_.getMessage(index); + } + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public Builder setConfigurations( + int index, agent.CollectorOuterClass.CollectorGroupConfigurations value) { + if (configurationsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureConfigurationsIsMutable(); + configurations_.set(index, value); + onChanged(); + } else { + configurationsBuilder_.setMessage(index, value); + } + return this; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public Builder setConfigurations( + int index, agent.CollectorOuterClass.CollectorGroupConfigurations.Builder builderForValue) { + if (configurationsBuilder_ == null) { + ensureConfigurationsIsMutable(); + configurations_.set(index, builderForValue.build()); + onChanged(); + } else { + configurationsBuilder_.setMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public Builder addConfigurations(agent.CollectorOuterClass.CollectorGroupConfigurations value) { + if (configurationsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureConfigurationsIsMutable(); + configurations_.add(value); + onChanged(); + } else { + configurationsBuilder_.addMessage(value); + } + return this; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public Builder addConfigurations( + int index, agent.CollectorOuterClass.CollectorGroupConfigurations value) { + if (configurationsBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + ensureConfigurationsIsMutable(); + configurations_.add(index, value); + onChanged(); + } else { + configurationsBuilder_.addMessage(index, value); + } + return this; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public Builder addConfigurations( + agent.CollectorOuterClass.CollectorGroupConfigurations.Builder builderForValue) { + if (configurationsBuilder_ == null) { + ensureConfigurationsIsMutable(); + configurations_.add(builderForValue.build()); + onChanged(); + } else { + configurationsBuilder_.addMessage(builderForValue.build()); + } + return this; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public Builder addConfigurations( + int index, agent.CollectorOuterClass.CollectorGroupConfigurations.Builder builderForValue) { + if (configurationsBuilder_ == null) { + ensureConfigurationsIsMutable(); + configurations_.add(index, builderForValue.build()); + onChanged(); + } else { + configurationsBuilder_.addMessage(index, builderForValue.build()); + } + return this; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public Builder addAllConfigurations( + java.lang.Iterable values) { + if (configurationsBuilder_ == null) { + ensureConfigurationsIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll( + values, configurations_); + onChanged(); + } else { + configurationsBuilder_.addAllMessages(values); + } + return this; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public Builder clearConfigurations() { + if (configurationsBuilder_ == null) { + configurations_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + } else { + configurationsBuilder_.clear(); + } + return this; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public Builder removeConfigurations(int index) { + if (configurationsBuilder_ == null) { + ensureConfigurationsIsMutable(); + configurations_.remove(index); + onChanged(); + } else { + configurationsBuilder_.remove(index); + } + return this; + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public agent.CollectorOuterClass.CollectorGroupConfigurations.Builder getConfigurationsBuilder( + int index) { + return getConfigurationsFieldBuilder().getBuilder(index); + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public agent.CollectorOuterClass.CollectorGroupConfigurationsOrBuilder getConfigurationsOrBuilder( + int index) { + if (configurationsBuilder_ == null) { + return configurations_.get(index); } else { + return configurationsBuilder_.getMessageOrBuilder(index); + } + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public java.util.List + getConfigurationsOrBuilderList() { + if (configurationsBuilder_ != null) { + return configurationsBuilder_.getMessageOrBuilderList(); + } else { + return java.util.Collections.unmodifiableList(configurations_); + } + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public agent.CollectorOuterClass.CollectorGroupConfigurations.Builder addConfigurationsBuilder() { + return getConfigurationsFieldBuilder().addBuilder( + agent.CollectorOuterClass.CollectorGroupConfigurations.getDefaultInstance()); + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public agent.CollectorOuterClass.CollectorGroupConfigurations.Builder addConfigurationsBuilder( + int index) { + return getConfigurationsFieldBuilder().addBuilder( + index, agent.CollectorOuterClass.CollectorGroupConfigurations.getDefaultInstance()); + } + /** + * repeated .agent.CollectorGroupConfigurations configurations = 4; + */ + public java.util.List + getConfigurationsBuilderList() { + return getConfigurationsFieldBuilder().getBuilderList(); + } + private com.google.protobuf.RepeatedFieldBuilder< + agent.CollectorOuterClass.CollectorGroupConfigurations, agent.CollectorOuterClass.CollectorGroupConfigurations.Builder, agent.CollectorOuterClass.CollectorGroupConfigurationsOrBuilder> + getConfigurationsFieldBuilder() { + if (configurationsBuilder_ == null) { + configurationsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< + agent.CollectorOuterClass.CollectorGroupConfigurations, agent.CollectorOuterClass.CollectorGroupConfigurations.Builder, agent.CollectorOuterClass.CollectorGroupConfigurationsOrBuilder>( + configurations_, + ((bitField0_ & 0x00000008) != 0), + getParentForChildren(), + isClean()); + configurations_ = null; + } + return configurationsBuilder_; + } + + private int collectorId_ ; + /** + * int32 collector_id = 5; + * @return The collectorId. + */ + @java.lang.Override + public int getCollectorId() { + return collectorId_; + } + /** + * int32 collector_id = 5; + * @param value The collectorId to set. + * @return This builder for chaining. + */ + public Builder setCollectorId(int value) { + + collectorId_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + * int32 collector_id = 5; + * @return This builder for chaining. + */ + public Builder clearCollectorId() { + bitField0_ = (bitField0_ & ~0x00000010); + collectorId_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:agent.CollectorConfigGroup) + } + + // @@protoc_insertion_point(class_scope:agent.CollectorConfigGroup) + private static final agent.CollectorOuterClass.CollectorConfigGroup DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new agent.CollectorOuterClass.CollectorConfigGroup(); + } + + public static agent.CollectorOuterClass.CollectorConfigGroup getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public CollectorConfigGroup parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorConfigGroup getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface CollectorGroupConfigurationsOrBuilder extends + // @@protoc_insertion_point(interface_extends:agent.CollectorGroupConfigurations) + com.google.protobuf.MessageOrBuilder { + + /** + * int32 id = 1; + * @return The id. + */ + int getId(); + + /** + * int32 group_id = 2; + * @return The groupId. + */ + int getGroupId(); + + /** + * string conf_key = 3; + * @return The confKey. + */ + java.lang.String getConfKey(); + /** + * string conf_key = 3; + * @return The bytes for confKey. + */ + com.google.protobuf.ByteString + getConfKeyBytes(); + + /** + * string conf_value = 4; + * @return The confValue. + */ + java.lang.String getConfValue(); + /** + * string conf_value = 4; + * @return The bytes for confValue. + */ + com.google.protobuf.ByteString + getConfValueBytes(); + + /** + * string conf_name = 5; + * @return The confName. + */ + java.lang.String getConfName(); + /** + * string conf_name = 5; + * @return The bytes for confName. + */ + com.google.protobuf.ByteString + getConfNameBytes(); + + /** + * string conf_description = 6; + * @return The confDescription. + */ + java.lang.String getConfDescription(); + /** + * string conf_description = 6; + * @return The bytes for confDescription. + */ + com.google.protobuf.ByteString + getConfDescriptionBytes(); + + /** + * string conf_data_type = 7; + * @return The confDataType. + */ + java.lang.String getConfDataType(); + /** + * string conf_data_type = 7; + * @return The bytes for confDataType. + */ + com.google.protobuf.ByteString + getConfDataTypeBytes(); + + /** + * bool conf_required = 8; + * @return The confRequired. + */ + boolean getConfRequired(); + } + /** + * Protobuf type {@code agent.CollectorGroupConfigurations} + */ + public static final class CollectorGroupConfigurations extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:agent.CollectorGroupConfigurations) + CollectorGroupConfigurationsOrBuilder { + private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + CollectorGroupConfigurations.class.getName()); + } + // Use CollectorGroupConfigurations.newBuilder() to construct. + private CollectorGroupConfigurations(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private CollectorGroupConfigurations() { + confKey_ = ""; + confValue_ = ""; + confName_ = ""; + confDescription_ = ""; + confDataType_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_CollectorGroupConfigurations_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_CollectorGroupConfigurations_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.CollectorGroupConfigurations.class, agent.CollectorOuterClass.CollectorGroupConfigurations.Builder.class); + } + + public static final int ID_FIELD_NUMBER = 1; + private int id_ = 0; + /** + * int32 id = 1; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + + public static final int GROUP_ID_FIELD_NUMBER = 2; + private int groupId_ = 0; + /** + * int32 group_id = 2; + * @return The groupId. + */ + @java.lang.Override + public int getGroupId() { + return groupId_; + } + + public static final int CONF_KEY_FIELD_NUMBER = 3; + @SuppressWarnings("serial") + private volatile java.lang.Object confKey_ = ""; + /** + * string conf_key = 3; + * @return The confKey. + */ + @java.lang.Override + public java.lang.String getConfKey() { + java.lang.Object ref = confKey_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confKey_ = s; + return s; + } + } + /** + * string conf_key = 3; + * @return The bytes for confKey. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getConfKeyBytes() { + java.lang.Object ref = confKey_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confKey_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONF_VALUE_FIELD_NUMBER = 4; + @SuppressWarnings("serial") + private volatile java.lang.Object confValue_ = ""; + /** + * string conf_value = 4; + * @return The confValue. + */ + @java.lang.Override + public java.lang.String getConfValue() { + java.lang.Object ref = confValue_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confValue_ = s; + return s; + } + } + /** + * string conf_value = 4; + * @return The bytes for confValue. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getConfValueBytes() { + java.lang.Object ref = confValue_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confValue_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONF_NAME_FIELD_NUMBER = 5; + @SuppressWarnings("serial") + private volatile java.lang.Object confName_ = ""; + /** + * string conf_name = 5; + * @return The confName. + */ + @java.lang.Override + public java.lang.String getConfName() { + java.lang.Object ref = confName_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confName_ = s; + return s; + } + } + /** + * string conf_name = 5; + * @return The bytes for confName. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getConfNameBytes() { + java.lang.Object ref = confName_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONF_DESCRIPTION_FIELD_NUMBER = 6; + @SuppressWarnings("serial") + private volatile java.lang.Object confDescription_ = ""; + /** + * string conf_description = 6; + * @return The confDescription. + */ + @java.lang.Override + public java.lang.String getConfDescription() { + java.lang.Object ref = confDescription_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confDescription_ = s; + return s; + } + } + /** + * string conf_description = 6; + * @return The bytes for confDescription. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getConfDescriptionBytes() { + java.lang.Object ref = confDescription_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confDescription_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONF_DATA_TYPE_FIELD_NUMBER = 7; + @SuppressWarnings("serial") + private volatile java.lang.Object confDataType_ = ""; + /** + * string conf_data_type = 7; + * @return The confDataType. + */ + @java.lang.Override + public java.lang.String getConfDataType() { + java.lang.Object ref = confDataType_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confDataType_ = s; + return s; + } + } + /** + * string conf_data_type = 7; + * @return The bytes for confDataType. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getConfDataTypeBytes() { + java.lang.Object ref = confDataType_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confDataType_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int CONF_REQUIRED_FIELD_NUMBER = 8; + private boolean confRequired_ = false; + /** + * bool conf_required = 8; + * @return The confRequired. + */ + @java.lang.Override + public boolean getConfRequired() { + return confRequired_; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (id_ != 0) { + output.writeInt32(1, id_); + } + if (groupId_ != 0) { + output.writeInt32(2, groupId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confKey_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 3, confKey_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confValue_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 4, confValue_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confName_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 5, confName_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confDescription_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 6, confDescription_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confDataType_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 7, confDataType_); + } + if (confRequired_ != false) { + output.writeBool(8, confRequired_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (id_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(1, id_); + } + if (groupId_ != 0) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(2, groupId_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confKey_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(3, confKey_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confValue_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(4, confValue_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confName_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(5, confName_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confDescription_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(6, confDescription_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(confDataType_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(7, confDataType_); + } + if (confRequired_ != false) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(8, confRequired_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof agent.CollectorOuterClass.CollectorGroupConfigurations)) { + return super.equals(obj); + } + agent.CollectorOuterClass.CollectorGroupConfigurations other = (agent.CollectorOuterClass.CollectorGroupConfigurations) obj; + + if (getId() + != other.getId()) return false; + if (getGroupId() + != other.getGroupId()) return false; + if (!getConfKey() + .equals(other.getConfKey())) return false; + if (!getConfValue() + .equals(other.getConfValue())) return false; + if (!getConfName() + .equals(other.getConfName())) return false; + if (!getConfDescription() + .equals(other.getConfDescription())) return false; + if (!getConfDataType() + .equals(other.getConfDataType())) return false; + if (getConfRequired() + != other.getConfRequired()) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ID_FIELD_NUMBER; + hash = (53 * hash) + getId(); + hash = (37 * hash) + GROUP_ID_FIELD_NUMBER; + hash = (53 * hash) + getGroupId(); + hash = (37 * hash) + CONF_KEY_FIELD_NUMBER; + hash = (53 * hash) + getConfKey().hashCode(); + hash = (37 * hash) + CONF_VALUE_FIELD_NUMBER; + hash = (53 * hash) + getConfValue().hashCode(); + hash = (37 * hash) + CONF_NAME_FIELD_NUMBER; + hash = (53 * hash) + getConfName().hashCode(); + hash = (37 * hash) + CONF_DESCRIPTION_FIELD_NUMBER; + hash = (53 * hash) + getConfDescription().hashCode(); + hash = (37 * hash) + CONF_DATA_TYPE_FIELD_NUMBER; + hash = (53 * hash) + getConfDataType().hashCode(); + hash = (37 * hash) + CONF_REQUIRED_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( + getConfRequired()); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.CollectorGroupConfigurations parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(agent.CollectorOuterClass.CollectorGroupConfigurations prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code agent.CollectorGroupConfigurations} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:agent.CollectorGroupConfigurations) + agent.CollectorOuterClass.CollectorGroupConfigurationsOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_CollectorGroupConfigurations_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_CollectorGroupConfigurations_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.CollectorGroupConfigurations.class, agent.CollectorOuterClass.CollectorGroupConfigurations.Builder.class); + } + + // Construct using agent.CollectorOuterClass.CollectorGroupConfigurations.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + id_ = 0; + groupId_ = 0; + confKey_ = ""; + confValue_ = ""; + confName_ = ""; + confDescription_ = ""; + confDataType_ = ""; + confRequired_ = false; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return agent.CollectorOuterClass.internal_static_agent_CollectorGroupConfigurations_descriptor; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorGroupConfigurations getDefaultInstanceForType() { + return agent.CollectorOuterClass.CollectorGroupConfigurations.getDefaultInstance(); + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorGroupConfigurations build() { + agent.CollectorOuterClass.CollectorGroupConfigurations result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorGroupConfigurations buildPartial() { + agent.CollectorOuterClass.CollectorGroupConfigurations result = new agent.CollectorOuterClass.CollectorGroupConfigurations(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(agent.CollectorOuterClass.CollectorGroupConfigurations result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.id_ = id_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.groupId_ = groupId_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + result.confKey_ = confKey_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + result.confValue_ = confValue_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.confName_ = confName_; + } + if (((from_bitField0_ & 0x00000020) != 0)) { + result.confDescription_ = confDescription_; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + result.confDataType_ = confDataType_; + } + if (((from_bitField0_ & 0x00000080) != 0)) { + result.confRequired_ = confRequired_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof agent.CollectorOuterClass.CollectorGroupConfigurations) { + return mergeFrom((agent.CollectorOuterClass.CollectorGroupConfigurations)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(agent.CollectorOuterClass.CollectorGroupConfigurations other) { + if (other == agent.CollectorOuterClass.CollectorGroupConfigurations.getDefaultInstance()) return this; + if (other.getId() != 0) { + setId(other.getId()); + } + if (other.getGroupId() != 0) { + setGroupId(other.getGroupId()); + } + if (!other.getConfKey().isEmpty()) { + confKey_ = other.confKey_; + bitField0_ |= 0x00000004; + onChanged(); + } + if (!other.getConfValue().isEmpty()) { + confValue_ = other.confValue_; + bitField0_ |= 0x00000008; + onChanged(); + } + if (!other.getConfName().isEmpty()) { + confName_ = other.confName_; + bitField0_ |= 0x00000010; + onChanged(); + } + if (!other.getConfDescription().isEmpty()) { + confDescription_ = other.confDescription_; + bitField0_ |= 0x00000020; + onChanged(); + } + if (!other.getConfDataType().isEmpty()) { + confDataType_ = other.confDataType_; + bitField0_ |= 0x00000040; + onChanged(); + } + if (other.getConfRequired() != false) { + setConfRequired(other.getConfRequired()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + id_ = input.readInt32(); + bitField0_ |= 0x00000001; + break; + } // case 8 + case 16: { + groupId_ = input.readInt32(); + bitField0_ |= 0x00000002; + break; + } // case 16 + case 26: { + confKey_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000004; + break; + } // case 26 + case 34: { + confValue_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000008; + break; + } // case 34 + case 42: { + confName_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 50: { + confDescription_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000020; + break; + } // case 50 + case 58: { + confDataType_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000040; + break; + } // case 58 + case 64: { + confRequired_ = input.readBool(); + bitField0_ |= 0x00000080; + break; + } // case 64 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private int id_ ; + /** + * int32 id = 1; + * @return The id. + */ + @java.lang.Override + public int getId() { + return id_; + } + /** + * int32 id = 1; + * @param value The id to set. + * @return This builder for chaining. + */ + public Builder setId(int value) { + + id_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * int32 id = 1; + * @return This builder for chaining. + */ + public Builder clearId() { + bitField0_ = (bitField0_ & ~0x00000001); + id_ = 0; + onChanged(); + return this; + } + + private int groupId_ ; + /** + * int32 group_id = 2; + * @return The groupId. + */ + @java.lang.Override + public int getGroupId() { + return groupId_; + } + /** + * int32 group_id = 2; + * @param value The groupId to set. + * @return This builder for chaining. + */ + public Builder setGroupId(int value) { + + groupId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * int32 group_id = 2; + * @return This builder for chaining. + */ + public Builder clearGroupId() { + bitField0_ = (bitField0_ & ~0x00000002); + groupId_ = 0; + onChanged(); + return this; + } + + private java.lang.Object confKey_ = ""; + /** + * string conf_key = 3; + * @return The confKey. + */ + public java.lang.String getConfKey() { + java.lang.Object ref = confKey_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confKey_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string conf_key = 3; + * @return The bytes for confKey. + */ + public com.google.protobuf.ByteString + getConfKeyBytes() { + java.lang.Object ref = confKey_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confKey_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string conf_key = 3; + * @param value The confKey to set. + * @return This builder for chaining. + */ + public Builder setConfKey( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + confKey_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + /** + * string conf_key = 3; + * @return This builder for chaining. + */ + public Builder clearConfKey() { + confKey_ = getDefaultInstance().getConfKey(); + bitField0_ = (bitField0_ & ~0x00000004); + onChanged(); + return this; + } + /** + * string conf_key = 3; + * @param value The bytes for confKey to set. + * @return This builder for chaining. + */ + public Builder setConfKeyBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + confKey_ = value; + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private java.lang.Object confValue_ = ""; + /** + * string conf_value = 4; + * @return The confValue. + */ + public java.lang.String getConfValue() { + java.lang.Object ref = confValue_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confValue_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string conf_value = 4; + * @return The bytes for confValue. + */ + public com.google.protobuf.ByteString + getConfValueBytes() { + java.lang.Object ref = confValue_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confValue_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string conf_value = 4; + * @param value The confValue to set. + * @return This builder for chaining. + */ + public Builder setConfValue( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + confValue_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + /** + * string conf_value = 4; + * @return This builder for chaining. + */ + public Builder clearConfValue() { + confValue_ = getDefaultInstance().getConfValue(); + bitField0_ = (bitField0_ & ~0x00000008); + onChanged(); + return this; + } + /** + * string conf_value = 4; + * @param value The bytes for confValue to set. + * @return This builder for chaining. + */ + public Builder setConfValueBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + confValue_ = value; + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + private java.lang.Object confName_ = ""; + /** + * string conf_name = 5; + * @return The confName. + */ + public java.lang.String getConfName() { + java.lang.Object ref = confName_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confName_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string conf_name = 5; + * @return The bytes for confName. + */ + public com.google.protobuf.ByteString + getConfNameBytes() { + java.lang.Object ref = confName_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confName_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string conf_name = 5; + * @param value The confName to set. + * @return This builder for chaining. + */ + public Builder setConfName( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + confName_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + /** + * string conf_name = 5; + * @return This builder for chaining. + */ + public Builder clearConfName() { + confName_ = getDefaultInstance().getConfName(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + return this; + } + /** + * string conf_name = 5; + * @param value The bytes for confName to set. + * @return This builder for chaining. + */ + public Builder setConfNameBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + confName_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private java.lang.Object confDescription_ = ""; + /** + * string conf_description = 6; + * @return The confDescription. + */ + public java.lang.String getConfDescription() { + java.lang.Object ref = confDescription_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confDescription_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string conf_description = 6; + * @return The bytes for confDescription. + */ + public com.google.protobuf.ByteString + getConfDescriptionBytes() { + java.lang.Object ref = confDescription_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confDescription_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string conf_description = 6; + * @param value The confDescription to set. + * @return This builder for chaining. + */ + public Builder setConfDescription( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + confDescription_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + /** + * string conf_description = 6; + * @return This builder for chaining. + */ + public Builder clearConfDescription() { + confDescription_ = getDefaultInstance().getConfDescription(); + bitField0_ = (bitField0_ & ~0x00000020); + onChanged(); + return this; + } + /** + * string conf_description = 6; + * @param value The bytes for confDescription to set. + * @return This builder for chaining. + */ + public Builder setConfDescriptionBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + confDescription_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + private java.lang.Object confDataType_ = ""; + /** + * string conf_data_type = 7; + * @return The confDataType. + */ + public java.lang.String getConfDataType() { + java.lang.Object ref = confDataType_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + confDataType_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string conf_data_type = 7; + * @return The bytes for confDataType. + */ + public com.google.protobuf.ByteString + getConfDataTypeBytes() { + java.lang.Object ref = confDataType_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + confDataType_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string conf_data_type = 7; + * @param value The confDataType to set. + * @return This builder for chaining. + */ + public Builder setConfDataType( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + confDataType_ = value; + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + /** + * string conf_data_type = 7; + * @return This builder for chaining. + */ + public Builder clearConfDataType() { + confDataType_ = getDefaultInstance().getConfDataType(); + bitField0_ = (bitField0_ & ~0x00000040); + onChanged(); + return this; + } + /** + * string conf_data_type = 7; + * @param value The bytes for confDataType to set. + * @return This builder for chaining. + */ + public Builder setConfDataTypeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + confDataType_ = value; + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + + private boolean confRequired_ ; + /** + * bool conf_required = 8; + * @return The confRequired. + */ + @java.lang.Override + public boolean getConfRequired() { + return confRequired_; + } + /** + * bool conf_required = 8; + * @param value The confRequired to set. + * @return This builder for chaining. + */ + public Builder setConfRequired(boolean value) { + + confRequired_ = value; + bitField0_ |= 0x00000080; + onChanged(); + return this; + } + /** + * bool conf_required = 8; + * @return This builder for chaining. + */ + public Builder clearConfRequired() { + bitField0_ = (bitField0_ & ~0x00000080); + confRequired_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:agent.CollectorGroupConfigurations) + } + + // @@protoc_insertion_point(class_scope:agent.CollectorGroupConfigurations) + private static final agent.CollectorOuterClass.CollectorGroupConfigurations DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new agent.CollectorOuterClass.CollectorGroupConfigurations(); + } + + public static agent.CollectorOuterClass.CollectorGroupConfigurations getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public CollectorGroupConfigurations parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public agent.CollectorOuterClass.CollectorGroupConfigurations getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface ConfigKnowledgeOrBuilder extends + // @@protoc_insertion_point(interface_extends:agent.ConfigKnowledge) + com.google.protobuf.MessageOrBuilder { + + /** + * string accepted = 1; + * @return The accepted. + */ + java.lang.String getAccepted(); + /** + * string accepted = 1; + * @return The bytes for accepted. + */ + com.google.protobuf.ByteString + getAcceptedBytes(); + + /** + * string request_id = 2; + * @return The requestId. + */ + java.lang.String getRequestId(); + /** + * string request_id = 2; + * @return The bytes for requestId. + */ + com.google.protobuf.ByteString + getRequestIdBytes(); + } + /** + * Protobuf type {@code agent.ConfigKnowledge} + */ + public static final class ConfigKnowledge extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:agent.ConfigKnowledge) + ConfigKnowledgeOrBuilder { + private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + ConfigKnowledge.class.getName()); + } + // Use ConfigKnowledge.newBuilder() to construct. + private ConfigKnowledge(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ConfigKnowledge() { + accepted_ = ""; + requestId_ = ""; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_ConfigKnowledge_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_ConfigKnowledge_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.ConfigKnowledge.class, agent.CollectorOuterClass.ConfigKnowledge.Builder.class); + } + + public static final int ACCEPTED_FIELD_NUMBER = 1; + @SuppressWarnings("serial") + private volatile java.lang.Object accepted_ = ""; + /** + * string accepted = 1; + * @return The accepted. + */ + @java.lang.Override + public java.lang.String getAccepted() { + java.lang.Object ref = accepted_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + accepted_ = s; + return s; + } + } + /** + * string accepted = 1; + * @return The bytes for accepted. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getAcceptedBytes() { + java.lang.Object ref = accepted_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + accepted_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int REQUEST_ID_FIELD_NUMBER = 2; + @SuppressWarnings("serial") + private volatile java.lang.Object requestId_ = ""; + /** + * string request_id = 2; + * @return The requestId. + */ + @java.lang.Override + public java.lang.String getRequestId() { + java.lang.Object ref = requestId_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + requestId_ = s; + return s; + } + } + /** + * string request_id = 2; + * @return The bytes for requestId. + */ + @java.lang.Override + public com.google.protobuf.ByteString + getRequestIdBytes() { + java.lang.Object ref = requestId_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + requestId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(accepted_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 1, accepted_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(requestId_)) { + com.google.protobuf.GeneratedMessage.writeString(output, 2, requestId_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(accepted_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(1, accepted_); + } + if (!com.google.protobuf.GeneratedMessage.isStringEmpty(requestId_)) { + size += com.google.protobuf.GeneratedMessage.computeStringSize(2, requestId_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof agent.CollectorOuterClass.ConfigKnowledge)) { + return super.equals(obj); + } + agent.CollectorOuterClass.ConfigKnowledge other = (agent.CollectorOuterClass.ConfigKnowledge) obj; + + if (!getAccepted() + .equals(other.getAccepted())) return false; + if (!getRequestId() + .equals(other.getRequestId())) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + ACCEPTED_FIELD_NUMBER; + hash = (53 * hash) + getAccepted().hashCode(); + hash = (37 * hash) + REQUEST_ID_FIELD_NUMBER; + hash = (53 * hash) + getRequestId().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static agent.CollectorOuterClass.ConfigKnowledge parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static agent.CollectorOuterClass.ConfigKnowledge parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.ConfigKnowledge parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(agent.CollectorOuterClass.ConfigKnowledge prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code agent.ConfigKnowledge} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:agent.ConfigKnowledge) + agent.CollectorOuterClass.ConfigKnowledgeOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_ConfigKnowledge_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_ConfigKnowledge_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.ConfigKnowledge.class, agent.CollectorOuterClass.ConfigKnowledge.Builder.class); + } + + // Construct using agent.CollectorOuterClass.ConfigKnowledge.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + accepted_ = ""; + requestId_ = ""; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return agent.CollectorOuterClass.internal_static_agent_ConfigKnowledge_descriptor; + } + + @java.lang.Override + public agent.CollectorOuterClass.ConfigKnowledge getDefaultInstanceForType() { + return agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance(); + } + + @java.lang.Override + public agent.CollectorOuterClass.ConfigKnowledge build() { + agent.CollectorOuterClass.ConfigKnowledge result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public agent.CollectorOuterClass.ConfigKnowledge buildPartial() { + agent.CollectorOuterClass.ConfigKnowledge result = new agent.CollectorOuterClass.ConfigKnowledge(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(agent.CollectorOuterClass.ConfigKnowledge result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.accepted_ = accepted_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.requestId_ = requestId_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof agent.CollectorOuterClass.ConfigKnowledge) { + return mergeFrom((agent.CollectorOuterClass.ConfigKnowledge)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(agent.CollectorOuterClass.ConfigKnowledge other) { + if (other == agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance()) return this; + if (!other.getAccepted().isEmpty()) { + accepted_ = other.accepted_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getRequestId().isEmpty()) { + requestId_ = other.requestId_; + bitField0_ |= 0x00000002; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + accepted_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + requestId_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private java.lang.Object accepted_ = ""; + /** + * string accepted = 1; + * @return The accepted. + */ + public java.lang.String getAccepted() { + java.lang.Object ref = accepted_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + accepted_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string accepted = 1; + * @return The bytes for accepted. + */ + public com.google.protobuf.ByteString + getAcceptedBytes() { + java.lang.Object ref = accepted_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + accepted_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string accepted = 1; + * @param value The accepted to set. + * @return This builder for chaining. + */ + public Builder setAccepted( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + accepted_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * string accepted = 1; + * @return This builder for chaining. + */ + public Builder clearAccepted() { + accepted_ = getDefaultInstance().getAccepted(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + * string accepted = 1; + * @param value The bytes for accepted to set. + * @return This builder for chaining. + */ + public Builder setAcceptedBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + accepted_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private java.lang.Object requestId_ = ""; + /** + * string request_id = 2; + * @return The requestId. + */ + public java.lang.String getRequestId() { + java.lang.Object ref = requestId_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + requestId_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string request_id = 2; + * @return The bytes for requestId. + */ + public com.google.protobuf.ByteString + getRequestIdBytes() { + java.lang.Object ref = requestId_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + requestId_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string request_id = 2; + * @param value The requestId to set. + * @return This builder for chaining. + */ + public Builder setRequestId( + java.lang.String value) { + if (value == null) { throw new NullPointerException(); } + requestId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + /** + * string request_id = 2; + * @return This builder for chaining. + */ + public Builder clearRequestId() { + requestId_ = getDefaultInstance().getRequestId(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + * string request_id = 2; + * @param value The bytes for requestId to set. + * @return This builder for chaining. + */ + public Builder setRequestIdBytes( + com.google.protobuf.ByteString value) { + if (value == null) { throw new NullPointerException(); } + checkByteStringIsUtf8(value); + requestId_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:agent.ConfigKnowledge) + } + + // @@protoc_insertion_point(class_scope:agent.ConfigKnowledge) + private static final agent.CollectorOuterClass.ConfigKnowledge DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new agent.CollectorOuterClass.ConfigKnowledge(); + } + + public static agent.CollectorOuterClass.ConfigKnowledge getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ConfigKnowledge parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public agent.CollectorOuterClass.ConfigKnowledge getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + public interface ConfigRequestOrBuilder extends + // @@protoc_insertion_point(interface_extends:agent.ConfigRequest) + com.google.protobuf.MessageOrBuilder { + + /** + * .agent.CollectorModule module = 1; + * @return The enum numeric value on the wire for module. + */ + int getModuleValue(); + /** + * .agent.CollectorModule module = 1; + * @return The module. + */ + agent.CollectorOuterClass.CollectorModule getModule(); + } + /** + * Protobuf type {@code agent.ConfigRequest} + */ + public static final class ConfigRequest extends + com.google.protobuf.GeneratedMessage implements + // @@protoc_insertion_point(message_implements:agent.ConfigRequest) + ConfigRequestOrBuilder { + private static final long serialVersionUID = 0L; + static { + com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( + com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, + /* major= */ 4, + /* minor= */ 29, + /* patch= */ 3, + /* suffix= */ "", + ConfigRequest.class.getName()); + } + // Use ConfigRequest.newBuilder() to construct. + private ConfigRequest(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + } + private ConfigRequest() { + module_ = 0; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_ConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_ConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.ConfigRequest.class, agent.CollectorOuterClass.ConfigRequest.Builder.class); + } + + public static final int MODULE_FIELD_NUMBER = 1; + private int module_ = 0; + /** + * .agent.CollectorModule module = 1; + * @return The enum numeric value on the wire for module. + */ + @java.lang.Override public int getModuleValue() { + return module_; + } + /** + * .agent.CollectorModule module = 1; + * @return The module. + */ + @java.lang.Override public agent.CollectorOuterClass.CollectorModule getModule() { + agent.CollectorOuterClass.CollectorModule result = agent.CollectorOuterClass.CollectorModule.forNumber(module_); + return result == null ? agent.CollectorOuterClass.CollectorModule.UNRECOGNIZED : result; + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (module_ != agent.CollectorOuterClass.CollectorModule.AS_400.getNumber()) { + output.writeEnum(1, module_); + } + getUnknownFields().writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (module_ != agent.CollectorOuterClass.CollectorModule.AS_400.getNumber()) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(1, module_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof agent.CollectorOuterClass.ConfigRequest)) { + return super.equals(obj); + } + agent.CollectorOuterClass.ConfigRequest other = (agent.CollectorOuterClass.ConfigRequest) obj; + + if (module_ != other.module_) return false; + if (!getUnknownFields().equals(other.getUnknownFields())) return false; + return true; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + MODULE_FIELD_NUMBER; + hash = (53 * hash) + module_; + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static agent.CollectorOuterClass.ConfigRequest parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.ConfigRequest parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.ConfigRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.ConfigRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.ConfigRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static agent.CollectorOuterClass.ConfigRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static agent.CollectorOuterClass.ConfigRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.ConfigRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static agent.CollectorOuterClass.ConfigRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input); + } + + public static agent.CollectorOuterClass.ConfigRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static agent.CollectorOuterClass.ConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input); + } + public static agent.CollectorOuterClass.ConfigRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessage + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(agent.CollectorOuterClass.ConfigRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code agent.ConfigRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder implements + // @@protoc_insertion_point(builder_implements:agent.ConfigRequest) + agent.CollectorOuterClass.ConfigRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return agent.CollectorOuterClass.internal_static_agent_ConfigRequest_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return agent.CollectorOuterClass.internal_static_agent_ConfigRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + agent.CollectorOuterClass.ConfigRequest.class, agent.CollectorOuterClass.ConfigRequest.Builder.class); + } + + // Construct using agent.CollectorOuterClass.ConfigRequest.newBuilder() + private Builder() { + + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + + } + @java.lang.Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + module_ = 0; + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return agent.CollectorOuterClass.internal_static_agent_ConfigRequest_descriptor; + } + + @java.lang.Override + public agent.CollectorOuterClass.ConfigRequest getDefaultInstanceForType() { + return agent.CollectorOuterClass.ConfigRequest.getDefaultInstance(); + } + + @java.lang.Override + public agent.CollectorOuterClass.ConfigRequest build() { + agent.CollectorOuterClass.ConfigRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public agent.CollectorOuterClass.ConfigRequest buildPartial() { + agent.CollectorOuterClass.ConfigRequest result = new agent.CollectorOuterClass.ConfigRequest(this); + if (bitField0_ != 0) { buildPartial0(result); } + onBuilt(); + return result; + } + + private void buildPartial0(agent.CollectorOuterClass.ConfigRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.module_ = module_; + } + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof agent.CollectorOuterClass.ConfigRequest) { + return mergeFrom((agent.CollectorOuterClass.ConfigRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(agent.CollectorOuterClass.ConfigRequest other) { + if (other == agent.CollectorOuterClass.ConfigRequest.getDefaultInstance()) return this; + if (other.module_ != 0) { + setModuleValue(other.getModuleValue()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 8: { + module_ = input.readEnum(); + bitField0_ |= 0x00000001; + break; + } // case 8 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + private int bitField0_; + + private int module_ = 0; + /** + * .agent.CollectorModule module = 1; + * @return The enum numeric value on the wire for module. + */ + @java.lang.Override public int getModuleValue() { + return module_; + } + /** + * .agent.CollectorModule module = 1; + * @param value The enum numeric value on the wire for module to set. + * @return This builder for chaining. + */ + public Builder setModuleValue(int value) { + module_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + /** + * .agent.CollectorModule module = 1; + * @return The module. + */ + @java.lang.Override + public agent.CollectorOuterClass.CollectorModule getModule() { + agent.CollectorOuterClass.CollectorModule result = agent.CollectorOuterClass.CollectorModule.forNumber(module_); + return result == null ? agent.CollectorOuterClass.CollectorModule.UNRECOGNIZED : result; + } + /** + * .agent.CollectorModule module = 1; + * @param value The module to set. + * @return This builder for chaining. + */ + public Builder setModule(agent.CollectorOuterClass.CollectorModule value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + module_ = value.getNumber(); + onChanged(); + return this; + } + /** + * .agent.CollectorModule module = 1; + * @return This builder for chaining. + */ + public Builder clearModule() { + bitField0_ = (bitField0_ & ~0x00000001); + module_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:agent.ConfigRequest) + } + + // @@protoc_insertion_point(class_scope:agent.ConfigRequest) + private static final agent.CollectorOuterClass.ConfigRequest DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new agent.CollectorOuterClass.ConfigRequest(); + } + + public static agent.CollectorOuterClass.ConfigRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ConfigRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public agent.CollectorOuterClass.ConfigRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_agent_RegisterRequest_descriptor; + private static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_agent_RegisterRequest_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_agent_ListCollectorResponse_descriptor; + private static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_agent_ListCollectorResponse_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_agent_Collector_descriptor; + private static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_agent_Collector_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_agent_CollectorMessages_descriptor; + private static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_agent_CollectorMessages_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_agent_CollectorConfig_descriptor; + private static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_agent_CollectorConfig_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_agent_CollectorConfigGroup_descriptor; + private static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_agent_CollectorConfigGroup_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_agent_CollectorGroupConfigurations_descriptor; + private static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_agent_CollectorGroupConfigurations_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_agent_ConfigKnowledge_descriptor; + private static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_agent_ConfigKnowledge_fieldAccessorTable; + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_agent_ConfigRequest_descriptor; + private static final + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_agent_ConfigRequest_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\017collector.proto\022\005agent\032\014common.proto\"k" + + "\n\017RegisterRequest\022\n\n\002ip\030\001 \001(\t\022\020\n\010hostnam" + + "e\030\002 \001(\t\022\017\n\007version\030\003 \001(\t\022)\n\tcollector\030\004 " + + "\001(\0162\026.agent.CollectorModule\"F\n\025ListColle" + + "ctorResponse\022\036\n\004rows\030\001 \003(\0132\020.agent.Colle" + + "ctor\022\r\n\005total\030\002 \001(\005\"\267\001\n\tCollector\022\n\n\002id\030" + + "\001 \001(\005\022\035\n\006status\030\002 \001(\0162\r.agent.Status\022\025\n\r" + + "collector_key\030\003 \001(\t\022\n\n\002ip\030\004 \001(\t\022\020\n\010hostn" + + "ame\030\005 \001(\t\022\017\n\007version\030\006 \001(\t\022&\n\006module\030\007 \001" + + "(\0162\026.agent.CollectorModule\022\021\n\tlast_seen\030" + + "\010 \001(\t\"y\n\021CollectorMessages\022(\n\006config\030\001 \001" + + "(\0132\026.agent.CollectorConfigH\000\022(\n\006result\030\002" + + " \001(\0132\026.agent.ConfigKnowledgeH\000B\020\n\016stream" + + "_message\"h\n\017CollectorConfig\022\024\n\014collector" + + "_id\030\001 \001(\t\022+\n\006groups\030\002 \003(\0132\033.agent.Collec" + + "torConfigGroup\022\022\n\nrequest_id\030\003 \001(\t\"\244\001\n\024C" + + "ollectorConfigGroup\022\n\n\002id\030\001 \001(\005\022\022\n\ngroup" + + "_name\030\002 \001(\t\022\031\n\021group_description\030\003 \001(\t\022;" + + "\n\016configurations\030\004 \003(\0132#.agent.Collector" + + "GroupConfigurations\022\024\n\014collector_id\030\005 \001(" + + "\005\"\276\001\n\034CollectorGroupConfigurations\022\n\n\002id" + + "\030\001 \001(\005\022\020\n\010group_id\030\002 \001(\005\022\020\n\010conf_key\030\003 \001" + + "(\t\022\022\n\nconf_value\030\004 \001(\t\022\021\n\tconf_name\030\005 \001(" + + "\t\022\030\n\020conf_description\030\006 \001(\t\022\026\n\016conf_data" + + "_type\030\007 \001(\t\022\025\n\rconf_required\030\010 \001(\010\"7\n\017Co" + + "nfigKnowledge\022\020\n\010accepted\030\001 \001(\t\022\022\n\nreque" + + "st_id\030\002 \001(\t\"7\n\rConfigRequest\022&\n\006module\030\001" + + " \001(\0162\026.agent.CollectorModule*+\n\017Collecto" + + "rModule\022\n\n\006AS_400\020\000\022\014\n\010UTMSTACK\020\0012\356\002\n\020Co" + + "llectorService\022B\n\021RegisterCollector\022\026.ag" + + "ent.RegisterRequest\032\023.agent.AuthResponse" + + "\"\000\022>\n\017DeleteCollector\022\024.agent.DeleteRequ" + + "est\032\023.agent.AuthResponse\"\000\022C\n\rListCollec" + + "tor\022\022.agent.ListRequest\032\034.agent.ListColl" + + "ectorResponse\"\000\022K\n\017CollectorStream\022\030.age" + + "nt.CollectorMessages\032\030.agent.CollectorMe" + + "ssages\"\000(\0010\001\022D\n\022GetCollectorConfig\022\024.age" + + "nt.ConfigRequest\032\026.agent.CollectorConfig" + + "\"\0002d\n\025PanelCollectorService\022K\n\027RegisterC" + + "ollectorConfig\022\026.agent.CollectorConfig\032\026" + + ".agent.ConfigKnowledge\"\000B2Z0github.com/u" + + "tmstack/UTMStack/agent-manager/agentb\006pr" + + "oto3" + }; + descriptor = com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + com.park.utmstack.service.grpc.Common.getDescriptor(), + }); + internal_static_agent_RegisterRequest_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_agent_RegisterRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_agent_RegisterRequest_descriptor, + new java.lang.String[] { "Ip", "Hostname", "Version", "Collector", }); + internal_static_agent_ListCollectorResponse_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_agent_ListCollectorResponse_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_agent_ListCollectorResponse_descriptor, + new java.lang.String[] { "Rows", "Total", }); + internal_static_agent_Collector_descriptor = + getDescriptor().getMessageTypes().get(2); + internal_static_agent_Collector_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_agent_Collector_descriptor, + new java.lang.String[] { "Id", "Status", "CollectorKey", "Ip", "Hostname", "Version", "Module", "LastSeen", }); + internal_static_agent_CollectorMessages_descriptor = + getDescriptor().getMessageTypes().get(3); + internal_static_agent_CollectorMessages_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_agent_CollectorMessages_descriptor, + new java.lang.String[] { "Config", "Result", "StreamMessage", }); + internal_static_agent_CollectorConfig_descriptor = + getDescriptor().getMessageTypes().get(4); + internal_static_agent_CollectorConfig_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_agent_CollectorConfig_descriptor, + new java.lang.String[] { "CollectorId", "Groups", "RequestId", }); + internal_static_agent_CollectorConfigGroup_descriptor = + getDescriptor().getMessageTypes().get(5); + internal_static_agent_CollectorConfigGroup_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_agent_CollectorConfigGroup_descriptor, + new java.lang.String[] { "Id", "GroupName", "GroupDescription", "Configurations", "CollectorId", }); + internal_static_agent_CollectorGroupConfigurations_descriptor = + getDescriptor().getMessageTypes().get(6); + internal_static_agent_CollectorGroupConfigurations_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_agent_CollectorGroupConfigurations_descriptor, + new java.lang.String[] { "Id", "GroupId", "ConfKey", "ConfValue", "ConfName", "ConfDescription", "ConfDataType", "ConfRequired", }); + internal_static_agent_ConfigKnowledge_descriptor = + getDescriptor().getMessageTypes().get(7); + internal_static_agent_ConfigKnowledge_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_agent_ConfigKnowledge_descriptor, + new java.lang.String[] { "Accepted", "RequestId", }); + internal_static_agent_ConfigRequest_descriptor = + getDescriptor().getMessageTypes().get(8); + internal_static_agent_ConfigRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_agent_ConfigRequest_descriptor, + new java.lang.String[] { "Module", }); + descriptor.resolveAllFeaturesImmutable(); + com.park.utmstack.service.grpc.Common.getDescriptor(); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/backend/src/main/java/agent/CollectorServiceGrpc.java b/backend/src/main/java/agent/CollectorServiceGrpc.java new file mode 100644 index 000000000..8e1d81f22 --- /dev/null +++ b/backend/src/main/java/agent/CollectorServiceGrpc.java @@ -0,0 +1,573 @@ +package agent; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.65.1)", + comments = "Source: collector.proto") +@io.grpc.stub.annotations.GrpcGenerated +public final class CollectorServiceGrpc { + + private CollectorServiceGrpc() {} + + public static final java.lang.String SERVICE_NAME = "agent.CollectorService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getRegisterCollectorMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "RegisterCollector", + requestType = agent.CollectorOuterClass.RegisterRequest.class, + responseType = com.park.utmstack.service.grpc.AuthResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getRegisterCollectorMethod() { + io.grpc.MethodDescriptor getRegisterCollectorMethod; + if ((getRegisterCollectorMethod = CollectorServiceGrpc.getRegisterCollectorMethod) == null) { + synchronized (CollectorServiceGrpc.class) { + if ((getRegisterCollectorMethod = CollectorServiceGrpc.getRegisterCollectorMethod) == null) { + CollectorServiceGrpc.getRegisterCollectorMethod = getRegisterCollectorMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "RegisterCollector")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + agent.CollectorOuterClass.RegisterRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + com.park.utmstack.service.grpc.AuthResponse.getDefaultInstance())) + .setSchemaDescriptor(new CollectorServiceMethodDescriptorSupplier("RegisterCollector")) + .build(); + } + } + } + return getRegisterCollectorMethod; + } + + private static volatile io.grpc.MethodDescriptor getDeleteCollectorMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "DeleteCollector", + requestType = com.park.utmstack.service.grpc.DeleteRequest.class, + responseType = com.park.utmstack.service.grpc.AuthResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getDeleteCollectorMethod() { + io.grpc.MethodDescriptor getDeleteCollectorMethod; + if ((getDeleteCollectorMethod = CollectorServiceGrpc.getDeleteCollectorMethod) == null) { + synchronized (CollectorServiceGrpc.class) { + if ((getDeleteCollectorMethod = CollectorServiceGrpc.getDeleteCollectorMethod) == null) { + CollectorServiceGrpc.getDeleteCollectorMethod = getDeleteCollectorMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "DeleteCollector")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + com.park.utmstack.service.grpc.DeleteRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + com.park.utmstack.service.grpc.AuthResponse.getDefaultInstance())) + .setSchemaDescriptor(new CollectorServiceMethodDescriptorSupplier("DeleteCollector")) + .build(); + } + } + } + return getDeleteCollectorMethod; + } + + private static volatile io.grpc.MethodDescriptor getListCollectorMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "ListCollector", + requestType = com.park.utmstack.service.grpc.ListRequest.class, + responseType = agent.CollectorOuterClass.ListCollectorResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getListCollectorMethod() { + io.grpc.MethodDescriptor getListCollectorMethod; + if ((getListCollectorMethod = CollectorServiceGrpc.getListCollectorMethod) == null) { + synchronized (CollectorServiceGrpc.class) { + if ((getListCollectorMethod = CollectorServiceGrpc.getListCollectorMethod) == null) { + CollectorServiceGrpc.getListCollectorMethod = getListCollectorMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "ListCollector")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + com.park.utmstack.service.grpc.ListRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + agent.CollectorOuterClass.ListCollectorResponse.getDefaultInstance())) + .setSchemaDescriptor(new CollectorServiceMethodDescriptorSupplier("ListCollector")) + .build(); + } + } + } + return getListCollectorMethod; + } + + private static volatile io.grpc.MethodDescriptor getCollectorStreamMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "CollectorStream", + requestType = agent.CollectorOuterClass.CollectorMessages.class, + responseType = agent.CollectorOuterClass.CollectorMessages.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getCollectorStreamMethod() { + io.grpc.MethodDescriptor getCollectorStreamMethod; + if ((getCollectorStreamMethod = CollectorServiceGrpc.getCollectorStreamMethod) == null) { + synchronized (CollectorServiceGrpc.class) { + if ((getCollectorStreamMethod = CollectorServiceGrpc.getCollectorStreamMethod) == null) { + CollectorServiceGrpc.getCollectorStreamMethod = getCollectorStreamMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "CollectorStream")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + agent.CollectorOuterClass.CollectorMessages.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + agent.CollectorOuterClass.CollectorMessages.getDefaultInstance())) + .setSchemaDescriptor(new CollectorServiceMethodDescriptorSupplier("CollectorStream")) + .build(); + } + } + } + return getCollectorStreamMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetCollectorConfigMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "GetCollectorConfig", + requestType = agent.CollectorOuterClass.ConfigRequest.class, + responseType = agent.CollectorOuterClass.CollectorConfig.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetCollectorConfigMethod() { + io.grpc.MethodDescriptor getGetCollectorConfigMethod; + if ((getGetCollectorConfigMethod = CollectorServiceGrpc.getGetCollectorConfigMethod) == null) { + synchronized (CollectorServiceGrpc.class) { + if ((getGetCollectorConfigMethod = CollectorServiceGrpc.getGetCollectorConfigMethod) == null) { + CollectorServiceGrpc.getGetCollectorConfigMethod = getGetCollectorConfigMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "GetCollectorConfig")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + agent.CollectorOuterClass.ConfigRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + agent.CollectorOuterClass.CollectorConfig.getDefaultInstance())) + .setSchemaDescriptor(new CollectorServiceMethodDescriptorSupplier("GetCollectorConfig")) + .build(); + } + } + } + return getGetCollectorConfigMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static CollectorServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public CollectorServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CollectorServiceStub(channel, callOptions); + } + }; + return CollectorServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static CollectorServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public CollectorServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CollectorServiceBlockingStub(channel, callOptions); + } + }; + return CollectorServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static CollectorServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public CollectorServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CollectorServiceFutureStub(channel, callOptions); + } + }; + return CollectorServiceFutureStub.newStub(factory, channel); + } + + /** + */ + public interface AsyncService { + + /** + */ + default void registerCollector(agent.CollectorOuterClass.RegisterRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getRegisterCollectorMethod(), responseObserver); + } + + /** + */ + default void deleteCollector(com.park.utmstack.service.grpc.DeleteRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getDeleteCollectorMethod(), responseObserver); + } + + /** + */ + default void listCollector(com.park.utmstack.service.grpc.ListRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getListCollectorMethod(), responseObserver); + } + + /** + */ + default io.grpc.stub.StreamObserver collectorStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall(getCollectorStreamMethod(), responseObserver); + } + + /** + */ + default void getCollectorConfig(agent.CollectorOuterClass.ConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetCollectorConfigMethod(), responseObserver); + } + } + + /** + * Base class for the server implementation of the service CollectorService. + */ + public static abstract class CollectorServiceImplBase + implements io.grpc.BindableService, AsyncService { + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return CollectorServiceGrpc.bindService(this); + } + } + + /** + * A stub to allow clients to do asynchronous rpc calls to service CollectorService. + */ + public static final class CollectorServiceStub + extends io.grpc.stub.AbstractAsyncStub { + private CollectorServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected CollectorServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CollectorServiceStub(channel, callOptions); + } + + /** + */ + public void registerCollector(agent.CollectorOuterClass.RegisterRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getRegisterCollectorMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void deleteCollector(com.park.utmstack.service.grpc.DeleteRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getDeleteCollectorMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void listCollector(com.park.utmstack.service.grpc.ListRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getListCollectorMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver collectorStream( + io.grpc.stub.StreamObserver responseObserver) { + return io.grpc.stub.ClientCalls.asyncBidiStreamingCall( + getChannel().newCall(getCollectorStreamMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public void getCollectorConfig(agent.CollectorOuterClass.ConfigRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetCollectorConfigMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + * A stub to allow clients to do synchronous rpc calls to service CollectorService. + */ + public static final class CollectorServiceBlockingStub + extends io.grpc.stub.AbstractBlockingStub { + private CollectorServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected CollectorServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CollectorServiceBlockingStub(channel, callOptions); + } + + /** + */ + public com.park.utmstack.service.grpc.AuthResponse registerCollector(agent.CollectorOuterClass.RegisterRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getRegisterCollectorMethod(), getCallOptions(), request); + } + + /** + */ + public com.park.utmstack.service.grpc.AuthResponse deleteCollector(com.park.utmstack.service.grpc.DeleteRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getDeleteCollectorMethod(), getCallOptions(), request); + } + + /** + */ + public agent.CollectorOuterClass.ListCollectorResponse listCollector(com.park.utmstack.service.grpc.ListRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getListCollectorMethod(), getCallOptions(), request); + } + + /** + */ + public agent.CollectorOuterClass.CollectorConfig getCollectorConfig(agent.CollectorOuterClass.ConfigRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetCollectorConfigMethod(), getCallOptions(), request); + } + } + + /** + * A stub to allow clients to do ListenableFuture-style rpc calls to service CollectorService. + */ + public static final class CollectorServiceFutureStub + extends io.grpc.stub.AbstractFutureStub { + private CollectorServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected CollectorServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new CollectorServiceFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture registerCollector( + agent.CollectorOuterClass.RegisterRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getRegisterCollectorMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture deleteCollector( + com.park.utmstack.service.grpc.DeleteRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getDeleteCollectorMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture listCollector( + com.park.utmstack.service.grpc.ListRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getListCollectorMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture getCollectorConfig( + agent.CollectorOuterClass.ConfigRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetCollectorConfigMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_REGISTER_COLLECTOR = 0; + private static final int METHODID_DELETE_COLLECTOR = 1; + private static final int METHODID_LIST_COLLECTOR = 2; + private static final int METHODID_GET_COLLECTOR_CONFIG = 3; + private static final int METHODID_COLLECTOR_STREAM = 4; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final AsyncService serviceImpl; + private final int methodId; + + MethodHandlers(AsyncService serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_REGISTER_COLLECTOR: + serviceImpl.registerCollector((agent.CollectorOuterClass.RegisterRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_DELETE_COLLECTOR: + serviceImpl.deleteCollector((com.park.utmstack.service.grpc.DeleteRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_LIST_COLLECTOR: + serviceImpl.listCollector((com.park.utmstack.service.grpc.ListRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_COLLECTOR_CONFIG: + serviceImpl.getCollectorConfig((agent.CollectorOuterClass.ConfigRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_COLLECTOR_STREAM: + return (io.grpc.stub.StreamObserver) serviceImpl.collectorStream( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getRegisterCollectorMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + agent.CollectorOuterClass.RegisterRequest, + com.park.utmstack.service.grpc.AuthResponse>( + service, METHODID_REGISTER_COLLECTOR))) + .addMethod( + getDeleteCollectorMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + com.park.utmstack.service.grpc.DeleteRequest, + com.park.utmstack.service.grpc.AuthResponse>( + service, METHODID_DELETE_COLLECTOR))) + .addMethod( + getListCollectorMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + com.park.utmstack.service.grpc.ListRequest, + agent.CollectorOuterClass.ListCollectorResponse>( + service, METHODID_LIST_COLLECTOR))) + .addMethod( + getCollectorStreamMethod(), + io.grpc.stub.ServerCalls.asyncBidiStreamingCall( + new MethodHandlers< + agent.CollectorOuterClass.CollectorMessages, + agent.CollectorOuterClass.CollectorMessages>( + service, METHODID_COLLECTOR_STREAM))) + .addMethod( + getGetCollectorConfigMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + agent.CollectorOuterClass.ConfigRequest, + agent.CollectorOuterClass.CollectorConfig>( + service, METHODID_GET_COLLECTOR_CONFIG))) + .build(); + } + + private static abstract class CollectorServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + CollectorServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return agent.CollectorOuterClass.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("CollectorService"); + } + } + + private static final class CollectorServiceFileDescriptorSupplier + extends CollectorServiceBaseDescriptorSupplier { + CollectorServiceFileDescriptorSupplier() {} + } + + private static final class CollectorServiceMethodDescriptorSupplier + extends CollectorServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final java.lang.String methodName; + + CollectorServiceMethodDescriptorSupplier(java.lang.String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (CollectorServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new CollectorServiceFileDescriptorSupplier()) + .addMethod(getRegisterCollectorMethod()) + .addMethod(getDeleteCollectorMethod()) + .addMethod(getListCollectorMethod()) + .addMethod(getCollectorStreamMethod()) + .addMethod(getGetCollectorConfigMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/backend/src/main/java/agent/PanelCollectorServiceGrpc.java b/backend/src/main/java/agent/PanelCollectorServiceGrpc.java new file mode 100644 index 000000000..e6d014150 --- /dev/null +++ b/backend/src/main/java/agent/PanelCollectorServiceGrpc.java @@ -0,0 +1,293 @@ +package agent; + +import static io.grpc.MethodDescriptor.generateFullMethodName; + +/** + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler (version 1.65.1)", + comments = "Source: collector.proto") +@io.grpc.stub.annotations.GrpcGenerated +public final class PanelCollectorServiceGrpc { + + private PanelCollectorServiceGrpc() {} + + public static final java.lang.String SERVICE_NAME = "agent.PanelCollectorService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getRegisterCollectorConfigMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "RegisterCollectorConfig", + requestType = agent.CollectorOuterClass.CollectorConfig.class, + responseType = agent.CollectorOuterClass.ConfigKnowledge.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getRegisterCollectorConfigMethod() { + io.grpc.MethodDescriptor getRegisterCollectorConfigMethod; + if ((getRegisterCollectorConfigMethod = PanelCollectorServiceGrpc.getRegisterCollectorConfigMethod) == null) { + synchronized (PanelCollectorServiceGrpc.class) { + if ((getRegisterCollectorConfigMethod = PanelCollectorServiceGrpc.getRegisterCollectorConfigMethod) == null) { + PanelCollectorServiceGrpc.getRegisterCollectorConfigMethod = getRegisterCollectorConfigMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "RegisterCollectorConfig")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + agent.CollectorOuterClass.CollectorConfig.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + agent.CollectorOuterClass.ConfigKnowledge.getDefaultInstance())) + .setSchemaDescriptor(new PanelCollectorServiceMethodDescriptorSupplier("RegisterCollectorConfig")) + .build(); + } + } + } + return getRegisterCollectorConfigMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static PanelCollectorServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public PanelCollectorServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PanelCollectorServiceStub(channel, callOptions); + } + }; + return PanelCollectorServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static PanelCollectorServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public PanelCollectorServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PanelCollectorServiceBlockingStub(channel, callOptions); + } + }; + return PanelCollectorServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static PanelCollectorServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public PanelCollectorServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PanelCollectorServiceFutureStub(channel, callOptions); + } + }; + return PanelCollectorServiceFutureStub.newStub(factory, channel); + } + + /** + */ + public interface AsyncService { + + /** + */ + default void registerCollectorConfig(agent.CollectorOuterClass.CollectorConfig request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getRegisterCollectorConfigMethod(), responseObserver); + } + } + + /** + * Base class for the server implementation of the service PanelCollectorService. + */ + public static abstract class PanelCollectorServiceImplBase + implements io.grpc.BindableService, AsyncService { + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return PanelCollectorServiceGrpc.bindService(this); + } + } + + /** + * A stub to allow clients to do asynchronous rpc calls to service PanelCollectorService. + */ + public static final class PanelCollectorServiceStub + extends io.grpc.stub.AbstractAsyncStub { + private PanelCollectorServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected PanelCollectorServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PanelCollectorServiceStub(channel, callOptions); + } + + /** + */ + public void registerCollectorConfig(agent.CollectorOuterClass.CollectorConfig request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getRegisterCollectorConfigMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + * A stub to allow clients to do synchronous rpc calls to service PanelCollectorService. + */ + public static final class PanelCollectorServiceBlockingStub + extends io.grpc.stub.AbstractBlockingStub { + private PanelCollectorServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected PanelCollectorServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PanelCollectorServiceBlockingStub(channel, callOptions); + } + + /** + */ + public agent.CollectorOuterClass.ConfigKnowledge registerCollectorConfig(agent.CollectorOuterClass.CollectorConfig request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getRegisterCollectorConfigMethod(), getCallOptions(), request); + } + } + + /** + * A stub to allow clients to do ListenableFuture-style rpc calls to service PanelCollectorService. + */ + public static final class PanelCollectorServiceFutureStub + extends io.grpc.stub.AbstractFutureStub { + private PanelCollectorServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected PanelCollectorServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new PanelCollectorServiceFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture registerCollectorConfig( + agent.CollectorOuterClass.CollectorConfig request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getRegisterCollectorConfigMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_REGISTER_COLLECTOR_CONFIG = 0; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final AsyncService serviceImpl; + private final int methodId; + + MethodHandlers(AsyncService serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_REGISTER_COLLECTOR_CONFIG: + serviceImpl.registerCollectorConfig((agent.CollectorOuterClass.CollectorConfig) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + } + + public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getRegisterCollectorConfigMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + agent.CollectorOuterClass.CollectorConfig, + agent.CollectorOuterClass.ConfigKnowledge>( + service, METHODID_REGISTER_COLLECTOR_CONFIG))) + .build(); + } + + private static abstract class PanelCollectorServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + PanelCollectorServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return agent.CollectorOuterClass.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("PanelCollectorService"); + } + } + + private static final class PanelCollectorServiceFileDescriptorSupplier + extends PanelCollectorServiceBaseDescriptorSupplier { + PanelCollectorServiceFileDescriptorSupplier() {} + } + + private static final class PanelCollectorServiceMethodDescriptorSupplier + extends PanelCollectorServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final java.lang.String methodName; + + PanelCollectorServiceMethodDescriptorSupplier(java.lang.String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (PanelCollectorServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new PanelCollectorServiceFileDescriptorSupplier()) + .addMethod(getRegisterCollectorConfigMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/backend/src/main/java/com/park/utmstack/service/grpc/AgentManagerGrpc.java b/backend/src/main/java/com/park/utmstack/service/grpc/AgentManagerGrpc.java index b72898c05..4311bb7a1 100644 --- a/backend/src/main/java/com/park/utmstack/service/grpc/AgentManagerGrpc.java +++ b/backend/src/main/java/com/park/utmstack/service/grpc/AgentManagerGrpc.java @@ -111,9 +111,9 @@ public static void registerAllExtensions( "\n\013origin_type\030\n \001(\t\022\021\n\torigin_id\030\013 \001(\t*W" + "\n\022AgentCommandStatus\022\020\n\014NOT_EXECUTED\020\000\022\t" + "\n\005QUEUE\020\001\022\013\n\007PENDING\020\002\022\014\n\010EXECUTED\020\003\022\t\n\005" + - "ERROR\020\0042\234\003\n\014AgentService\0229\n\013UpdateAgent\022" + - "\023.agent.AgentRequest\032\023.agent.AuthRespons" + - "e\"\000\022;\n\rRegisterAgent\022\023.agent.AgentReques" + + "ERROR\020\0042\234\003\n\014AgentService\022;\n\rRegisterAgen" + + "t\022\023.agent.AgentRequest\032\023.agent.AuthRespo" + + "nse\"\000\0229\n\013UpdateAgent\022\023.agent.AgentReques" + "t\032\023.agent.AuthResponse\"\000\022:\n\013DeleteAgent\022" + "\024.agent.DeleteRequest\032\023.agent.AuthRespon" + "se\"\000\022=\n\nListAgents\022\022.agent.ListRequest\032\031" + diff --git a/backend/src/main/java/com/park/utmstack/service/grpc/AgentService.java b/backend/src/main/java/com/park/utmstack/service/grpc/AgentService.java index b731670a5..5cc24081b 100644 --- a/backend/src/main/java/com/park/utmstack/service/grpc/AgentService.java +++ b/backend/src/main/java/com/park/utmstack/service/grpc/AgentService.java @@ -14,17 +14,17 @@ protected AgentService() {} public interface Interface { /** - * rpc UpdateAgent(.agent.AgentRequest) returns (.agent.AuthResponse); + * rpc RegisterAgent(.agent.AgentRequest) returns (.agent.AuthResponse); */ - public abstract void updateAgent( + public abstract void registerAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request, com.google.protobuf.RpcCallback done); /** - * rpc RegisterAgent(.agent.AgentRequest) returns (.agent.AuthResponse); + * rpc UpdateAgent(.agent.AgentRequest) returns (.agent.AuthResponse); */ - public abstract void registerAgent( + public abstract void updateAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request, com.google.protobuf.RpcCallback done); @@ -67,19 +67,19 @@ public static com.google.protobuf.Service newReflectiveService( final Interface impl) { return new AgentService() { @java.lang.Override - public void updateAgent( + public void registerAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request, com.google.protobuf.RpcCallback done) { - impl.updateAgent(controller, request, done); + impl.registerAgent(controller, request, done); } @java.lang.Override - public void registerAgent( + public void updateAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request, com.google.protobuf.RpcCallback done) { - impl.registerAgent(controller, request, done); + impl.updateAgent(controller, request, done); } @java.lang.Override @@ -137,9 +137,9 @@ public final com.google.protobuf.Message callBlockingMethod( } switch(method.getIndex()) { case 0: - return impl.updateAgent(controller, (com.park.utmstack.service.grpc.AgentRequest)request); - case 1: return impl.registerAgent(controller, (com.park.utmstack.service.grpc.AgentRequest)request); + case 1: + return impl.updateAgent(controller, (com.park.utmstack.service.grpc.AgentRequest)request); case 2: return impl.deleteAgent(controller, (com.park.utmstack.service.grpc.DeleteRequest)request); case 3: @@ -209,17 +209,17 @@ public final com.google.protobuf.Message callBlockingMethod( } /** - * rpc UpdateAgent(.agent.AgentRequest) returns (.agent.AuthResponse); + * rpc RegisterAgent(.agent.AgentRequest) returns (.agent.AuthResponse); */ - public abstract void updateAgent( + public abstract void registerAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request, com.google.protobuf.RpcCallback done); /** - * rpc RegisterAgent(.agent.AgentRequest) returns (.agent.AuthResponse); + * rpc UpdateAgent(.agent.AgentRequest) returns (.agent.AuthResponse); */ - public abstract void registerAgent( + public abstract void updateAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request, com.google.protobuf.RpcCallback done); @@ -279,12 +279,12 @@ public final void callMethod( } switch(method.getIndex()) { case 0: - this.updateAgent(controller, (com.park.utmstack.service.grpc.AgentRequest)request, + this.registerAgent(controller, (com.park.utmstack.service.grpc.AgentRequest)request, com.google.protobuf.RpcUtil.specializeCallback( done)); return; case 1: - this.registerAgent(controller, (com.park.utmstack.service.grpc.AgentRequest)request, + this.updateAgent(controller, (com.park.utmstack.service.grpc.AgentRequest)request, com.google.protobuf.RpcUtil.specializeCallback( done)); return; @@ -381,7 +381,7 @@ public com.google.protobuf.RpcChannel getChannel() { return channel; } - public void updateAgent( + public void registerAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request, com.google.protobuf.RpcCallback done) { @@ -396,7 +396,7 @@ public void updateAgent( com.park.utmstack.service.grpc.AuthResponse.getDefaultInstance())); } - public void registerAgent( + public void updateAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request, com.google.protobuf.RpcCallback done) { @@ -478,12 +478,12 @@ public static BlockingInterface newBlockingStub( } public interface BlockingInterface { - public com.park.utmstack.service.grpc.AuthResponse updateAgent( + public com.park.utmstack.service.grpc.AuthResponse registerAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request) throws com.google.protobuf.ServiceException; - public com.park.utmstack.service.grpc.AuthResponse registerAgent( + public com.park.utmstack.service.grpc.AuthResponse updateAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request) throws com.google.protobuf.ServiceException; @@ -516,7 +516,7 @@ private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) { private final com.google.protobuf.BlockingRpcChannel channel; - public com.park.utmstack.service.grpc.AuthResponse updateAgent( + public com.park.utmstack.service.grpc.AuthResponse registerAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request) throws com.google.protobuf.ServiceException { @@ -528,7 +528,7 @@ public com.park.utmstack.service.grpc.AuthResponse updateAgent( } - public com.park.utmstack.service.grpc.AuthResponse registerAgent( + public com.park.utmstack.service.grpc.AuthResponse updateAgent( com.google.protobuf.RpcController controller, com.park.utmstack.service.grpc.AgentRequest request) throws com.google.protobuf.ServiceException { diff --git a/backend/src/main/java/com/park/utmstack/service/grpc/AgentServiceGrpc.java b/backend/src/main/java/com/park/utmstack/service/grpc/AgentServiceGrpc.java index 82d648019..a49da0020 100644 --- a/backend/src/main/java/com/park/utmstack/service/grpc/AgentServiceGrpc.java +++ b/backend/src/main/java/com/park/utmstack/service/grpc/AgentServiceGrpc.java @@ -16,65 +16,65 @@ private AgentServiceGrpc() {} // Static method descriptors that strictly reflect the proto. private static volatile io.grpc.MethodDescriptor getUpdateAgentMethod; + com.park.utmstack.service.grpc.AuthResponse> getRegisterAgentMethod; @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "UpdateAgent", + fullMethodName = SERVICE_NAME + '/' + "RegisterAgent", requestType = com.park.utmstack.service.grpc.AgentRequest.class, responseType = com.park.utmstack.service.grpc.AuthResponse.class, methodType = io.grpc.MethodDescriptor.MethodType.UNARY) public static io.grpc.MethodDescriptor getUpdateAgentMethod() { - io.grpc.MethodDescriptor getUpdateAgentMethod; - if ((getUpdateAgentMethod = AgentServiceGrpc.getUpdateAgentMethod) == null) { + com.park.utmstack.service.grpc.AuthResponse> getRegisterAgentMethod() { + io.grpc.MethodDescriptor getRegisterAgentMethod; + if ((getRegisterAgentMethod = AgentServiceGrpc.getRegisterAgentMethod) == null) { synchronized (AgentServiceGrpc.class) { - if ((getUpdateAgentMethod = AgentServiceGrpc.getUpdateAgentMethod) == null) { - AgentServiceGrpc.getUpdateAgentMethod = getUpdateAgentMethod = + if ((getRegisterAgentMethod = AgentServiceGrpc.getRegisterAgentMethod) == null) { + AgentServiceGrpc.getRegisterAgentMethod = getRegisterAgentMethod = io.grpc.MethodDescriptor.newBuilder() .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "UpdateAgent")) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "RegisterAgent")) .setSampledToLocalTracing(true) .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( com.park.utmstack.service.grpc.AgentRequest.getDefaultInstance())) .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( com.park.utmstack.service.grpc.AuthResponse.getDefaultInstance())) - .setSchemaDescriptor(new AgentServiceMethodDescriptorSupplier("UpdateAgent")) + .setSchemaDescriptor(new AgentServiceMethodDescriptorSupplier("RegisterAgent")) .build(); } } } - return getUpdateAgentMethod; + return getRegisterAgentMethod; } private static volatile io.grpc.MethodDescriptor getRegisterAgentMethod; + com.park.utmstack.service.grpc.AuthResponse> getUpdateAgentMethod; @io.grpc.stub.annotations.RpcMethod( - fullMethodName = SERVICE_NAME + '/' + "RegisterAgent", + fullMethodName = SERVICE_NAME + '/' + "UpdateAgent", requestType = com.park.utmstack.service.grpc.AgentRequest.class, responseType = com.park.utmstack.service.grpc.AuthResponse.class, methodType = io.grpc.MethodDescriptor.MethodType.UNARY) public static io.grpc.MethodDescriptor getRegisterAgentMethod() { - io.grpc.MethodDescriptor getRegisterAgentMethod; - if ((getRegisterAgentMethod = AgentServiceGrpc.getRegisterAgentMethod) == null) { + com.park.utmstack.service.grpc.AuthResponse> getUpdateAgentMethod() { + io.grpc.MethodDescriptor getUpdateAgentMethod; + if ((getUpdateAgentMethod = AgentServiceGrpc.getUpdateAgentMethod) == null) { synchronized (AgentServiceGrpc.class) { - if ((getRegisterAgentMethod = AgentServiceGrpc.getRegisterAgentMethod) == null) { - AgentServiceGrpc.getRegisterAgentMethod = getRegisterAgentMethod = + if ((getUpdateAgentMethod = AgentServiceGrpc.getUpdateAgentMethod) == null) { + AgentServiceGrpc.getUpdateAgentMethod = getUpdateAgentMethod = io.grpc.MethodDescriptor.newBuilder() .setType(io.grpc.MethodDescriptor.MethodType.UNARY) - .setFullMethodName(generateFullMethodName(SERVICE_NAME, "RegisterAgent")) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "UpdateAgent")) .setSampledToLocalTracing(true) .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( com.park.utmstack.service.grpc.AgentRequest.getDefaultInstance())) .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( com.park.utmstack.service.grpc.AuthResponse.getDefaultInstance())) - .setSchemaDescriptor(new AgentServiceMethodDescriptorSupplier("RegisterAgent")) + .setSchemaDescriptor(new AgentServiceMethodDescriptorSupplier("UpdateAgent")) .build(); } } } - return getRegisterAgentMethod; + return getUpdateAgentMethod; } private static volatile io.grpc.MethodDescriptor responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getUpdateAgentMethod(), responseObserver); + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getRegisterAgentMethod(), responseObserver); } /** */ - default void registerAgent(com.park.utmstack.service.grpc.AgentRequest request, + default void updateAgent(com.park.utmstack.service.grpc.AgentRequest request, io.grpc.stub.StreamObserver responseObserver) { - io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getRegisterAgentMethod(), responseObserver); + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getUpdateAgentMethod(), responseObserver); } /** @@ -321,18 +321,18 @@ protected AgentServiceStub build( /** */ - public void updateAgent(com.park.utmstack.service.grpc.AgentRequest request, + public void registerAgent(com.park.utmstack.service.grpc.AgentRequest request, io.grpc.stub.StreamObserver responseObserver) { io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getUpdateAgentMethod(), getCallOptions()), request, responseObserver); + getChannel().newCall(getRegisterAgentMethod(), getCallOptions()), request, responseObserver); } /** */ - public void registerAgent(com.park.utmstack.service.grpc.AgentRequest request, + public void updateAgent(com.park.utmstack.service.grpc.AgentRequest request, io.grpc.stub.StreamObserver responseObserver) { io.grpc.stub.ClientCalls.asyncUnaryCall( - getChannel().newCall(getRegisterAgentMethod(), getCallOptions()), request, responseObserver); + getChannel().newCall(getUpdateAgentMethod(), getCallOptions()), request, responseObserver); } /** @@ -386,16 +386,16 @@ protected AgentServiceBlockingStub build( /** */ - public com.park.utmstack.service.grpc.AuthResponse updateAgent(com.park.utmstack.service.grpc.AgentRequest request) { + public com.park.utmstack.service.grpc.AuthResponse registerAgent(com.park.utmstack.service.grpc.AgentRequest request) { return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getUpdateAgentMethod(), getCallOptions(), request); + getChannel(), getRegisterAgentMethod(), getCallOptions(), request); } /** */ - public com.park.utmstack.service.grpc.AuthResponse registerAgent(com.park.utmstack.service.grpc.AgentRequest request) { + public com.park.utmstack.service.grpc.AuthResponse updateAgent(com.park.utmstack.service.grpc.AgentRequest request) { return io.grpc.stub.ClientCalls.blockingUnaryCall( - getChannel(), getRegisterAgentMethod(), getCallOptions(), request); + getChannel(), getUpdateAgentMethod(), getCallOptions(), request); } /** @@ -438,18 +438,18 @@ protected AgentServiceFutureStub build( /** */ - public com.google.common.util.concurrent.ListenableFuture updateAgent( + public com.google.common.util.concurrent.ListenableFuture registerAgent( com.park.utmstack.service.grpc.AgentRequest request) { return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getUpdateAgentMethod(), getCallOptions()), request); + getChannel().newCall(getRegisterAgentMethod(), getCallOptions()), request); } /** */ - public com.google.common.util.concurrent.ListenableFuture registerAgent( + public com.google.common.util.concurrent.ListenableFuture updateAgent( com.park.utmstack.service.grpc.AgentRequest request) { return io.grpc.stub.ClientCalls.futureUnaryCall( - getChannel().newCall(getRegisterAgentMethod(), getCallOptions()), request); + getChannel().newCall(getUpdateAgentMethod(), getCallOptions()), request); } /** @@ -477,8 +477,8 @@ public com.google.common.util.concurrent.ListenableFuture implements @java.lang.SuppressWarnings("unchecked") public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { switch (methodId) { - case METHODID_UPDATE_AGENT: - serviceImpl.updateAgent((com.park.utmstack.service.grpc.AgentRequest) request, - (io.grpc.stub.StreamObserver) responseObserver); - break; case METHODID_REGISTER_AGENT: serviceImpl.registerAgent((com.park.utmstack.service.grpc.AgentRequest) request, (io.grpc.stub.StreamObserver) responseObserver); break; + case METHODID_UPDATE_AGENT: + serviceImpl.updateAgent((com.park.utmstack.service.grpc.AgentRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; case METHODID_DELETE_AGENT: serviceImpl.deleteAgent((com.park.utmstack.service.grpc.DeleteRequest) request, (io.grpc.stub.StreamObserver) responseObserver); @@ -543,19 +543,19 @@ public io.grpc.stub.StreamObserver invoke( public static final io.grpc.ServerServiceDefinition bindService(AsyncService service) { return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) .addMethod( - getUpdateAgentMethod(), + getRegisterAgentMethod(), io.grpc.stub.ServerCalls.asyncUnaryCall( new MethodHandlers< com.park.utmstack.service.grpc.AgentRequest, com.park.utmstack.service.grpc.AuthResponse>( - service, METHODID_UPDATE_AGENT))) + service, METHODID_REGISTER_AGENT))) .addMethod( - getRegisterAgentMethod(), + getUpdateAgentMethod(), io.grpc.stub.ServerCalls.asyncUnaryCall( new MethodHandlers< com.park.utmstack.service.grpc.AgentRequest, com.park.utmstack.service.grpc.AuthResponse>( - service, METHODID_REGISTER_AGENT))) + service, METHODID_UPDATE_AGENT))) .addMethod( getDeleteAgentMethod(), io.grpc.stub.ServerCalls.asyncUnaryCall( @@ -632,8 +632,8 @@ public static io.grpc.ServiceDescriptor getServiceDescriptor() { if (result == null) { serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) .setSchemaDescriptor(new AgentServiceFileDescriptorSupplier()) - .addMethod(getUpdateAgentMethod()) .addMethod(getRegisterAgentMethod()) + .addMethod(getUpdateAgentMethod()) .addMethod(getDeleteAgentMethod()) .addMethod(getListAgentsMethod()) .addMethod(getAgentStreamMethod()) diff --git a/backend/src/main/java/com/park/utmstack/service/grpc/UtmCommand.java b/backend/src/main/java/com/park/utmstack/service/grpc/UtmCommand.java index 84c4f287c..c6b5938f2 100644 --- a/backend/src/main/java/com/park/utmstack/service/grpc/UtmCommand.java +++ b/backend/src/main/java/com/park/utmstack/service/grpc/UtmCommand.java @@ -327,6 +327,10 @@ public java.lang.String getReason() { @SuppressWarnings("serial") private volatile java.lang.Object shell_ = ""; /** + *
+   * Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default
+   * 
+ * * string shell = 8; * @return The shell. */ @@ -344,6 +348,10 @@ public java.lang.String getShell() { } } /** + *
+   * Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default
+   * 
+ * * string shell = 8; * @return The bytes for shell. */ @@ -1330,6 +1338,10 @@ public Builder setReasonBytes( private java.lang.Object shell_ = ""; /** + *
+     * Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default
+     * 
+ * * string shell = 8; * @return The shell. */ @@ -1346,6 +1358,10 @@ public java.lang.String getShell() { } } /** + *
+     * Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default
+     * 
+ * * string shell = 8; * @return The bytes for shell. */ @@ -1363,6 +1379,10 @@ public java.lang.String getShell() { } } /** + *
+     * Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default
+     * 
+ * * string shell = 8; * @param value The shell to set. * @return This builder for chaining. @@ -1376,6 +1396,10 @@ public Builder setShell( return this; } /** + *
+     * Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default
+     * 
+ * * string shell = 8; * @return This builder for chaining. */ @@ -1386,6 +1410,10 @@ public Builder clearShell() { return this; } /** + *
+     * Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default
+     * 
+ * * string shell = 8; * @param value The bytes for shell to set. * @return This builder for chaining. diff --git a/backend/src/main/java/com/park/utmstack/service/grpc/UtmCommandOrBuilder.java b/backend/src/main/java/com/park/utmstack/service/grpc/UtmCommandOrBuilder.java index 215ccc7ad..2f0b558a0 100644 --- a/backend/src/main/java/com/park/utmstack/service/grpc/UtmCommandOrBuilder.java +++ b/backend/src/main/java/com/park/utmstack/service/grpc/UtmCommandOrBuilder.java @@ -94,11 +94,19 @@ public interface UtmCommandOrBuilder extends getReasonBytes(); /** + *
+   * Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default
+   * 
+ * * string shell = 8; * @return The shell. */ java.lang.String getShell(); /** + *
+   * Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default
+   * 
+ * * string shell = 8; * @return The bytes for shell. */ diff --git a/backend/src/main/proto/agent.proto b/backend/src/main/proto/agent.proto index d5ee2df98..258fe1fda 100644 --- a/backend/src/main/proto/agent.proto +++ b/backend/src/main/proto/agent.proto @@ -11,102 +11,103 @@ import "google/protobuf/timestamp.proto"; import "common.proto"; service AgentService { - rpc UpdateAgent(AgentRequest) returns (AuthResponse) {} - rpc RegisterAgent(AgentRequest) returns (AuthResponse) {} - rpc DeleteAgent(DeleteRequest) returns (AuthResponse) {} - rpc ListAgents (ListRequest) returns (ListAgentsResponse) {} - rpc AgentStream(stream BidirectionalStream) returns (stream BidirectionalStream) {} - rpc ListAgentCommands (ListRequest) returns (ListAgentsCommandsResponse) {} + rpc RegisterAgent(AgentRequest) returns (AuthResponse) {} + rpc UpdateAgent(AgentRequest) returns (AuthResponse) {} + rpc DeleteAgent(DeleteRequest) returns (AuthResponse) {} + rpc ListAgents (ListRequest) returns (ListAgentsResponse) {} + rpc AgentStream(stream BidirectionalStream) returns (stream BidirectionalStream) {} + rpc ListAgentCommands (ListRequest) returns (ListAgentsCommandsResponse) {} } service PanelService { - rpc ProcessCommand (stream UtmCommand) returns (stream CommandResult){} + rpc ProcessCommand (stream UtmCommand) returns (stream CommandResult){} } enum AgentCommandStatus { - NOT_EXECUTED = 0; - QUEUE = 1; - PENDING = 2; - EXECUTED = 3; - ERROR = 4; + NOT_EXECUTED = 0; + QUEUE = 1; + PENDING = 2; + EXECUTED = 3; + ERROR = 4; } message AgentRequest { - string ip = 1; - string hostname = 2; - string os = 3; - string platform = 4; - string version = 5; - string register_by = 6; - string mac = 7 ; - string os_major_version = 8; - string os_minor_version = 9; - string aliases = 10; - string addresses = 11; + string ip = 1; + string hostname = 2; + string os = 3; + string platform = 4; + string version = 5; + string register_by = 6; + string mac = 7 ; + string os_major_version = 8; + string os_minor_version = 9; + string aliases = 10; + string addresses = 11; } message ListAgentsResponse { - repeated Agent rows = 1; - int32 total = 2; + repeated Agent rows = 1; + int32 total = 2; } message Agent { - string ip = 1; - string hostname = 2; - string os = 3; - Status status = 4; - string platform = 5; - string version = 6; - string agent_key = 7; - uint32 id = 8; - string last_seen = 9; - string mac = 10 ; - string os_major_version = 11; - string os_minor_version = 12; - string aliases = 13; - string addresses = 14; + string ip = 1; + string hostname = 2; + string os = 3; + Status status = 4; + string platform = 5; + string version = 6; + string agent_key = 7; + uint32 id = 8; + string last_seen = 9; + string mac = 10 ; + string os_major_version = 11; + string os_minor_version = 12; + string aliases = 13; + string addresses = 14; } message BidirectionalStream { - oneof stream_message { - UtmCommand command = 1; - CommandResult result = 2; - } + oneof stream_message { + UtmCommand command = 1; + CommandResult result = 2; + } } message UtmCommand { - string agent_id = 1; - string command = 2; - string executed_by = 3; - string cmd_id = 4; - string origin_type = 5; - string origin_id = 6; - string reason = 7; - string shell = 8; + string agent_id = 1; + string command = 2; + string executed_by = 3; + string cmd_id = 4; + string origin_type = 5; + string origin_id = 6; + string reason = 7; + string shell = 8; // Shell to execute command: "cmd", "powershell" (Windows), "sh", "bash" (Linux/macOS). Empty = default } message CommandResult { - string agent_id = 1; - string result = 2; - google.protobuf.Timestamp executed_at = 3; - string cmd_id = 4; + string agent_id = 1; + string result = 2; + google.protobuf.Timestamp executed_at = 3; + string cmd_id = 4; } message ListAgentsCommandsResponse { - repeated AgentCommand rows = 1; - int32 total = 2; + repeated AgentCommand rows = 1; + int32 total = 2; } message AgentCommand { - google.protobuf.Timestamp created_at = 1; - google.protobuf.Timestamp updated_at = 2; - uint32 agent_id = 3; - string command = 4; - AgentCommandStatus command_status = 5; - string result = 6; - string executed_by = 7; - string cmd_id = 8; - string reason = 9; - string origin_type = 10; - string origin_id = 11; + google.protobuf.Timestamp created_at = 1; + google.protobuf.Timestamp updated_at = 2; + uint32 agent_id = 3; + string command = 4; + AgentCommandStatus command_status = 5; + string result = 6; + string executed_by = 7; + string cmd_id = 8; + string reason = 9; + string origin_type = 10; + string origin_id = 11; } + From ce1b9321a432a7f8cbf9ad31293807147ee22dc0 Mon Sep 17 00:00:00 2001 From: AlexSanchez-bit Date: Mon, 30 Mar 2026 18:27:14 -0400 Subject: [PATCH 060/135] feat[frontend](agent-console): added shell switch for windows agents (powershell or cmd) --- .../utm-agent-console.component.html | 21 +++++++++++++------ .../utm-agent-console.component.scss | 16 ++++++++++++++ .../utm-agent-console.component.ts | 1 + .../types/incident/incident-command.type.ts | 1 + frontend/tslint.json | 1 + 5 files changed, 34 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/shared/components/utm/util/utm-agent-console/utm-agent-console.component.html b/frontend/src/app/shared/components/utm/util/utm-agent-console/utm-agent-console.component.html index 1929e00fd..f438d965e 100644 --- a/frontend/src/app/shared/components/utm/util/utm-agent-console/utm-agent-console.component.html +++ b/frontend/src/app/shared/components/utm/util/utm-agent-console/utm-agent-console.component.html @@ -6,12 +6,21 @@
- - - {{ agent.hostname }} ({{ agent.os }}) - +
+ + + {{ agent.hostname }} ({{ agent.os }}) + + + +