Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
3ecb012
fix: move exception handling to prevent workflow interruptions
mjabascal10 Mar 28, 2025
6740b67
chore: set version
mjabascal10 Mar 28, 2025
a47755a
chore: set version
mjabascal10 Mar 28, 2025
aa09097
chore: update changelog
mjabascal10 Mar 28, 2025
45a095d
feat: filter compliance reports based on active integration
mjabascal10 Mar 31, 2025
1a4f237
chore: update changeLog
mjabascal10 Mar 31, 2025
6689b60
feat: filter compliance reports based on active integration
mjabascal10 Mar 31, 2025
6b08e6a
fix: improve field value validation for "contains one of" and "does n…
mjabascal10 Mar 31, 2025
418f4cd
feat: improve operator selection based on field type
mjabascal10 Apr 2, 2025
fe8aaa2
feat: improve operator selection based on field type
mjabascal10 Apr 2, 2025
3b5ff92
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 4, 2025
37aff64
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 5, 2025
bc841ba
feat: add tag rule
mjabascal10 Apr 5, 2025
0d74492
feat: add tag rule
mjabascal10 Apr 5, 2025
6479ea3
feat: enable create and update for incident response
mjabascal10 Apr 7, 2025
f7dead1
feat: enable create and update for incident response
mjabascal10 Apr 7, 2025
b3ca58f
Merge remote-tracking branch 'origin/bugfix/10.7.1/alerts-stopping-ta…
mjabascal10 Apr 7, 2025
97d1353
feat: add new compliance reports
mjabascal10 Apr 7, 2025
d78e3c4
feat: add new compliance reports
mjabascal10 Apr 8, 2025
404ea60
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 8, 2025
81f55ed
Merge remote-tracking branch 'origin/bugfix/10.7.1/alerts-stopping-ta…
mjabascal10 Apr 8, 2025
8944439
feat: add new compliance reports
mjabascal10 Apr 8, 2025
48dc770
chore: update changelog
mjabascal10 Apr 8, 2025
3ee2849
Merge remote-tracking branch 'origin/bugfix/10.7.1/alerts-stopping-ta…
mjabascal10 Apr 8, 2025
7e1f2fc
fix: move exception handling to prevent workflow interruptions
mjabascal10 Mar 28, 2025
3432c72
chore: set version
mjabascal10 Mar 28, 2025
9627024
chore: update changelog
mjabascal10 Mar 28, 2025
d2015d3
feat: filter compliance reports based on active integration
mjabascal10 Mar 31, 2025
5cc27a0
chore: update changeLog
mjabascal10 Mar 31, 2025
6c904db
feat: filter compliance reports based on active integration
mjabascal10 Mar 31, 2025
d6b47df
fix: improve field value validation for "contains one of" and "does n…
mjabascal10 Mar 31, 2025
1b05c3c
feat: improve operator selection based on field type
mjabascal10 Apr 2, 2025
6b242d0
feat: improve operator selection based on field type
mjabascal10 Apr 2, 2025
8adde75
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 4, 2025
1c802e2
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 5, 2025
12515a1
feat: add tag rule
mjabascal10 Apr 5, 2025
8d563d9
feat: add tag rule
mjabascal10 Apr 5, 2025
73a719c
feat: enable create and update for incident response
mjabascal10 Apr 7, 2025
8b32345
feat: enable create and update for incident response
mjabascal10 Apr 7, 2025
cd1b0d5
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 8, 2025
1e0eaaa
chore: update changelog
mjabascal10 Apr 8, 2025
bb7bdca
feat: add new compliance reports
mjabascal10 Apr 7, 2025
4597f19
feat: add new compliance reports
mjabascal10 Apr 8, 2025
5579c5d
feat: add new compliance reports
mjabascal10 Apr 8, 2025
8e865ba
Merge remote-tracking branch 'origin/bugfix/10.7.1/alerts-stopping-ta…
mjabascal10 Apr 8, 2025
1e918d3
chore: update changelog
mjabascal10 Apr 8, 2025
178c988
feat: enable create and update of tag-based rules with dynamic condit…
mjabascal10 Apr 9, 2025
85cf8aa
feat: enable create and update of tag-based rules with dynamic condit…
mjabascal10 Apr 9, 2025
3afb2b8
feat: enable create and update of tag-based rules with dynamic condit…
mjabascal10 Apr 9, 2025
8a59bc3
chore: update changelog
mjabascal10 Mar 28, 2025
043d1e5
feat: filter compliance reports based on active integration
mjabascal10 Mar 31, 2025
3bb2894
chore: update changeLog
mjabascal10 Mar 31, 2025
0480370
feat: improve operator selection based on field type
mjabascal10 Apr 2, 2025
11e0473
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 4, 2025
ceedafb
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 5, 2025
5d4b8a5
feat: add tag rule
mjabascal10 Apr 5, 2025
acdb0f5
feat: add tag rule
mjabascal10 Apr 5, 2025
e74fed1
feat: enable create and update for incident response
mjabascal10 Apr 7, 2025
a1e13c0
chore: update changelog
mjabascal10 Apr 8, 2025
c4820f0
feat: add new compliance reports
mjabascal10 Apr 7, 2025
e9b81e1
feat: add new compliance reports
mjabascal10 Apr 8, 2025
05502c9
feat: filter compliance reports based on active integration
mjabascal10 Mar 31, 2025
0067d9c
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 4, 2025
9b26eb7
feat: allow edit and delete for non-owners only in dev mode
mjabascal10 Apr 5, 2025
f95e775
feat: add tag rule
mjabascal10 Apr 5, 2025
4be4604
feat: add tag rule
mjabascal10 Apr 5, 2025
d8580fc
feat: enable create and update for incident response
mjabascal10 Apr 7, 2025
b48942a
feat: add new compliance reports
mjabascal10 Apr 7, 2025
2938c0e
feat: add new compliance reports
mjabascal10 Apr 8, 2025
4c960a8
chore: update changelog
mjabascal10 Apr 8, 2025
26eb18b
feat: enable create and update of tag-based rules with dynamic condit…
mjabascal10 Apr 9, 2025
ddd1b16
feat: enable create and update of tag-based rules with dynamic condit…
mjabascal10 Apr 9, 2025
19629ae
feat: enable create and update of tag-based rules with dynamic condit…
mjabascal10 Apr 9, 2025
d7cc7df
feat: enable create and update of tag-based rules with dynamic condit…
mjabascal10 Apr 9, 2025
c6a8021
Merge remote-tracking branch 'origin/bugfix/10.7.1/alerts-stopping-ta…
mjabascal10 Apr 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
### 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.
-- Improved operator selection for more accurate and consistent filtering.
-- Introduced new compliance reports aligned with the PCI DSS standard to expand auditing capabilities.
-- Introduced new compliance reports aligned with the PCI DSS standard to expand auditing capabilities.
-- Enabled creation and update of tag-based rules with dynamic conditions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ <h5 class="card-title mb-0 label-header">Alerts rules</h5>
Manage alerts
</button>
<button (click)="createRule()" class="btn utm-button utm-button-primary ml-2">
Add tag rule
Create tag rule
</button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {SourcesService} from '../../../admin/sources/sources.service';
import {UtmToastService} from '../../../shared/alert/utm-toast.service';
import {ModalConfirmationComponent} from '../../../shared/components/utm/util/modal-confirmation/modal-confirmation.component';
import {FALSE_POSITIVE_OBJECT} from '../../../shared/constants/alert/alert-field.constant';
import {ITEMS_PER_PAGE} from '../../../shared/constants/pagination.constants';
import {SortEvent} from '../../../shared/directives/sortable/type/sort-event';
import {AlertTags} from '../../../shared/types/alert/alert-tag.type';
import {TimeFilterType} from '../../../shared/types/time-filter.type';
import {AlertRuleCreateComponent} from '../shared/components/alert-rule-create/alert-rule-create.component';
import {AlertRulesService} from '../shared/services/alert-rules.service';
import {AlertTagService} from '../shared/services/alert-tag.service';
import {AlertRuleType} from './alert-rule.type';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<app-utm-modal-header [name]="(action === 'update' ? 'Update' : 'Add new') + ' tag rule'" class="w-100"></app-utm-modal-header>
<app-utm-modal-header [name]="(action === 'update' ? 'Update' : 'Add new') + ' tag rule'"
class="w-100"></app-utm-modal-header>
<div class="container-fluid p-3" style="z-index: 99999999">
<div class="w-100">
<div *ngIf="!tags"
Expand Down Expand Up @@ -30,22 +31,22 @@
</div>
</div>

<ng-container *ngIf="action !== 'select'">
<label class="pb-1">Alerts</label>
<div class="d-flex justify-content-between align-items-center mb-3">
<ng-select (change)="onAlertChange($event)"
(search)="onSearch($event)"
(scrollToEnd)="loadMoreAlerts()"
[items]="(alerts$ | async)"
[loading]="loading"
[trackByFn]="trackByFn"
[virtualScroll]="true"
bindLabel="name"
class="flex-item type-select w-100"
placeholder="Choose an alert">
</ng-select>
</div>
</ng-container>
<!--<ng-container *ngIf="action !== 'select'">
<label class="pb-1">Alerts</label>
<div class="d-flex justify-content-between align-items-center mb-3">
<ng-select (change)="onAlertChange($event)"
(search)="onSearch($event)"
(scrollToEnd)="loadMoreAlerts()"
[items]="(alerts$ | async)"
[loading]="loading"
[trackByFn]="trackByFn"
[virtualScroll]="true"
bindLabel="name"
class="flex-item type-select w-100"
placeholder="Choose an alert">
</ng-select>
</div>
</ng-container>-->

<form [formGroup]="formRule">
<div class="form-group">
Expand Down Expand Up @@ -81,48 +82,70 @@
rows="2"></textarea>
<app-formcontrol-error [formcontrol]="formRule.get('description')"></app-formcontrol-error>
</div>
</form>

<div *ngIf="isFalsePositive()" class="w-100">
<div class="alert bg-info-400 text-white alert-styled-right mt-3">
<div *ngIf="isFalsePositive()" class="w-100">
<div class="alert bg-info-400 text-white alert-styled-right mt-3">
<span>By creating a False Positive rule, future alerts where the fields
and values match the operator defined will be tagged as <b>False positive</b>.
The alerts that match with this rule will be marked as <b>Completed</b>.</span>
</div>
</div>
</div>

<div class="d-flex justify-content-start align-items-center mt-3">
<div class="d-flex justify-content-start align-items-center mt-3">
<span (click)="viewFieldDetail=!viewFieldDetail"
class="text-center cursor-pointer">
<i [ngClass]="viewFieldDetail?'icon-arrow-up32':'icon-arrow-down32'"></i>
<span class="font-weight-semibold">View rule fields</span>&nbsp;
</span>&nbsp;
</div>
<div *ngIf="viewFieldDetail" class="alert-history mt-2">
<div class="d-flex justify-content-between align-items-center pb-2" *ngFor="let filter of filters">
<span class="text-blue-800 rule-label">{{ getFieldName(filter.field) }}:&nbsp;</span>
<ng-select
[clearable]="false"
[items]="getOperators(filter)"
[(ngModel)]="filter.operator"
[loadingText]="'Loading operators....'"
[loading]="!operators"
[searchable]="true"
bindLabel="name"
class="rule-operator"
dropdownPosition="top"
bindValue="operator"
id="operators">
</ng-select>
<input
[style.visibility]="filter.operator == ElasticOperatorsEnum.EXIST || filter.operator == ElasticOperatorsEnum.DOES_NOT_EXIST ? 'hidden' : 'visible'"
[(ngModel)]="filter.value" class="form-control">
<i class="icon-cross2 cursor-pointer ml-3" ngbTooltip="Delete filter field"
placement="left"
(click)="deleteFilter(filter)"></i>
</div>
</div>

<div *ngIf="viewFieldDetail" class="alert-history mt-2">
<div formArrayName="conditions">
<div class="d-flex justify-content-between align-items-center pb-2"
*ngFor="let condition of ruleConditions.controls; let i = index" [formGroupName]="i">
<span *ngIf="action === 'select'"
class="text-blue-800 rule-label">{{ getFieldName(condition.get('field').value) }}:&nbsp;</span>
<ng-select *ngIf="action !== 'select'"
formControlName="field"
[clearable]="false"
[items]="fields"
[loadingText]="'Loading fields....'"
[loading]="!operators"
[searchable]="true"
bindLabel="label"
class="rule-operator"
dropdownPosition="top"
bindValue="field"
id="fields">
</ng-select>
<ng-select
formControlName="operator"
[clearable]="false"
[items]="getOperators(condition.get('field').value)"
[loadingText]="'Loading operators....'"
[loading]="!operators"
[searchable]="true"
bindLabel="name"
class="rule-operator"
dropdownPosition="top"
bindValue="operator"
id="operators">
</ng-select>
<input formControlName="value"
[style.visibility]="condition.get('operator').value == ElasticOperatorsEnum.EXIST || condition.get('operator').value == ElasticOperatorsEnum.DOES_NOT_EXIST ? 'hidden' : 'visible'"
class="form-control">
<i *ngIf="ruleConditions.length > 1" class="icon-cross2 cursor-pointer ml-3" ngbTooltip="Delete filter field"
placement="left"
(click)="removeRuleCondition(i)"></i>
</div>
<div class="d-flex justify-content-end mt-2">
<button class="btn utm-button btn-success align-self-end" (click)="addRuleCondition()">
<i class="icon-plus22"></i>&nbsp;
Add
</button>
</div>
</div>
</div>
</form>

<div class="button-container d-flex justify-content-end mt-3">
<button (click)="activeModal.close()" class="btn utm-button utm-button-grey mr-3">
Expand All @@ -132,7 +155,7 @@
<button (click)="saveRule()" class="btn utm-button utm-button-primary"
[disabled]="!formRule.valid || exist || selected.length === 0">
<i class="icon-stack-text"></i>&nbsp;
Add rule & Tag
{{ (action === 'update' ? 'Update ' : 'Add ') + 'rule & Tag' }}
</button>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {HttpResponse} from '@angular/common/http';
import {Component, EventEmitter, Input, OnDestroy, OnInit, Output} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {AbstractControl, FormArray, FormBuilder, FormGroup, Validators} from '@angular/forms';
import {NgbActiveModal, NgbModal} from '@ng-bootstrap/ng-bootstrap';
import {UUID} from 'angular2-uuid';
import {Observable, Subject} from 'rxjs';
Expand All @@ -20,7 +20,7 @@ import {
ALERT_INCIDENT_FLAG_FIELD,
ALERT_INCIDENT_MODULE_FIELD,
ALERT_INCIDENT_OBSERVATION_FIELD,
ALERT_INCIDENT_USER_FIELD,
ALERT_INCIDENT_USER_FIELD, ALERT_NAME_FIELD,
ALERT_NOTE_FIELD,
ALERT_OBSERVATION_FIELD,
ALERT_REFERENCE_FIELD,
Expand Down Expand Up @@ -142,18 +142,12 @@ export class AlertRuleCreateComponent implements OnInit, OnDestroy {
ngOnInit() {

this.initForm();
this.createDefaultFilters();
this.getTags();
this.formRule.get('name').valueChanges.pipe(debounceTime(3000)).subscribe(ruleName => {
this.searchRule(ruleName);
});

if (!this.alert) {
this.loading = true;
this.alertService.notifyRefresh(true);
} else {
this.createDefaultFilters();
}

if (this.rule) {
this.filters = [... this.rule.conditions];
this.selected = this.rule.tags.length > 0 ? [...this.rule.tags] : [];
Expand All @@ -173,18 +167,52 @@ export class AlertRuleCreateComponent implements OnInit, OnDestroy {
id: [this.rule ? this.rule.id : null],
name: [ this.rule ? this.rule.name : '', Validators.required],
description: [this.rule ? this.rule.description : '', Validators.required],
conditions: [ this.rule ? this.rule.conditions : [], Validators.required],
conditions: this.fb.array([], Validators.required),
tags: [this.rule ? this.rule.tags : null, Validators.required],
});
}

createDefaultFilters() {
if (this.alert) {
this.initConditionsFromAlert();
} else {
this.initConditionsFromAction();
}

this.subscribeToFieldChanges();
}

private initConditionsFromAlert() {
for (const field of this.fields) {
if (this.getFieldValue(field.field)) {
this.filters.push({field: field.field, operator: ElasticOperatorsEnum.IS, value: this.getFieldValue(field.field)});
const value = this.getFieldValue(field.field);
if (value) {
const condition = this.buildCondition(field.field, value);
this.filters.push(condition);
this.ruleConditions.push(this.createConditionGroup(condition));
}
}
this.formRule.get('conditions').setValue(this.filters);
}

private initConditionsFromAction() {
if (this.action === 'create') {
const field = this.fields[0];
const condition = this.buildCondition(field.field, '');
this.filters.push(condition);
this.ruleConditions.push(this.createConditionGroup(condition));
} else if (this.action === 'update') {
this.filters = [...this.rule.conditions];
this.rule.conditions.forEach(condition => {
this.ruleConditions.push(this.createConditionGroup(condition));
});
}
}

private buildCondition(field: string, value: any) {
return {
field,
operator: ElasticOperatorsEnum.IS,
value
};
}

getFieldValue(field: string): any {
Expand Down Expand Up @@ -262,8 +290,8 @@ export class AlertRuleCreateComponent implements OnInit, OnDestroy {

}

deleteFilter(filter: ElasticFilterType) {
const index = this.filters.indexOf(filter);
deleteFilter(elasticFilterType: ElasticFilterType) {
const index = this.filters.indexOf(elasticFilterType);
if (index !== -1) {
this.filters.splice(index, 1);
this.formRule.get('conditions').setValue(this.filters);
Expand Down Expand Up @@ -326,8 +354,8 @@ export class AlertRuleCreateComponent implements OnInit, OnDestroy {
return this.selected.findIndex(value => value.tagName.includes('False positive')) !== -1;
}

getOperators(filter: ElasticFilterType) {
const field = this.fields.find(f => f.field === filter.field);
getOperators(conditionField: string) {
const field = this.fields.find(f => f.field === conditionField);
if (field) {
return this.operatorService.getOperators({name: field.field, type: field.type}, this.operators);
}
Expand Down Expand Up @@ -391,6 +419,48 @@ export class AlertRuleCreateComponent implements OnInit, OnDestroy {
this.activeModal.close();
}

get ruleConditions() {
return this.formRule.get('conditions') as FormArray;
}

removeRuleCondition(index: number) {
this.ruleConditions.removeAt(index);
}

createConditionGroup(condition: any): FormGroup {
return this.fb.group({
field: [condition.field, Validators.required],
operator: [condition.operator, Validators.required],
value: [condition.value]
});
}

subscribeToFieldChanges() {
this.ruleConditions.controls.forEach((group: AbstractControl, index: number) => {
const fieldControl = group.get('field');
const operatorControl = group.get('operator');

fieldControl.valueChanges
.pipe(takeUntil(this.destroy$))
.subscribe(newField => {
const validOperators = this.getOperators(newField).map(op => op.operator);
if (!validOperators.includes(operatorControl.value)) {
operatorControl.setValue(null);
}
});
});
}

addRuleCondition() {
this.ruleConditions.push(
this.createConditionGroup({
field: this.fields[0].field,
operator: null,
value: null
}));
this.subscribeToFieldChanges();
}

ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
Expand Down
Loading