From 3ecb0127d5c395c44fea173a44d6b51ef4d8023b Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Fri, 28 Mar 2025 11:40:14 -0500 Subject: [PATCH 01/42] fix: move exception handling to prevent workflow interruptions --- .../service/UtmAlertTagRuleService.java | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/service/UtmAlertTagRuleService.java b/backend/src/main/java/com/park/utmstack/service/UtmAlertTagRuleService.java index 761a26124..16e541ea6 100644 --- a/backend/src/main/java/com/park/utmstack/service/UtmAlertTagRuleService.java +++ b/backend/src/main/java/com/park/utmstack/service/UtmAlertTagRuleService.java @@ -104,7 +104,7 @@ public Page findByFilter(AlertTagRuleFilterVM filters, Pageable TypedParameterValue isDeleted = new TypedParameterValue(new BooleanType(), filters.getRuleDeleted()); return alertTagRuleRepository.findByFilter(id, name, conditionField, - conditionValue, tagIds, isActive, isDeleted, pageable); + conditionValue, tagIds, isActive, isDeleted, pageable); } catch (Exception e) { throw new Exception(ctx + ": " + e.getMessage()); } @@ -145,7 +145,7 @@ public void automaticReview() { final String ctx = CLASSNAME + ".automaticReview"; try { // If no new alerts have been received, stop execution - if (alertUtil.countAlertsByStatus(AlertStatus.AUTOMATIC_REVIEW.getCode()) == 0) + if (alertUtil.countAlertsByStatus(AlertStatus.OPEN.getCode()) == 0) return; // Getting all registered rules @@ -154,12 +154,12 @@ public void automaticReview() { // Getting rules that are actives and are not deleted if (!CollectionUtils.isEmpty(tagRules)) tagRules = tagRules.stream() - .filter(rule -> rule.getRuleActive() && !rule.getRuleDeleted()) - .collect(Collectors.toList()); + .filter(rule -> rule.getRuleActive() && !rule.getRuleDeleted()) + .collect(Collectors.toList()); // Getting rule evaluation start time Instant rulesEvaluationStart = LocalDateTime.now().toInstant(ZoneOffset.UTC) - .truncatedTo(ChronoUnit.SECONDS); + .truncatedTo(ChronoUnit.SECONDS); // If there is any rule if (!CollectionUtils.isEmpty(tagRules)) @@ -174,17 +174,17 @@ public void automaticReview() { } } - private void releaseToOpen(Instant rulesEvaluationStart) throws Exception { + private void releaseToOpen(Instant rulesEvaluationStart) { final String ctx = CLASSNAME + ".releaseToOpen"; try { String ruleScript = "ctx._source.status=%1$s;" + - "ctx._source.statusLabel='%2$s';" + - "ctx._source.statusObservation='%3$s';"; + "ctx._source.statusLabel='%2$s';" + + "ctx._source.statusObservation='%3$s';"; String statusObservation = "This alert has been evaluated by the tag rules engine"; String script = String.format(ruleScript, AlertStatus.OPEN.getCode(), AlertStatus.OPEN.getName(), - statusObservation); + statusObservation); List filters = new ArrayList<>(); filters.add(new FilterType(Constants.alertStatus, OperatorType.IS, AlertStatus.AUTOMATIC_REVIEW.getCode())); @@ -196,16 +196,18 @@ private void releaseToOpen(Instant rulesEvaluationStart) throws Exception { elasticsearchService.updateByQuery(query, indexPattern, script); alertPointcut.automaticAlertStatusChangePointcut(query, AlertStatus.OPEN.getCode(), - statusObservation, indexPattern); + statusObservation, indexPattern); } catch (Exception e) { - throw new Exception(ctx + ": " + e.getMessage()); + String msg = ctx + ": " + e.getMessage(); + eventService.createEvent(msg, ApplicationEventType.ERROR); + log.error(msg, e.getMessage(), e); } } - private void applyTagRule(List rules, Instant rulesEvaluationStart) throws Exception { + private void applyTagRule(List rules, Instant rulesEvaluationStart) { final String ctx = CLASSNAME + ".applyTagRule"; - try { - for (UtmAlertTagRule rule : rules) { + for (UtmAlertTagRule rule : rules) { + try { List filters = rule.getConditions(); filters.add(new FilterType(Constants.alertStatus, OperatorType.IS, AlertStatus.AUTOMATIC_REVIEW.getCode())); filters.add(new FilterType(Constants.timestamp, OperatorType.IS_LESS_THAN_OR_EQUALS, rulesEvaluationStart.toString())); @@ -213,20 +215,20 @@ private void applyTagRule(List rules, Instant rulesEvaluationSt Query query = SearchUtil.toQuery(filters); String script = "if (!ctx._source.containsKey('tags') || ctx._source.tags == null || ctx._source.tags.empty)\n" + - "\tctx._source.tags = new ArrayList();\n" + - "ctx._source.tags.addAll([%1$s]);\n" + - "ctx._source.tags = ctx._source.tags.stream().distinct().collect(Collectors.toList());\n" + - "\n" + - "if (!ctx._source.containsKey('TagRulesApplied') || ctx._source.TagRulesApplied == null || ctx._source.TagRulesApplied.empty)\n" + - "\tctx._source.TagRulesApplied = new ArrayList();\n" + - "ctx._source.TagRulesApplied.add(%2$s);\n" + - "ctx._source.TagRulesApplied = ctx._source.TagRulesApplied.stream().distinct().collect(Collectors.toList());" + - "\n" + - "if (ctx._source.tags.contains('False positive')) {\n" + - "\tctx._source.status=%3$s;\n" + - "\tctx._source.statusLabel='%4$s';\n" + - "\tctx._source.statusObservation='Status changed to completed because alert was tagged as False positive';\n" + - "\n}"; + "\tctx._source.tags = new ArrayList();\n" + + "ctx._source.tags.addAll([%1$s]);\n" + + "ctx._source.tags = ctx._source.tags.stream().distinct().collect(Collectors.toList());\n" + + "\n" + + "if (!ctx._source.containsKey('TagRulesApplied') || ctx._source.TagRulesApplied == null || ctx._source.TagRulesApplied.empty)\n" + + "\tctx._source.TagRulesApplied = new ArrayList();\n" + + "ctx._source.TagRulesApplied.add(%2$s);\n" + + "ctx._source.TagRulesApplied = ctx._source.TagRulesApplied.stream().distinct().collect(Collectors.toList());" + + "\n" + + "if (ctx._source.tags.contains('False positive')) {\n" + + "\tctx._source.status=%3$s;\n" + + "\tctx._source.statusLabel='%4$s';\n" + + "\tctx._source.statusObservation='Status changed to completed because alert was tagged as False positive';\n" + + "\n}"; List tags = alertTagService.findAllByIdIn(rule.getAppliedTagsAsListOfLong()); String indexPattern = Constants.SYS_INDEX_PATTERN.get(SystemIndexPattern.ALERTS); @@ -234,13 +236,15 @@ private void applyTagRule(List rules, Instant rulesEvaluationSt String tagsForInsert = tags.stream().map(tag -> "'" + tag.getTagName() + "'").collect(Collectors.joining(",")); elasticsearchService.updateByQuery(query, indexPattern, String.format(script, tagsForInsert, rule.getId(), - AlertStatus.COMPLETED.getCode(), AlertStatus.COMPLETED.getName())); + AlertStatus.COMPLETED.getCode(), AlertStatus.COMPLETED.getName())); String tagsForLogs = tags.stream().map(UtmAlertTag::getTagName).collect(Collectors.joining(",")); alertPointcut.automaticAlertTagsChangePointcut(query, tagsForLogs, rule.getRuleName(), indexPattern); + } catch (Exception e) { + String msg = String.format("%s: Error applying rule '%s' - %s", ctx, rule.getRuleName(), e.getMessage()); + eventService.createEvent(msg, ApplicationEventType.ERROR); + log.error(msg, e.getMessage(), e); } - } catch (Exception e) { - throw new Exception(ctx + ": " + e.getMessage()); } } } From 6740b67bf6985f633fdd546bf0fbe50b36d7b3ae Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Fri, 28 Mar 2025 11:48:36 -0500 Subject: [PATCH 02/42] chore: set version --- version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.yml b/version.yml index 63b9aa799..50c4306b0 100644 --- a/version.yml +++ b/version.yml @@ -1 +1 @@ -version: 10.7.1 +version: 10.7.3 From a47755af665e03cb0a084e945c779a22a09825fb Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Fri, 28 Mar 2025 11:49:39 -0500 Subject: [PATCH 03/42] chore: set version --- version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.yml b/version.yml index 50c4306b0..21c159ed9 100644 --- a/version.yml +++ b/version.yml @@ -1 +1 @@ -version: 10.7.3 +version: 10.7.3 \ No newline at end of file From aa09097e1f9bfe2f149aab2b8b47b8a25c7fbda1 Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Fri, 28 Mar 2025 11:49:47 -0500 Subject: [PATCH 04/42] chore: update changelog --- CHANGELOG.md | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 544de8d50..22d29718e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,4 @@ -# UTMStack 10.7.1 Release Notes +# UTMStack 10.7.2 Release Notes ### Bug Fixes --- Fixed responsive text alignment for action buttons in Log Explorer to enhance visual consistency. --- Fixed issues with loading data from saved queries in Log Explorer, ensuring the correct filter values are applied. --- Fixed issue where tabs remained open when navigating outside the Log Explorer scope to improve user experience. --- Fixed time filter issue where the date range was not applied correctly. --- Fixed incorrect query behavior when filtering incidents by ID. - -## New Features and Improvements --- Added organization name in app settings to distinguish alert and notification emails for better clarity. --- Enhanced the email notification system by including the organization name to improve recipient identification. --- Introduced new compliance reports aligned with the PCI DSS standard to expand auditing capabilities. --- Added new menu item **New Dashboard**. --- Added new menu item **New Visualization**. \ No newline at end of file +-- Improved exception handling in `automaticReview` to prevent the process from stopping due to errors, ensuring the system continues evaluating alerts even if a specific rule fails. \ No newline at end of file From 45a095d0ad180fbe54942e73badc3c666e79c99b Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Mon, 31 Mar 2025 10:05:59 -0500 Subject: [PATCH 05/42] feat: filter compliance reports based on active integration --- .../config/UtmComplianceReportConfigService.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceReportConfigService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceReportConfigService.java index 00267b73c..0eba1978a 100644 --- a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceReportConfigService.java +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceReportConfigService.java @@ -9,11 +9,13 @@ import com.park.utmstack.domain.compliance.UtmComplianceStandard; import com.park.utmstack.domain.compliance.UtmComplianceStandardSection; import com.park.utmstack.domain.compliance.enums.ComplianceStatus; +import com.park.utmstack.domain.index_pattern.UtmIndexPattern; import com.park.utmstack.repository.compliance.UtmComplianceReportConfigRepository; import com.park.utmstack.service.chart_builder.UtmDashboardService; import com.park.utmstack.service.chart_builder.UtmDashboardVisualizationService; import com.park.utmstack.service.elasticsearch.ElasticsearchService; import com.park.utmstack.service.elasticsearch.SearchUtil; +import com.park.utmstack.service.index_pattern.UtmIndexPatternService; import com.park.utmstack.util.UtilPagination; import com.park.utmstack.util.chart_builder.elasticsearch_dsl.requests.RequestDsl; import com.park.utmstack.util.exceptions.UtmElasticsearchException; @@ -21,6 +23,7 @@ import org.springframework.dao.DataIntegrityViolationException; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -32,6 +35,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.Collectors; @Service public class UtmComplianceReportConfigService { @@ -52,7 +56,7 @@ public UtmComplianceReportConfigService(UtmComplianceReportConfigRepository comp UtmComplianceStandardService standardService, UtmComplianceStandardSectionService standardSectionService, UtmDashboardVisualizationService dashboardVisualizationService, ElasticsearchService elasticsearchService, - EntityManager em) { + EntityManager em, UtmIndexPatternService indexPatternService) { this.complianceReportConfigRepository = complianceReportConfigRepository; this.dashboardService = dashboardService; this.standardService = standardService; @@ -116,7 +120,12 @@ public Page getReportsByFilters(Long standardId, Stri } } - return page; + List activeCompliance = page.getContent() + .stream() + .filter(cp -> !cp.getDashboard().isEmpty() && cp.getDashboard().stream().allMatch(v -> v.getVisualization().getPattern().getActive())) + .collect(Collectors.toList()); + + return new PageImpl<>(activeCompliance, pageable, activeCompliance.size()); } From 1a4f237f0b4589747c8dde5d17cf8666f66a989e Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Mon, 31 Mar 2025 10:06:23 -0500 Subject: [PATCH 06/42] chore: update changeLog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22d29718e..0c4cc593f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ # UTMStack 10.7.2 Release Notes +-- Implemented backend support for filtering compliance reports based on active integrations, optimizing query performance and data retrieval. ### Bug Fixes -- Improved exception handling in `automaticReview` to prevent the process from stopping due to errors, ensuring the system continues evaluating alerts even if a specific rule fails. \ No newline at end of file From 6689b604b6845d60d557bfeed12671e66f391c71 Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Mon, 31 Mar 2025 10:36:46 -0500 Subject: [PATCH 07/42] feat: filter compliance reports based on active integration --- .../compliance-reports-view.component.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 90819fef6..42c161763 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 @@ -79,10 +79,7 @@ export class ComplianceReportsViewComponent implements OnInit, OnChanges, OnDest })), tap(res => this.totalItems = Number(res.headers.get('X-Total-Count'))), map((res) => { - return res.body.filter(r => r.dashboard.length > 0 && r.dashboard.every(v => v.visualization.pattern.active)); - }), - map((res) => { - return res.map((r, index) => { + return res.body.map((r, index) => { return { ...r, selected: index === this.selected From 6b08e6a15542336f2f1bafac52e972499857f19d Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Mon, 31 Mar 2025 10:42:03 -0500 Subject: [PATCH 08/42] fix: improve field value validation for "contains one of" and "does not contain one of" operators --- .../elastic-filter-add/elastic-filter-add.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/elastic-filter-add/elastic-filter-add.component.ts b/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/elastic-filter-add/elastic-filter-add.component.ts index ccd3d90e9..a9bc17c2c 100644 --- a/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/elastic-filter-add/elastic-filter-add.component.ts +++ b/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/elastic-filter-add/elastic-filter-add.component.ts @@ -250,7 +250,8 @@ export class ElasticFilterAddComponent implements OnInit { */ operatorFieldSelectable(): boolean { return this.operator === this.operatorEnum.IS || this.operator === this.operatorEnum.IS_NOT || - this.operator === this.operatorEnum.IS_ONE_OF || this.operator === this.operatorEnum.IS_NOT_ONE_OF; + this.operator === this.operatorEnum.IS_ONE_OF || this.operator === this.operatorEnum.IS_NOT_ONE_OF || + this.operator === this.operatorEnum.CONTAIN_ONE_OF || this.operator === this.operatorEnum.DOES_NOT_CONTAIN_ONE_OF; } /** From 418f4cd155cea75f6a06a5678400795e3668536f Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Wed, 2 Apr 2025 09:42:10 -0500 Subject: [PATCH 09/42] feat: improve operator selection based on field type --- CHANGELOG.md | 3 +- .../alert-rule-create.component.html | 2 +- .../alert-rule-create.component.ts | 16 ++++++- .../elastic-filter-add.component.ts | 28 +++++++++--- .../shared/util/find-inverse-operator.util.ts | 3 -- .../shared/util/operator.service.ts | 45 +++++++++++++++++++ .../shared/enums/elastic-data-types.enum.ts | 3 +- 7 files changed, 87 insertions(+), 13 deletions(-) delete mode 100644 frontend/src/app/shared/components/utm/filters/utm-elastic-filter/shared/util/find-inverse-operator.util.ts create mode 100644 frontend/src/app/shared/components/utm/filters/utm-elastic-filter/shared/util/operator.service.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c4cc593f..351842a2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,5 @@ -- Implemented backend support for filtering compliance reports based on active integrations, optimizing query performance and data retrieval. ### Bug Fixes --- Improved exception handling in `automaticReview` to prevent the process from stopping due to errors, ensuring the system continues evaluating alerts even if a specific rule fails. \ No newline at end of file +-- Improved exception handling in `automaticReview` to prevent the process from stopping due to errors, ensuring the system continues evaluating alerts even if a specific rule fails. +-- Improved operator selection for more accurate and consistent filtering. \ No newline at end of file diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html index b6071db27..77bcdddca 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html @@ -86,7 +86,7 @@ {{getFieldName(filter.field)}}:  !this.excludeFields.includes(value.field)); this.operators = FILTER_OPERATORS.filter(value => !this.excludeOperators.includes(value.operator)); } @@ -241,4 +247,12 @@ export class AlertRuleCreateComponent implements OnInit { isFalsePositive() { return this.selected.findIndex(value => value.tagName.includes('False positive')) !== -1; } + + getOperators(filter: ElasticFilterType) { + const field = this.fields.find(f => f.field === filter.field); + if (field) { + return this.operatorService.getOperators({name: field.field, type: field.type}, this.operators); + } + return this.operators; + } } diff --git a/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/elastic-filter-add/elastic-filter-add.component.ts b/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/elastic-filter-add/elastic-filter-add.component.ts index a9bc17c2c..0c7a3a30c 100644 --- a/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/elastic-filter-add/elastic-filter-add.component.ts +++ b/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/elastic-filter-add/elastic-filter-add.component.ts @@ -13,6 +13,7 @@ import {ElasticFilterType} from '../../../../../types/filter/elastic-filter.type import {OperatorsType} from '../../../../../types/filter/operators.type'; import {TimeFilterType} from '../../../../../types/time-filter.type'; import {resolveIcon} from '../../../../../util/elastic-fields.util'; +import {OperatorService} from '../shared/util/operator.service'; @Component({ selector: 'app-elastic-filter-add', @@ -63,7 +64,8 @@ export class ElasticFilterAddComponent implements OnInit { constructor(private fb: FormBuilder, private fieldDataBehavior: FieldDataService, - private elasticSearchIndexService: ElasticSearchIndexService) { + private elasticSearchIndexService: ElasticSearchIndexService, + private operatorService: OperatorService) { } ngOnInit() { @@ -289,14 +291,15 @@ export class ElasticFilterAddComponent implements OnInit { } } - /** + /*/!** * Return operators based on field type - */ + *!/ getOperators() { const index = this.getIndexField(); if (index !== -1) { const fieldType = this.fields[index].type; - if (fieldType === ElasticDataTypesEnum.TEXT || fieldType === ElasticDataTypesEnum.STRING) { + if (fieldType === ElasticDataTypesEnum.TEXT || fieldType === ElasticDataTypesEnum.STRING || + fieldType === ElasticDataTypesEnum.KEYWORD) { if (!this.field.name.includes('.keyword')) { this.operators = FILTER_OPERATORS.filter(value => value.operator !== ElasticOperatorsEnum.IS_BETWEEN && @@ -306,18 +309,31 @@ export class ElasticFilterAddComponent implements OnInit { value.operator !== ElasticOperatorsEnum.IS_BETWEEN && value.operator !== ElasticOperatorsEnum.CONTAIN && value.operator !== ElasticOperatorsEnum.DOES_NOT_CONTAIN && - value.operator !== ElasticOperatorsEnum.IS_NOT_BETWEEN); + value.operator !== ElasticOperatorsEnum.IS_NOT_BETWEEN && + value.operator !== ElasticOperatorsEnum.ENDS_WITH && + value.operator !== ElasticOperatorsEnum.NOT_ENDS_WITH && + value.operator !== ElasticOperatorsEnum.START_WITH && + value.operator !== ElasticOperatorsEnum.NOT_START_WITH); } } else if (fieldType === ElasticDataTypesEnum.LONG || fieldType === ElasticDataTypesEnum.NUMBER || fieldType === ElasticDataTypesEnum.DATE) { this.operators = FILTER_OPERATORS.filter(value => value.operator !== ElasticOperatorsEnum.CONTAIN && - value.operator !== ElasticOperatorsEnum.DOES_NOT_CONTAIN); + value.operator !== ElasticOperatorsEnum.DOES_NOT_CONTAIN && + value.operator !== ElasticOperatorsEnum.START_WITH && + value.operator !== ElasticOperatorsEnum.NOT_START_WITH); } else { this.operators = FILTER_OPERATORS; } } + }*/ + + getOperators() { + const index = this.getIndexField(); + if (index !== -1) { + this.operators = this.operatorService.getOperators(this.fields[index], this.operators); + } } /** diff --git a/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/shared/util/find-inverse-operator.util.ts b/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/shared/util/find-inverse-operator.util.ts deleted file mode 100644 index 82c9f5737..000000000 --- a/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/shared/util/find-inverse-operator.util.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function findInverseOperator() { - -} diff --git a/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/shared/util/operator.service.ts b/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/shared/util/operator.service.ts new file mode 100644 index 000000000..b6ec7e576 --- /dev/null +++ b/frontend/src/app/shared/components/utm/filters/utm-elastic-filter/shared/util/operator.service.ts @@ -0,0 +1,45 @@ +import {Injectable} from '@angular/core'; +import {FILTER_OPERATORS} from '../../../../../../constants/filter-operators.const'; +import {ElasticDataTypesEnum} from '../../../../../../enums/elastic-data-types.enum'; +import {ElasticOperatorsEnum} from '../../../../../../enums/elastic-operators.enum'; +import {ElasticSearchFieldInfoType} from '../../../../../../types/elasticsearch/elastic-search-field-info.type'; +import {OperatorsType} from '../../../../../../types/filter/operators.type'; + +@Injectable({ + providedIn: 'root' +}) +export class OperatorService { + + getOperators(field: ElasticSearchFieldInfoType, operators: OperatorsType[]) { + if (field.type === ElasticDataTypesEnum.TEXT || field.type === ElasticDataTypesEnum.STRING || + field.type === ElasticDataTypesEnum.KEYWORD) { + if (!field.name.includes('.keyword')) { + operators = FILTER_OPERATORS.filter(value => + value.operator !== ElasticOperatorsEnum.IS_BETWEEN && + value.operator !== ElasticOperatorsEnum.IS_NOT_BETWEEN); + } else { + operators = FILTER_OPERATORS.filter(value => + value.operator !== ElasticOperatorsEnum.IS_BETWEEN && + value.operator !== ElasticOperatorsEnum.CONTAIN && + value.operator !== ElasticOperatorsEnum.DOES_NOT_CONTAIN && + value.operator !== ElasticOperatorsEnum.IS_NOT_BETWEEN && + value.operator !== ElasticOperatorsEnum.ENDS_WITH && + value.operator !== ElasticOperatorsEnum.NOT_ENDS_WITH && + value.operator !== ElasticOperatorsEnum.START_WITH && + value.operator !== ElasticOperatorsEnum.NOT_START_WITH); + } + + } else if (field.type === ElasticDataTypesEnum.LONG || + field.type === ElasticDataTypesEnum.NUMBER || field.type === ElasticDataTypesEnum.DATE) { + operators = FILTER_OPERATORS.filter(value => + value.operator !== ElasticOperatorsEnum.CONTAIN && + value.operator !== ElasticOperatorsEnum.DOES_NOT_CONTAIN && + value.operator !== ElasticOperatorsEnum.START_WITH && + value.operator !== ElasticOperatorsEnum.NOT_START_WITH); + } else { + operators = FILTER_OPERATORS; + } + + return operators; + } +} diff --git a/frontend/src/app/shared/enums/elastic-data-types.enum.ts b/frontend/src/app/shared/enums/elastic-data-types.enum.ts index 2e627b095..22422368b 100644 --- a/frontend/src/app/shared/enums/elastic-data-types.enum.ts +++ b/frontend/src/app/shared/enums/elastic-data-types.enum.ts @@ -11,5 +11,6 @@ export enum ElasticDataTypesEnum { IP = 'ip', GEO = 'GEO', OBJECT = 'object', - BOOLEAN = 'boolean' + BOOLEAN = 'boolean', + KEYWORD = 'keyword' } From fe8aaa221a3f4129c8b3017078f74ebd7641209f Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Wed, 2 Apr 2025 12:20:42 -0500 Subject: [PATCH 10/42] feat: improve operator selection based on field type --- .../log-analyzer-view/log-analyzer-view.component.html | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/frontend/src/app/log-analyzer/explorer/log-analyzer-view/log-analyzer-view.component.html b/frontend/src/app/log-analyzer/explorer/log-analyzer-view/log-analyzer-view.component.html index 3a08c50a0..aecf6d624 100644 --- a/frontend/src/app/log-analyzer/explorer/log-analyzer-view/log-analyzer-view.component.html +++ b/frontend/src/app/log-analyzer/explorer/log-analyzer-view/log-analyzer-view.component.html @@ -17,24 +17,19 @@ -
-
+
-
- -
-
From 3b5ff923d8dbd2db07c8dc97bceb9c9ae6158cbb Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Fri, 4 Apr 2025 18:48:33 -0500 Subject: [PATCH 11/42] feat: allow edit and delete for non-owners only in dev mode --- .../utm-cp-reports.component.html | 6 +++--- .../utm-cp-reports/utm-cp-reports.component.ts | 6 ++++++ .../utm-cp-standard-section.component.html | 4 ++-- .../utm-cp-standard-section.component.ts | 6 ++++++ .../utm-cp-standard.component.html | 4 ++-- .../utm-cp-standard.component.ts | 6 ++++++ .../compliance-print-view.component.ts | 7 +++++++ .../shared/type/compliance-standard.type.ts | 1 + .../dashboard-list.component.html | 4 ++-- .../dashboard-list/dashboard-list.component.ts | 6 ++++++ .../viewer/table-view/table-view.component.ts | 4 +++- .../visualization-list.component.html | 4 ++-- .../visualization-list.component.ts | 6 ++++++ .../shared/chart/types/visualization.type.ts | 1 + .../shared/services/util/enviroment.service.ts | 18 ++++++++++++++++++ 15 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 frontend/src/app/shared/services/util/enviroment.service.ts diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-reports/utm-cp-reports.component.html b/frontend/src/app/compliance/compliance-management/utm-cp-reports/utm-cp-reports.component.html index fdba1b7cd..07932f3d0 100644 --- a/frontend/src/app/compliance/compliance-management/utm-cp-reports/utm-cp-reports.component.html +++ b/frontend/src/app/compliance/compliance-management/utm-cp-reports/utm-cp-reports.component.html @@ -23,15 +23,15 @@
- - - - - dashboards class="icon-copy3 cursor-pointer mr-2" ngbTooltip="Copy dashboard URL" tooltipClass="utm-tooltip-top"> - - diff --git a/frontend/src/app/graphic-builder/dashboard-builder/dashboard-list/dashboard-list.component.ts b/frontend/src/app/graphic-builder/dashboard-builder/dashboard-list/dashboard-list.component.ts index f8c78e168..6395d7465 100644 --- a/frontend/src/app/graphic-builder/dashboard-builder/dashboard-list/dashboard-list.component.ts +++ b/frontend/src/app/graphic-builder/dashboard-builder/dashboard-list/dashboard-list.component.ts @@ -17,6 +17,7 @@ import {DashboardImportComponent} from '../dashboard-import/dashboard-import.com import {UtmDashboardVisualizationService} from '../shared/services/utm-dashboard-visualization.service'; import {UtmDashboardService} from '../shared/services/utm-dashboard.service'; import {buildDashboardUrl} from '../shared/util/get-menu-url'; +import {EnvironmentService} from "../../../shared/services/util/enviroment.service"; @Component({ selector: 'app-dashboard-list', @@ -50,6 +51,7 @@ export class DashboardListComponent implements OnInit { private dashboardService: UtmDashboardService, private utmToastService: UtmToastService, private spinner: NgxSpinnerService, + private environment: EnvironmentService, private dashboardVisualizationService: UtmDashboardVisualizationService, private router: Router) { } @@ -63,6 +65,10 @@ export class DashboardListComponent implements OnInit { this.getDashboardList(); } + isDev(){ + return this.environment.isDev(); + } + onSortBy($event) { } diff --git a/frontend/src/app/graphic-builder/shared/components/viewer/table-view/table-view.component.ts b/frontend/src/app/graphic-builder/shared/components/viewer/table-view/table-view.component.ts index 6816c35cb..b36bf3577 100644 --- a/frontend/src/app/graphic-builder/shared/components/viewer/table-view/table-view.component.ts +++ b/frontend/src/app/graphic-builder/shared/components/viewer/table-view/table-view.component.ts @@ -130,7 +130,9 @@ export class TableViewComponent implements OnInit, AfterViewInit, OnChanges { runVisualization() { this.loadingOption = true; - this.runVisualizationService.run(this.visualization).subscribe(data => { + const request = this.visualization.page ? this.visualization.page : {}; + console.log(request); + this.runVisualizationService.run(this.visualization, request).subscribe(data => { this.empty = data.length === 0 || data[0].rows.length === 0; this.data = data.length > 0 ? data[0] : []; if (!this.empty) { diff --git a/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.html b/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.html index 1db7ea203..53977b3a4 100644 --- a/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.html +++ b/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.html @@ -126,11 +126,11 @@
Visualizations
- - diff --git a/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.ts b/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.ts index b1d7cd221..166224e3c 100644 --- a/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.ts +++ b/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.ts @@ -18,6 +18,7 @@ import {VisualizationService} from '../shared/services/visualization.service'; import {VisualizationCreateComponent} from '../visualization-create/visualization-create.component'; import {VisualizationDeleteComponent} from '../visualization-delete/visualization-delete.component'; import {VisualizationImportComponent} from '../visualization-import/visualization-import.component'; +import {EnvironmentService} from "../../../shared/services/util/enviroment.service"; @Component({ selector: 'app-visualization-list', @@ -52,6 +53,7 @@ export class VisualizationListComponent implements OnInit { private visualizationService: VisualizationService, private spinner: NgxSpinnerService, private router: Router, + private environment: EnvironmentService, private activatedRoute: ActivatedRoute) { } @@ -70,6 +72,10 @@ export class VisualizationListComponent implements OnInit { }); } + isDev(){ + return this.environment.isDev(); + } + editVisualization(vis: VisualizationType) { this.spinner.show('loadingSpinner'); const queryParams = {}; diff --git a/frontend/src/app/shared/chart/types/visualization.type.ts b/frontend/src/app/shared/chart/types/visualization.type.ts index 8ace01447..d3b4765aa 100644 --- a/frontend/src/app/shared/chart/types/visualization.type.ts +++ b/frontend/src/app/shared/chart/types/visualization.type.ts @@ -21,6 +21,7 @@ export class VisualizationType { aggregationType?: MetricDataType; chartAction?: any; systemOwner?: boolean; + page?: any; } diff --git a/frontend/src/app/shared/services/util/enviroment.service.ts b/frontend/src/app/shared/services/util/enviroment.service.ts new file mode 100644 index 000000000..fa469e6d3 --- /dev/null +++ b/frontend/src/app/shared/services/util/enviroment.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import {environment} from '../../../../environments/environment'; + +@Injectable({ + providedIn: 'root' +}) +export class EnvironmentService { + + constructor() { } + + isDev(): boolean { + return !environment.production; + } + + isProd(): boolean { + return environment.production; + } +} From 37aff64812187958f0ef14f4c0d64099458b97a3 Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Fri, 4 Apr 2025 19:18:18 -0500 Subject: [PATCH 12/42] feat: allow edit and delete for non-owners only in dev mode --- .../utm-cp-reports/utm-cp-reports.component.html | 4 ++-- .../utm-cp-reports/utm-cp-reports.component.ts | 10 +++------- .../utm-cp-standard-section.component.html | 4 ++-- .../utm-cp-standard-section.component.ts | 9 ++------- .../utm-cp-standard/utm-cp-standard.component.ts | 6 ------ .../dashboard-list/dashboard-list.component.html | 4 ++-- .../dashboard-list/dashboard-list.component.ts | 10 +++------- .../visualization-list.component.html | 4 ++-- .../visualization-list/visualization-list.component.ts | 10 +++------- 9 files changed, 19 insertions(+), 42 deletions(-) diff --git a/frontend/src/app/compliance/compliance-management/utm-cp-reports/utm-cp-reports.component.html b/frontend/src/app/compliance/compliance-management/utm-cp-reports/utm-cp-reports.component.html index 07932f3d0..261258c36 100644 --- a/frontend/src/app/compliance/compliance-management/utm-cp-reports/utm-cp-reports.component.html +++ b/frontend/src/app/compliance/compliance-management/utm-cp-reports/utm-cp-reports.component.html @@ -24,14 +24,14 @@ class="w-100 card p-2 d-flex flex-column flex-grow-1"> - - dashboards class="icon-copy3 cursor-pointer mr-2" ngbTooltip="Copy dashboard URL" tooltipClass="utm-tooltip-top"> - - diff --git a/frontend/src/app/graphic-builder/dashboard-builder/dashboard-list/dashboard-list.component.ts b/frontend/src/app/graphic-builder/dashboard-builder/dashboard-list/dashboard-list.component.ts index 6395d7465..22fdcef65 100644 --- a/frontend/src/app/graphic-builder/dashboard-builder/dashboard-list/dashboard-list.component.ts +++ b/frontend/src/app/graphic-builder/dashboard-builder/dashboard-list/dashboard-list.component.ts @@ -1,5 +1,5 @@ import {HttpResponse} from '@angular/common/http'; -import {Component, OnInit} from '@angular/core'; +import {Component, isDevMode, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; import * as moment from 'moment'; @@ -17,7 +17,6 @@ import {DashboardImportComponent} from '../dashboard-import/dashboard-import.com import {UtmDashboardVisualizationService} from '../shared/services/utm-dashboard-visualization.service'; import {UtmDashboardService} from '../shared/services/utm-dashboard.service'; import {buildDashboardUrl} from '../shared/util/get-menu-url'; -import {EnvironmentService} from "../../../shared/services/util/enviroment.service"; @Component({ selector: 'app-dashboard-list', @@ -46,12 +45,12 @@ export class DashboardListComponent implements OnInit { checkbox: boolean; selected: number[] = []; exporting = false; + isDevMode = isDevMode; constructor(private modalService: NgbModal, private dashboardService: UtmDashboardService, private utmToastService: UtmToastService, private spinner: NgxSpinnerService, - private environment: EnvironmentService, private dashboardVisualizationService: UtmDashboardVisualizationService, private router: Router) { } @@ -65,10 +64,6 @@ export class DashboardListComponent implements OnInit { this.getDashboardList(); } - isDev(){ - return this.environment.isDev(); - } - onSortBy($event) { } @@ -216,4 +211,5 @@ export class DashboardListComponent implements OnInit { this.searching = false; this.loading = false; } + } diff --git a/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.html b/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.html index 53977b3a4..e02e075a7 100644 --- a/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.html +++ b/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.html @@ -126,11 +126,11 @@
Visualizations
- - diff --git a/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.ts b/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.ts index 166224e3c..bd0cd015a 100644 --- a/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.ts +++ b/frontend/src/app/graphic-builder/visualization/visualization-list/visualization-list.component.ts @@ -1,5 +1,5 @@ import {HttpResponse} from '@angular/common/http'; -import {Component, OnInit, QueryList, ViewChildren} from '@angular/core'; +import {Component, isDevMode, OnInit, QueryList, ViewChildren} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; @@ -18,7 +18,6 @@ import {VisualizationService} from '../shared/services/visualization.service'; import {VisualizationCreateComponent} from '../visualization-create/visualization-create.component'; import {VisualizationDeleteComponent} from '../visualization-delete/visualization-delete.component'; import {VisualizationImportComponent} from '../visualization-import/visualization-import.component'; -import {EnvironmentService} from "../../../shared/services/util/enviroment.service"; @Component({ selector: 'app-visualization-list', @@ -48,12 +47,12 @@ export class VisualizationListComponent implements OnInit { allPageSelected: boolean; sort: SortEvent; private requestParams: any; + isDevMode = isDevMode; constructor(private modalService: NgbModal, private visualizationService: VisualizationService, private spinner: NgxSpinnerService, private router: Router, - private environment: EnvironmentService, private activatedRoute: ActivatedRoute) { } @@ -72,10 +71,6 @@ export class VisualizationListComponent implements OnInit { }); } - isDev(){ - return this.environment.isDev(); - } - editVisualization(vis: VisualizationType) { this.spinner.show('loadingSpinner'); const queryParams = {}; @@ -204,4 +199,5 @@ export class VisualizationListComponent implements OnInit { private onError(error) { // this.alertService.error(error.error, error.message, null); } + } From bc841ba872df07b22613171930c702dbdf290b70 Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Sat, 5 Apr 2025 10:10:09 -0500 Subject: [PATCH 13/42] feat: add tag rule --- .../alert-rules/alert-rules.component.html | 3 ++ .../alert-rules/alert-rules.component.ts | 16 +++++++++ .../alert-rule-create.component.html | 20 +++++++++++ .../alert-rule-create.component.ts | 35 ++++++++++++++++--- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.html b/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.html index fcdd50a7b..8f927abdf 100644 --- a/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.html +++ b/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.html @@ -7,6 +7,9 @@
Alerts rules
routerLink="/data/alert/view"> Manage alerts +
diff --git a/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.ts b/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.ts index eda6db80f..848205759 100644 --- a/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.ts +++ b/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.ts @@ -12,6 +12,8 @@ import {TimeFilterType} from '../../../shared/types/time-filter.type'; import {AlertRulesService} from '../shared/services/alert-rules.service'; import {AlertTagService} from '../shared/services/alert-tag.service'; import {AlertRuleType} from './alert-rule.type'; +import {AlertRuleCreateComponent} from "../shared/components/alert-rule-create/alert-rule-create.component"; +import {FALSE_POSITIVE_OBJECT} from "../../../shared/constants/alert/alert-field.constant"; @Component({ selector: 'app-rules', @@ -35,6 +37,7 @@ export class AlertRulesComponent implements OnInit { }; viewRule: AlertRuleType; tags: AlertTags[]; + rule: AlertRuleType; constructor(private sourcesService: SourcesService, @@ -127,4 +130,17 @@ export class AlertRulesComponent implements OnInit { this.request.tagIds = $event.length === 0 ? null : $event.map(value => value.id); this.getRules(); } + + createRule() { + const modal = this.modalService.open(AlertRuleCreateComponent, {centered: true, size: 'lg'}); + const falsePositive: AlertTags[] = [FALSE_POSITIVE_OBJECT]; + if (this.rule) { + modal.componentInstance.rule = this.rule; + } + modal.componentInstance.isForComplete = true; + modal.componentInstance.tags = falsePositive; + modal.componentInstance.ruleAdd.subscribe(rule => { + this.rule = rule; + }); + } } diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html index 77bcdddca..45417cb43 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html @@ -74,6 +74,26 @@
+
+ +
+ + +
+
+
diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.ts b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.ts index 35b2eff82..0a0832322 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.ts +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.ts @@ -29,17 +29,18 @@ import { ALERT_STATUS_LABEL_FIELD, ALERT_TAGS_FIELD, ALERT_TIMESTAMP_FIELD, - EVENT_IS_ALERT, + EVENT_IS_ALERT, INCIDENT_AUTOMATION_ALERT_FIELDS, LOG_RELATED_ID_EVENT_FIELD } from '../../../../../shared/constants/alert/alert-field.constant'; import {CLOSED} from '../../../../../shared/constants/alert/alert-status.constant'; import {FILTER_OPERATORS} from '../../../../../shared/constants/filter-operators.const'; +import {ALERT_INDEX_PATTERN} from "../../../../../shared/constants/main-index-pattern.constant"; import {ElasticOperatorsEnum} from '../../../../../shared/enums/elastic-operators.enum'; +import {ElasticSearchIndexService} from "../../../../../shared/services/elasticsearch/elasticsearch-index.service"; import {AlertTags} from '../../../../../shared/types/alert/alert-tag.type'; import {UtmAlertType} from '../../../../../shared/types/alert/utm-alert.type'; import {ElasticFilterType} from '../../../../../shared/types/filter/elastic-filter.type'; import {OperatorsType} from '../../../../../shared/types/filter/operators.type'; -import {UtmFieldType} from '../../../../../shared/types/table/utm-field.type'; import {getValueFromPropertyPath} from '../../../../../shared/util/get-value-object-from-property-path.util'; import {InputClassResolve} from '../../../../../shared/util/input-class-resolve'; import {AlertRuleType} from '../../../alert-rules/alert-rule.type'; @@ -49,7 +50,8 @@ import {AlertManagementService} from '../../services/alert-management.service'; import {AlertRulesService} from '../../services/alert-rules.service'; import {AlertTagService} from '../../services/alert-tag.service'; import {setAlertPropertyValue} from '../../util/alert-util-function'; -import {ElasticSearchFieldInfoType} from "../../../../../shared/types/elasticsearch/elastic-search-field-info.type"; +import {sanitizeFilters} from "../../../../../shared/util/elastic-filter.util"; +import {HttpResponse} from "@angular/common/http"; @Component({ selector: 'app-alert-rule-create', @@ -100,6 +102,8 @@ export class AlertRuleCreateComponent implements OnInit { uuid = UUID.UUID(); tagging = false; ElasticOperatorsEnum = ElasticOperatorsEnum; + alerts = []; + loadingAlerts: boolean = false; constructor(public activeModal: NgbActiveModal, public inputClass: InputClassResolve, @@ -110,12 +114,17 @@ export class AlertRuleCreateComponent implements OnInit { private alertUpdateTagBehavior: AlertUpdateTagBehavior, private alertServiceManagement: AlertManagementService, private alertTagService: AlertTagService, - private operatorService: OperatorService) { + private operatorService: OperatorService, + private elasticDataService: ElasticSearchIndexService) { + this.fields = ALERT_FIELDS.filter(value => !this.excludeFields.includes(value.field)); this.operators = FILTER_OPERATORS.filter(value => !this.excludeOperators.includes(value.operator)); } ngOnInit() { + if ( !this.alert) { + this.getAlerts(); + } this.getTags(); this.initForm(); this.createDefaultFilters(); @@ -255,4 +264,22 @@ export class AlertRuleCreateComponent implements OnInit { } return this.operators; } + + getAlert() { + this.elasticDataService.search( + this.page, + this.itemsPerPage, + 100000000, + this.dataNature, + sanitizeFilters(this.filters), this.sortBy).subscribe( + (res: HttpResponse) => { + this.alerts = res.body; + this.loading = false; + this.refreshingAlert = false; + }, + (res: HttpResponse) => { + this.utmToastService.showError('Error', 'An error occurred while listing the alerts. Please try again later.'); + } + ); + } } From 0d74492a385fc73fe596d834793e3dcb4261ce39 Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Sat, 5 Apr 2025 10:59:00 -0500 Subject: [PATCH 14/42] feat: add tag rule --- .../alert-rule-create.component.html | 27 ++++---- .../alert-rule-create.component.ts | 64 ++++++++++++++++--- 2 files changed, 70 insertions(+), 21 deletions(-) diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html index 45417cb43..08936079d 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html @@ -77,19 +77,20 @@
- +
diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.ts b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.ts index 0a0832322..14a457b0c 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.ts +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.ts @@ -52,6 +52,7 @@ import {AlertTagService} from '../../services/alert-tag.service'; import {setAlertPropertyValue} from '../../util/alert-util-function'; import {sanitizeFilters} from "../../../../../shared/util/elastic-filter.util"; import {HttpResponse} from "@angular/common/http"; +import {ElasticDataService} from "../../../../../shared/services/elasticsearch/elastic-data.service"; @Component({ selector: 'app-alert-rule-create', @@ -103,7 +104,20 @@ export class AlertRuleCreateComponent implements OnInit { tagging = false; ElasticOperatorsEnum = ElasticOperatorsEnum; alerts = []; - loadingAlerts: boolean = false; + alertRequest = { + page: 0, + size: 100, + sort: '@timestamp,desc', + index: ALERT_INDEX_PATTERN, + filters: [ + {field: 'status', operator: 'IS_NOT', value: 1}, + {field: 'tags', operator: 'IS_NOT', value: 'False positive'}, + {field: '@timestamp', operator: 'IS_BETWEEN', value: ['now-30d', 'now']} + ], + dataNature: null, + }; + loading = false; + refreshingAlert = false; constructor(public activeModal: NgbActiveModal, public inputClass: InputClassResolve, @@ -115,7 +129,7 @@ export class AlertRuleCreateComponent implements OnInit { private alertServiceManagement: AlertManagementService, private alertTagService: AlertTagService, private operatorService: OperatorService, - private elasticDataService: ElasticSearchIndexService) { + private elasticDataService: ElasticDataService) { this.fields = ALERT_FIELDS.filter(value => !this.excludeFields.includes(value.field)); this.operators = FILTER_OPERATORS.filter(value => !this.excludeOperators.includes(value.operator)); @@ -252,7 +266,6 @@ export class AlertRuleCreateComponent implements OnInit { }); } - isFalsePositive() { return this.selected.findIndex(value => value.tagName.includes('False positive')) !== -1; } @@ -265,13 +278,48 @@ export class AlertRuleCreateComponent implements OnInit { return this.operators; } - getAlert() { + onDataTypeChange(selectedDataTypes: DataType[]) { + this.ruleForm.get('dataTypes').patchValue(selectedDataTypes); + this.dataTypeService.resetTypes(); + this.daTypeRequest.page = -1; + this.loadDataTypes(); + } + + onSearch(event: { term: string; items: any[] }) { + this.alertRequest = { + ...this.alertRequest, + filters: [ + ...this.alertRequest.filters.filter(f => f.operator !== ElasticOperatorsEnum.IS_IN_FIELD), + {field: 'name', operator: ElasticOperatorsEnum.IS_IN_FIELD, value: event.term} + ] + }; + + this.getAlerts(); + } + + loadDataTypes() { + this.daTypeRequest.page = this.daTypeRequest.page + 1; + this.loadingDataTypes = true; + + this.dataTypeService.getAll(this.daTypeRequest) + .subscribe(data => { + this.loadingDataTypes = false; + }); + } + + + trackByFn(alert: any) { + return alert.id; + } + + getAlerts() { this.elasticDataService.search( - this.page, - this.itemsPerPage, + this.alertRequest.page, + this.alertRequest.size, 100000000, - this.dataNature, - sanitizeFilters(this.filters), this.sortBy).subscribe( + this.alertRequest.dataNature, + sanitizeFilters(this.alertRequest.filters), + this.alertRequest.sort).subscribe( (res: HttpResponse) => { this.alerts = res.body; this.loading = false; From 6479ea3b93bab7e5fdf5826a5749b9e4b1df885a Mon Sep 17 00:00:00 2001 From: Manuel Abascal Date: Mon, 7 Apr 2025 14:30:23 -0500 Subject: [PATCH 15/42] feat: enable create and update for incident response --- .../alert-rules/alert-rules.component.html | 4 +- .../alert-rules/alert-rules.component.ts | 21 ++- .../alert-tags-apply.component.ts | 1 + .../alert-complete.component.ts | 1 + .../alert-rule-create.component.html | 55 +++---- .../alert-rule-create.component.ts | 151 +++++++++++++----- .../shared/services/alert.service.ts | 39 +++++ 7 files changed, 192 insertions(+), 80 deletions(-) create mode 100644 frontend/src/app/incident-response/shared/services/alert.service.ts diff --git a/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.html b/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.html index 8f927abdf..1a038d97e 100644 --- a/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.html +++ b/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.html @@ -77,7 +77,9 @@
Alerts rules
{{rule.lastModifiedDate | date:'short' }} {{rule.createdBy }} - + + diff --git a/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.ts b/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.ts index 848205759..db456d788 100644 --- a/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.ts +++ b/frontend/src/app/data-management/alert-management/alert-rules/alert-rules.component.ts @@ -12,8 +12,8 @@ import {TimeFilterType} from '../../../shared/types/time-filter.type'; import {AlertRulesService} from '../shared/services/alert-rules.service'; import {AlertTagService} from '../shared/services/alert-tag.service'; import {AlertRuleType} from './alert-rule.type'; -import {AlertRuleCreateComponent} from "../shared/components/alert-rule-create/alert-rule-create.component"; -import {FALSE_POSITIVE_OBJECT} from "../../../shared/constants/alert/alert-field.constant"; +import {AlertRuleCreateComponent} from '../shared/components/alert-rule-create/alert-rule-create.component'; +import {FALSE_POSITIVE_OBJECT} from '../../../shared/constants/alert/alert-field.constant'; @Component({ selector: 'app-rules', @@ -131,16 +131,23 @@ export class AlertRulesComponent implements OnInit { this.getRules(); } - createRule() { + createRule(rule?: AlertRuleType) { const modal = this.modalService.open(AlertRuleCreateComponent, {centered: true, size: 'lg'}); const falsePositive: AlertTags[] = [FALSE_POSITIVE_OBJECT]; - if (this.rule) { - modal.componentInstance.rule = this.rule; + if (rule) { + modal.componentInstance.rule = rule; } - modal.componentInstance.isForComplete = true; + modal.componentInstance.isForComplete = rule; + modal.componentInstance.action = rule ? 'update' : 'create'; modal.componentInstance.tags = falsePositive; modal.componentInstance.ruleAdd.subscribe(rule => { - this.rule = rule; + this.rule = null; + this.getRules(); + this.getTags(); }); } + + editRuleAction(rule: AlertRuleType) { + this.createRule(rule); + } } diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-actions/alert-apply-tags/alert-tags-apply.component.ts b/frontend/src/app/data-management/alert-management/shared/components/alert-actions/alert-apply-tags/alert-tags-apply.component.ts index f0b0cefa4..d427ea542 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-actions/alert-apply-tags/alert-tags-apply.component.ts +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-actions/alert-apply-tags/alert-tags-apply.component.ts @@ -52,6 +52,7 @@ export class AlertTagsApplyComponent implements OnInit, OnChanges { addNewTagRule() { const modalRef = this.modalService.open(AlertRuleCreateComponent, {centered: true, size: 'lg'}); modalRef.componentInstance.alert = this.alert; + modalRef.componentInstance.action = 'select'; modalRef.componentInstance.ruleAdd.subscribe((created) => { this.icon = this.getTagIcon(); this.color = this.getColor(); diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-complete/alert-complete.component.ts b/frontend/src/app/data-management/alert-management/shared/components/alert-complete/alert-complete.component.ts index 0cc6d4792..e82d086da 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-complete/alert-complete.component.ts +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-complete/alert-complete.component.ts @@ -67,6 +67,7 @@ export class AlertCompleteComponent implements OnInit { modal.componentInstance.rule = this.rule; } modal.componentInstance.alert = this.alert; + modal.componentInstance.action = 'select'; modal.componentInstance.isForComplete = true; modal.componentInstance.tags = falsePositive; modal.componentInstance.ruleAdd.subscribe(rule => { diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html index 08936079d..71cc4e550 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-rule-create/alert-rule-create.component.html @@ -1,6 +1,6 @@ - +
-
+
-
@@ -30,6 +30,23 @@
+ + +
+ + +
+
+
@@ -56,7 +73,7 @@
+ ({{ 512 - formRule.get('description').value.length }})