Skip to content

Commit ca86b1a

Browse files
authored
Merge branch 'release/v11.2.9' into fix/dependabot-remediation
Signed-off-by: Osmany Montero <osmontero@icloud.com>
2 parents 3701c7f + 007d88b commit ca86b1a

22 files changed

Lines changed: 268 additions & 99 deletions

File tree

agent/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
github.com/threatwinds/go-sdk v1.1.21
1717
github.com/threatwinds/logger v1.2.3
1818
github.com/utmstack/UTMStack/shared v0.0.0
19-
golang.org/x/sys v0.44.0
19+
golang.org/x/sys v0.45.0
2020
google.golang.org/grpc v1.81.1
2121
google.golang.org/protobuf v1.36.11
2222
gorm.io/gorm v1.31.1

agent/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
189189
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
190190
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
191191
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
192-
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
193-
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
192+
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
193+
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
194194
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
195195
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
196196
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=

backend/src/main/java/com/park/utmstack/domain/application_modules/factory/impl/ModuleSocAi.java

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,83 @@ public List<ModuleRequirement> checkRequirements(Long serverId) throws Exception
4545
public List<ModuleConfigurationKey> getConfigurationKeys(Long groupId) throws Exception {
4646
List<ModuleConfigurationKey> keys = new ArrayList<>();
4747

48+
keys.add(ModuleConfigurationKey.builder()
49+
.withGroupId(groupId)
50+
.withConfKey("utmstack.socai.provider")
51+
.withConfName("AI Provider")
52+
.withConfDescription("AI provider used by SOC AI.")
53+
.withConfDataType("text")
54+
.withConfValue("openai")
55+
.withConfRequired(true)
56+
.build());
57+
58+
keys.add(ModuleConfigurationKey.builder()
59+
.withGroupId(groupId)
60+
.withConfKey("utmstack.socai.model")
61+
.withConfName("AI Model")
62+
.withConfDescription("AI model that SOC AI will use to analyze alerts (first option of active provider).")
63+
.withConfDataType("text")
64+
.withConfValue("gpt-4o")
65+
.withConfRequired(true)
66+
.build());
67+
68+
keys.add(ModuleConfigurationKey.builder()
69+
.withGroupId(groupId)
70+
.withConfKey("utmstack.socai.url")
71+
.withConfName("Provider URL")
72+
.withConfDescription("Endpoint URL for the provider (only set for azure / ollama / custom).")
73+
.withConfDataType("text")
74+
.withConfValue("")
75+
.withConfRequired(false)
76+
.build());
77+
78+
keys.add(ModuleConfigurationKey.builder()
79+
.withGroupId(groupId)
80+
.withConfKey("utmstack.socai.maxTokens")
81+
.withConfName("Max Tokens")
82+
.withConfDescription("Maximum number of tokens used per request.")
83+
.withConfDataType("text")
84+
.withConfValue("4096")
85+
.withConfRequired(true)
86+
.build());
87+
88+
keys.add(ModuleConfigurationKey.builder()
89+
.withGroupId(groupId)
90+
.withConfKey("utmstack.socai.authType")
91+
.withConfName("Authentication Type")
92+
.withConfDescription("Authentication type used to reach the provider (none for ollama).")
93+
.withConfDataType("text")
94+
.withConfValue("custom-headers")
95+
.withConfRequired(true)
96+
.build());
97+
98+
keys.add(ModuleConfigurationKey.builder()
99+
.withGroupId(groupId)
100+
.withConfKey("utmstack.socai.customHeaders")
101+
.withConfName("Custom Headers")
102+
.withConfDescription("Custom headers (JSON object) sent with each request to the provider.")
103+
.withConfDataType("password")
104+
.withConfValue("")
105+
.withConfRequired(false)
106+
.build());
107+
108+
keys.add(ModuleConfigurationKey.builder()
109+
.withGroupId(groupId)
110+
.withConfKey("utmstack.socai.autoAnalyze")
111+
.withConfName("Auto Analyze")
112+
.withConfDescription("If set to \"true\", SOC AI will automatically analyze incoming alerts.")
113+
.withConfDataType("text")
114+
.withConfValue("false")
115+
.withConfRequired(false)
116+
.build());
117+
48118
keys.add(ModuleConfigurationKey.builder()
49119
.withGroupId(groupId)
50120
.withConfKey("utmstack.socai.incidentCreation")
51121
.withConfName("Automatic Incident creation")
52122
.withConfDescription("If set to \"true\", the system will create incidents based on analysis of alerts.")
53-
.withConfDataType("bool")
123+
.withConfDataType("text")
124+
.withConfValue("false")
54125
.withConfRequired(false)
55126
.build());
56127

@@ -60,37 +131,11 @@ public List<ModuleConfigurationKey> getConfigurationKeys(Long groupId) throws Ex
60131
.withConfName("Change Alert Status")
61132
.withConfDescription("If set to \"true\", SOC Ai will automatically change the status of alerts. " +
62133
"Analysts should investigate those with the status \"In Review\".")
63-
.withConfDataType("bool")
134+
.withConfDataType("text")
135+
.withConfValue("false")
64136
.withConfRequired(false)
65137
.build());
66138

67-
keys.add(ModuleConfigurationKey.builder()
68-
.withGroupId(groupId)
69-
.withConfKey("utmstack.socai.model")
70-
.withConfName("Select AI Model")
71-
.withConfDescription("Choose the AI model that SOC AI will use to analyze alerts.")
72-
.withConfDataType("select")
73-
.withConfRequired(true)
74-
.withConfOptions(
75-
"[" +
76-
"{\"value\": \"gpt-4\", \"label\": \"GPT-4\"}," +
77-
"{\"value\": \"gpt-4-0613\", \"label\": \"GPT-4 (0613)\"}," +
78-
"{\"value\": \"gpt-4-32k\", \"label\": \"GPT-4 32K\"}," +
79-
"{\"value\": \"gpt-4-32k-0613\", \"label\": \"GPT-4 32K (0613)\"}," +
80-
"{\"value\": \"gpt-4-turbo\", \"label\": \"GPT-4 Turbo\"}," +
81-
"{\"value\": \"gpt-4o\", \"label\": \"GPT-4 Omni\"}," +
82-
"{\"value\": \"gpt-4o-mini\", \"label\": \"GPT-4 Omni Mini\"}," +
83-
"{\"value\": \"gpt-4.1\", \"label\": \"GPT-4.1\"}," +
84-
"{\"value\": \"gpt-4.1-mini\", \"label\": \"GPT-4.1 Mini\"}," +
85-
"{\"value\": \"gpt-4.1-nano\", \"label\": \"GPT-4.1 Nano\"}," +
86-
"{\"value\": \"gpt-3.5-turbo\", \"label\": \"GPT-3.5 Turbo\"}," +
87-
"{\"value\": \"gpt-3.5-turbo-0613\", \"label\": \"GPT-3.5 Turbo (0613)\"}," +
88-
"{\"value\": \"gpt-3.5-turbo-16k\", \"label\": \"GPT-3.5 Turbo 16K\"}," +
89-
"{\"value\": \"gpt-3.5-turbo-16k-0613\", \"label\": \"GPT-3.5 Turbo 16K (0613)\"}" +
90-
"]"
91-
)
92-
.build());
93-
94139
return keys;
95140
}
96141

backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleGroupResource.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import javax.validation.Valid;
3131
import java.net.URISyntaxException;
3232
import java.util.ArrayList;
33+
import java.util.HashSet;
3334
import java.util.List;
3435
import java.util.Optional;
3536

@@ -82,6 +83,15 @@ public ResponseEntity<UtmModuleGroup> createConfigurationGroup(@Valid @RequestBo
8283
defaultConfigurationKeys.forEach(key -> keys.add(new UtmModuleGroupConfiguration(key)));
8384
moduleGroupConfigurationService.createConfigurationKeys(keys);
8485

86+
for (UtmModuleGroupConfiguration conf : keys) {
87+
if ((Constants.CONF_TYPE_PASSWORD.equals(conf.getConfDataType())
88+
|| Constants.CONF_TYPE_FILE.equals(conf.getConfDataType()))
89+
&& conf.getConfValue() != null) {
90+
conf.setConfValue(Constants.MASKED_VALUE);
91+
}
92+
}
93+
result.setModuleGroupConfigurations(new HashSet<>(keys));
94+
8595
return ResponseEntity.ok(result);
8696
} catch (DataIntegrityViolationException e) {
8797
String msg = ctx + ": " + e.getMostSpecificCause().getMessage().replaceAll("\n", "");

frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,11 @@ <h4 class="card-title mb-0 text-primary">SOC AI</h4>
155155
<i [ngClass]="saving ? 'icon-spinner2 spinner' : 'icon-cog5'" class="mr-1"></i>
156156
Save configuration
157157
</button>
158+
158159
<app-app-module-activate-button [module]="module.SOC_AI" [type]="'integration'"
159-
[disabled]="false"
160+
[disabled]="!configReady"
160161
[serverId]="serverId"
162+
(disableModuleClicked)="disableModule()"
161163
class="ml-2">
162164
</app-app-module-activate-button>
163165
</div>

frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export class GuideSocAiComponent implements OnInit {
3939
saving = false;
4040
loading = true;
4141

42+
configReady=false
43+
4244
// Form values - what the user sees/edits
4345
formValues: {[key: string]: string} = {};
4446
customModelValue = '';
@@ -322,6 +324,7 @@ export class GuideSocAiComponent implements OnInit {
322324
};
323325
}
324326
this.loading = false;
327+
this.configReady = true;
325328
this.cdr.detectChanges();
326329
}, () => {
327330
this.loading = false;
@@ -439,6 +442,31 @@ export class GuideSocAiComponent implements OnInit {
439442

440443
save() {
441444
this.saving = true;
445+
446+
if (!this.groupId || !this.rawConfigs.length) {
447+
this.moduleGroupService.create({
448+
name: 'socai',
449+
description: 'socai',
450+
moduleId: this.integrationId
451+
}).subscribe(
452+
response => {
453+
this.groupId = response.body.id;
454+
this.rawConfigs = response.body.moduleGroupConfigurations || [];
455+
this.cdr.markForCheck()
456+
this.persistConfig();
457+
},
458+
() => {
459+
this.saving = false;
460+
this.cdr.markForCheck();
461+
this.toast.showError('Error', 'Failed to create configuration group. Please try again.');
462+
}
463+
);
464+
return;
465+
}
466+
this.persistConfig();
467+
}
468+
469+
private persistConfig() {
442470
const changes: UtmModuleGroupConfType[] = [];
443471

444472
// Set provider
@@ -494,12 +522,16 @@ export class GuideSocAiComponent implements OnInit {
494522
// Otherwise: don't touch customHeaders — keep existing value in DB
495523
}
496524

525+
this.rawConfigs=changes
526+
this.cdr.markForCheck()
527+
497528
this.moduleGroupConfService.update({
498529
keys: changes,
499530
moduleId: this.integrationId
500531
}).subscribe(
501532
() => {
502533
this.saving = false;
534+
this.configReady = true;
503535
this.cdr.markForCheck()
504536
this.toast.showSuccessBottom('SOC AI configuration saved successfully');
505537
},
@@ -610,4 +642,10 @@ export class GuideSocAiComponent implements OnInit {
610642
// Invalid JSON, start empty
611643
}
612644
}
645+
646+
647+
public disableModule(){
648+
this.groupId=null
649+
this.rawConfigs=[]
650+
}
613651
}

frontend/src/app/app-module/shared/components/app-module-activate-button/app-module-activate-button.component.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,10 @@ export class AppModuleActivateButtonComponent implements OnInit, OnDestroy {
9595
this.moduleRefreshBehavior.$moduleChange.next(true);
9696
this.toastService.showSuccessBottom('Module ' + this.moduleDetail.moduleName +
9797
' has been ' + (this.moduleDetail.moduleActive ? 'enabled' : 'disabled') + ' successfully');
98+
if (!status) {
99+
this.disableModuleClicked.emit();
100+
}
98101
});
99-
} else {
100-
if (fromOnclick && !status) {
101-
this.disableModuleClicked.emit();
102-
}
103102
}
104103
}
105104

frontend/src/app/data-management/alert-management/alert-view/alert-view.component.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ <h5 class="card-title mb-0 text-uppercase label-header">
3838
&nbsp;The system has detected new alerts, retrieving from the data engine...
3939
</span>
4040
</div>
41+
<div *ngIf="searching && !loading && !refreshingAlert"
42+
class="search-loading-indicator text-blue-800 pt-2 pr-2 pl-2">
43+
<span class="span-small-icon"><i class="icon-spinner2 spinner"></i>
44+
&nbsp;Searching...
45+
</span>
46+
</div>
4147
<div *ngIf="incomingAlert$ | async as openAlert" class="d-flex justify-content-start align-items-center pt-2 pr-2 pl-2">
4248
<ng-container *ngIf="openAlert > 0 && showRefresh">
4349
<span class="span-small-icon">

frontend/src/app/data-management/alert-management/alert-view/alert-view.component.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,7 @@ tr.no-bottom-border {
3232
.bg-children-light {
3333
background-color: #cccccc52 !important;
3434
}
35+
36+
.search-loading-indicator {
37+
pointer-events: none;
38+
}

frontend/src/app/data-management/alert-management/alert-view/alert-view.component.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import {TranslateService} from '@ngx-translate/core';
66
import {ResizeEvent} from 'angular-resizable-element';
77
import {NgxSpinnerService} from 'ngx-spinner';
88
import {LocalStorageService} from 'ngx-webstorage';
9-
import {Observable, Subject} from 'rxjs';
10-
import {filter, takeUntil, tap} from 'rxjs/operators';
9+
import {Observable, Subject, throwError, timer, Subscription} from 'rxjs';
10+
import {concatMap, filter, retryWhen, takeUntil, tap, finalize} from 'rxjs/operators';
1111
import {UtmToastService} from '../../../shared/alert/utm-toast.service';
1212
import {
1313
ElasticFilterDefaultTime
@@ -64,7 +64,8 @@ import {ElasticDataTypesEnum} from "../../../shared/enums/elastic-data-types.enu
6464
styleUrls: ['./alert-view.component.scss']
6565
})
6666
export class AlertViewComponent implements OnInit, OnDestroy {
67-
67+
private lastRequest:Subscription|null = null
68+
private lastTimeout:any = -1
6869

6970
constructor(private elasticDataService: ElasticDataService,
7071
private modalService: NgbModal,
@@ -343,10 +344,24 @@ export class AlertViewComponent implements OnInit, OnDestroy {
343344
this.getAlert('on time filter change');
344345
}
345346

347+
get searching(): boolean {
348+
return this.lastRequest!=null;
349+
}
350+
346351
getAlert(calledFrom?: string, filtersParam?: ElasticFilterType[]) {
347-
this.elasticDataService.search(this.page, this.itemsPerPage,
352+
if(this.lastTimeout!=-1){
353+
clearTimeout(this.lastTimeout)
354+
if(this.lastRequest){
355+
this.lastRequest.unsubscribe()
356+
this.lastRequest=null
357+
}
358+
}
359+
this.lastTimeout= setTimeout(()=>{
360+
this.lastRequest=this.elasticDataService.search(this.page, this.itemsPerPage,
348361
MAX_SEARCH_RESULTS, this.dataNature,
349-
sanitizeFilters(this.filters), this.sortBy, true).subscribe(
362+
sanitizeFilters(this.filters), this.sortBy, true)
363+
.pipe(finalize(()=>this.lastRequest=null))
364+
.subscribe(
350365
(res: HttpResponse<any>) => {
351366
this.totalItems = Number(res.headers.get('X-Total-Count'));
352367
this.alerts = res.body;
@@ -355,8 +370,11 @@ export class AlertViewComponent implements OnInit, OnDestroy {
355370
},
356371
(res: HttpResponse<any>) => {
357372
this.utmToastService.showError('Error', 'An error occurred while listing the alerts. Please try again later.');
373+
this.loading = false;
374+
this.refreshingAlert = false;
358375
}
359376
);
377+
},100)
360378
}
361379

362380
saveReport() {

0 commit comments

Comments
 (0)