diff --git a/.github/workflows/reusable-java.yml b/.github/workflows/reusable-java.yml index 34b49a1fd..657d4955c 100644 --- a/.github/workflows/reusable-java.yml +++ b/.github/workflows/reusable-java.yml @@ -36,6 +36,11 @@ on: type: string default: "clean install" description: "Maven goals to execute" + copy_filters_and_rules: + required: false + type: boolean + default: false + description: "Copy filters and rules folders to build context" jobs: build: @@ -99,6 +104,13 @@ jobs: username: utmstack password: ${{ secrets.GITHUB_TOKEN }} + - name: Copy filters and rules to build context + if: ${{ inputs.copy_filters_and_rules }} + run: | + cp -r filters ./${{ inputs.image_name }}/ + cp -r rules ./${{ inputs.image_name }}/ + echo "✅ Copied filters and rules to ./${{ inputs.image_name }}/" + - name: Build and Push the Image uses: docker/build-push-action@v6 with: diff --git a/.github/workflows/v11-deployment-pipeline.yml b/.github/workflows/v11-deployment-pipeline.yml index 93cb8d925..cf15b2677 100644 --- a/.github/workflows/v11-deployment-pipeline.yml +++ b/.github/workflows/v11-deployment-pipeline.yml @@ -493,6 +493,7 @@ jobs: use_tag_as_version: true maven_profile: 'prod' maven_goals: 'clean package' + copy_filters_and_rules: true build_frontend: name: Build Frontend Microservice diff --git a/agent-manager/agent/agent_imp.go b/agent-manager/agent/agent_imp.go index fafa7d97d..b3b2029aa 100644 --- a/agent-manager/agent/agent_imp.go +++ b/agent-manager/agent/agent_imp.go @@ -29,13 +29,20 @@ type AgentService struct { AgentStreamMap map[uint]AgentService_AgentStreamServer AgentStreamMutex sync.Mutex CacheAgentKey map[uint]string - CacheAgentKeyMutex sync.Mutex + CacheAgentKeyMutex sync.RWMutex CommandResultChannel map[string]chan *CommandResult CommandResultChannelM sync.Mutex DBConnection *database.DB } +func (s *AgentService) ValidateAgentKey(key string, id uint) bool { + s.CacheAgentKeyMutex.RLock() + defer s.CacheAgentKeyMutex.RUnlock() + _, valid := utils.IsKeyPairValid(key, id, s.CacheAgentKey) + return valid +} + func InitAgentService() error { var err error agentServOnce.Do(func() { @@ -338,20 +345,35 @@ func (s *AgentService) ProcessCommand(stream PanelService_ProcessCommandServer) return status.Errorf(codes.Internal, "failed to send command to agent: %v", err) } - result := <-s.CommandResultChannel[cmdID] - err = s.DBConnection.Upsert( - &models.AgentCommand{}, - "agent_id = ? AND cmd_id = ?", - map[string]interface{}{"command_status": models.Executed, "result": result.Result}, - cmd.AgentId, cmdID, - ) - if err != nil { - catcher.Error("failed to update command status", err, map[string]any{"process": "agent-manager"}) - } + select { + case result := <-s.CommandResultChannel[cmdID]: + err = s.DBConnection.Upsert( + &models.AgentCommand{}, + "agent_id = ? AND cmd_id = ?", + map[string]interface{}{"command_status": models.Executed, "result": result.Result}, + cmd.AgentId, cmdID, + ) + if err != nil { + catcher.Error("failed to update command status", err, map[string]any{"process": "agent-manager"}) + } - err = stream.Send(result) - if err != nil { - return err + err = stream.Send(result) + if err != nil { + return err + } + case <-time.After(5 * time.Minute): + s.CommandResultChannelM.Lock() + delete(s.CommandResultChannel, cmdID) + s.CommandResultChannelM.Unlock() + + _ = s.DBConnection.Upsert( + &models.AgentCommand{}, + "agent_id = ? AND cmd_id = ?", + map[string]interface{}{"command_status": models.Error, "result": "command timed out after 5 minutes"}, + cmd.AgentId, cmdID, + ) + + return status.Errorf(codes.DeadlineExceeded, "agent did not respond within 5 minutes") } s.CommandResultChannelM.Lock() diff --git a/agent-manager/agent/collector_imp.go b/agent-manager/agent/collector_imp.go index a4b9e3ee0..133c2a857 100644 --- a/agent-manager/agent/collector_imp.go +++ b/agent-manager/agent/collector_imp.go @@ -43,13 +43,20 @@ type CollectorService struct { CollectorConfigsCache map[uint][]*CollectorConfigGroup CollectorConfigsCacheM sync.Mutex CacheCollectorKey map[uint]string - CacheCollectorKeyMutex sync.Mutex + CacheCollectorKeyMutex sync.RWMutex CollectorPendigConfigChan chan *CollectorConfig CollectorTypes []enum.UTMModule DBConnection *database.DB } +func (s *CollectorService) ValidateCollectorKey(key string, id uint) bool { + s.CacheCollectorKeyMutex.RLock() + defer s.CacheCollectorKeyMutex.RUnlock() + _, valid := utils.IsKeyPairValid(key, id, s.CacheCollectorKey) + return valid +} + func InitCollectorService() { collectorServOnce.Do(func() { CollectorServ = &CollectorService{ diff --git a/agent-manager/agent/interceptor.go b/agent-manager/agent/interceptor.go index a86ccbe01..45c06db19 100644 --- a/agent-manager/agent/interceptor.go +++ b/agent-manager/agent/interceptor.go @@ -2,7 +2,7 @@ package agent import ( "context" - _ "errors" + "crypto/subtle" "fmt" "strconv" "strings" @@ -79,11 +79,11 @@ func authHeaders(md metadata.MD, fullMethod string) error { typ := strings.ToLower(connectorType[0]) switch typ { case "agent": - if _, isValid := utils.IsKeyPairValid(key, uint(id), AgentServ.CacheAgentKey); !isValid { + if !AgentServ.ValidateAgentKey(key, uint(id)) { return status.Error(codes.PermissionDenied, "invalid key") } case "collector": - if _, isValid := utils.IsKeyPairValid(key, uint(id), CollectorServ.CacheCollectorKey); !isValid { + if !CollectorServ.ValidateCollectorKey(key, uint(id)) { return status.Error(codes.PermissionDenied, "invalid key") } default: @@ -102,7 +102,7 @@ func authHeaders(md metadata.MD, fullMethod string) error { } func isInternalKeyValid(token string) bool { - return token == config.InternalKey + return subtle.ConstantTimeCompare([]byte(token), []byte(config.InternalKey)) == 1 } func isInRoute(route string, list []string) bool { diff --git a/agent-manager/agent/parser.go b/agent-manager/agent/parser.go index 3dae283d7..01ff84345 100644 --- a/agent-manager/agent/parser.go +++ b/agent-manager/agent/parser.go @@ -100,7 +100,11 @@ func replaceSecretValues(input string) string { return match } encryptedValue := matches[2] - decryptedValue, _ := utils.DecryptValue(config.EncryptionKey, encryptedValue) + decryptedValue, err := utils.DecryptValue(config.EncryptionKey, encryptedValue) + if err != nil { + catcher.Error("failed to decrypt secret value in command", err, map[string]any{"process": "agent-manager"}) + return match + } return decryptedValue }) } diff --git a/agent-manager/utils/auth.go b/agent-manager/utils/auth.go index ed552e21d..27b88d030 100644 --- a/agent-manager/utils/auth.go +++ b/agent-manager/utils/auth.go @@ -1,6 +1,7 @@ package utils import ( + "crypto/subtle" "crypto/tls" "net/http" "strings" @@ -19,10 +20,12 @@ func IsConnectionKeyValid(panelUrl string, token string) bool { } func IsKeyPairValid(key string, id uint, cache map[uint]string) (string, bool) { - for agentId, agentKey := range cache { - if key == agentKey && id == agentId { - return agentKey, true - } + agentKey, ok := cache[id] + if !ok { + return "", false + } + if subtle.ConstantTimeCompare([]byte(key), []byte(agentKey)) == 1 { + return agentKey, true } return "", false } diff --git a/agent-manager/utils/filter.go b/agent-manager/utils/filter.go index dbb7f960a..60a50651f 100644 --- a/agent-manager/utils/filter.go +++ b/agent-manager/utils/filter.go @@ -2,6 +2,7 @@ package utils import ( "fmt" + "regexp" "strings" "gorm.io/gorm" @@ -24,14 +25,14 @@ type Filter struct { Value interface{} } -func NewFilter(searchQuery string) []Filter { - defer func() { - if r := recover(); r != nil { - // Handle the panic here - fmt.Println("Panic occurred:", r) - } - }() +// validFieldName ensures the field name only contains safe characters (letters, digits, underscores) +var validFieldName = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`) +func IsValidFieldName(field string) bool { + return validFieldName.MatchString(field) +} + +func NewFilter(searchQuery string) []Filter { filters := make([]Filter, 0) if searchQuery == "" { return filters @@ -42,11 +43,27 @@ func NewFilter(searchQuery string) []Filter { } for _, v := range query { filter := strings.Split(v, "=") + if len(filter) != 2 { + continue + } filerQuery := strings.Split(filter[0], ".") + if len(filerQuery) != 2 { + continue + } + field := filerQuery[0] + if !IsValidFieldName(field) { + fmt.Printf("Rejected invalid filter field: %s\n", field) + continue + } + op := resolveOperator(filerQuery[1]) + if op == "" { + continue + } filters = append(filters, Filter{ - Field: filerQuery[0], - Op: resolveOperator(filerQuery[1]), - Value: filter[1]}) + Field: field, + Op: op, + Value: filter[1], + }) } return filters } diff --git a/agent-manager/utils/paginator.go b/agent-manager/utils/paginator.go index 52aed1dcb..1a25e8178 100644 --- a/agent-manager/utils/paginator.go +++ b/agent-manager/utils/paginator.go @@ -28,7 +28,19 @@ func NewPaginator(limit int, page int, sort string) Pagination { if len(sort) > 0 { srt := make([]string, 0) for _, s := range strings.Split(sort, "&") { - srt = append(srt, strings.Replace(s, ",", " ", 1)) + parts := strings.SplitN(s, ",", 2) + field := parts[0] + if !IsValidFieldName(field) { + continue + } + direction := "asc" + if len(parts) == 2 { + d := strings.ToLower(strings.TrimSpace(parts[1])) + if d == "desc" { + direction = "desc" + } + } + srt = append(srt, field+" "+direction) } p.Sort = strings.Join(srt, ",") } 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..9b72c2b3c --- /dev/null +++ b/agent/collector/auditd/auditd.go @@ -0,0 +1,24 @@ +// 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 + // 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 + + // 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..71b5d1d0c --- /dev/null +++ b/agent/collector/auditd/auditd_linux.go @@ -0,0 +1,210 @@ +//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 + + // 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 { + 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..0b734364f --- /dev/null +++ b/agent/collector/auditd/client.go @@ -0,0 +1,73 @@ +//go:build linux +// +build linux + +package auditd + +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) + 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 +} + +// 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/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..33ba3bf58 --- /dev/null +++ b/agent/collector/auditd/stream.go @@ -0,0 +1,74 @@ +//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" +) + +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 +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. +// 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 + } + + jsonOutput, err := formatAuditEvent(msgs) + if err != nil { + utils.Logger.ErrorF("auditd: error formatting event: %v", err) + return + } + + log := &plugins.Log{ + DataType: string(config.DataTypeLinuxAgent), + DataSource: s.hostname, + Raw: jsonOutput, + } + + // Non-blocking send: drop events if queue is full to prevent backpressure + 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. +// We filter these out by checking against a reasonable maximum. +func (s *eventStream) EventsLost(count int) { + // 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 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..049137dcb --- /dev/null +++ b/agent/dependency/auditd_linux.go @@ -0,0 +1,448 @@ +//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) +# 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 (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 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 +-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 +-w /etc/localtime -p wa -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/docs/tasks.md b/agent/docs/tasks.md deleted file mode 100644 index a748637c0..000000000 --- a/agent/docs/tasks.md +++ /dev/null @@ -1,133 +0,0 @@ -# UTMStack Agent Improvement Tasks - -This document contains a prioritized list of tasks for improving the UTMStack Agent codebase. Each task is marked with a checkbox that can be checked off when completed. - -## Architecture Improvements - -1. [ ] Implement a more modular plugin architecture to make it easier to add new collectors and data sources -2. [ ] Create a unified configuration management system that centralizes all configuration options -3. [ ] Implement a proper dependency injection system to improve testability and reduce tight coupling -4. [ ] Refactor the service management code to use a common interface across all platforms -5. [ ] Implement a more robust error handling and recovery mechanism for all collectors -6. [ ] Create a standardized logging framework with configurable log levels -7. [ ] Implement a metrics collection system to monitor agent performance -8. [ ] Design a more efficient log batching and transmission system to reduce resource usage -9. [ ] Implement a circuit breaker pattern for external service connections -10. [ ] Create a formal API versioning strategy for communication with the server - -## Code Quality Improvements - -11. [ ] Add comprehensive unit tests for all packages (current coverage appears low) -12. [ ] Implement integration tests for collector functionality -13. [ ] Add proper documentation for all exported functions, types, and interfaces -14. [ ] Standardize error handling across the codebase -15. [ ] Refactor long functions (like in main.go) into smaller, more focused functions -16. [ ] Remove commented-out code in config/const.go and other files -17. [ ] Implement consistent naming conventions across the codebase -18. [ ] Add context support for all long-running operations -19. [ ] Implement proper resource cleanup in error cases -20. [ ] Add validation for all user inputs and configuration values - -## Security Improvements - -21. [ ] Implement secure storage for sensitive configuration (beyond basic encryption) -22. [ ] Add TLS certificate validation by default (currently optional) -23. [ ] Implement proper authentication for all API endpoints -24. [ ] Add integrity verification for downloaded dependencies -25. [ ] Implement secure logging practices (masking sensitive data) -26. [ ] Add rate limiting for authentication attempts -27. [ ] Implement proper permission checking for file operations -28. [ ] Add security scanning in the CI/CD pipeline -29. [ ] Implement secure coding practices training for developers -30. [ ] Create a security incident response plan - -## Performance Improvements - -31. [ ] Profile the application to identify performance bottlenecks -32. [ ] Optimize log collection and processing for high-volume environments -33. [ ] Implement more efficient data structures for log storage -34. [ ] Add caching for frequently accessed configuration -35. [ ] Optimize file operations to reduce disk I/O -36. [ ] Implement connection pooling for network operations -37. [ ] Reduce memory usage in log processing pipelines -38. [ ] Optimize CPU usage during idle periods -39. [ ] Implement more efficient serialization/deserialization -40. [ ] Add performance benchmarks to CI/CD pipeline - -## Platform Support Improvements - -41. [ ] Standardize platform-specific code to reduce duplication -42. [ ] Improve macOS arm64 support (recently added) -43. [ ] Add support for additional Linux distributions -44. [ ] Improve Windows arm64 support -45. [ ] Create a unified build system for all platforms -46. [ ] Implement automated testing on all supported platforms -47. [ ] Add containerization support for easier deployment -48. [ ] Create platform-specific installation documentation -49. [ ] Implement feature parity across all supported platforms -50. [ ] Add support for cloud-native environments - -## User Experience Improvements - -51. [ ] Improve installation process with better user feedback -52. [ ] Create a web-based configuration interface -53. [ ] Implement a status dashboard for monitoring agent health -54. [ ] Add better error messages for common failure scenarios -55. [ ] Improve logging with more context and clarity -56. [ ] Create user-friendly documentation with examples -57. [ ] Implement a troubleshooting guide for common issues -58. [ ] Add a command-line interface for common administrative tasks -59. [ ] Implement a self-diagnostic tool for agent issues -60. [ ] Create a user feedback mechanism - -## Operational Improvements - -61. [ ] Implement a more robust update mechanism with rollback capability -62. [ ] Add health checks for all components -63. [ ] Implement proper service lifecycle management -64. [ ] Create automated deployment scripts for common environments -65. [ ] Implement configuration validation before applying changes -66. [ ] Add support for configuration templates for common scenarios -67. [ ] Implement a backup and restore mechanism for agent configuration -68. [ ] Create operational runbooks for common maintenance tasks -69. [ ] Implement proper service dependencies management -70. [ ] Add support for centralized configuration management - -## Technical Debt Reduction - -71. [ ] Refactor the collector implementation to reduce code duplication -72. [ ] Update deprecated dependencies and APIs -73. [ ] Remove unused code and dependencies -74. [ ] Consolidate duplicate functionality across packages -75. [ ] Implement consistent error handling patterns -76. [ ] Refactor configuration handling to use a single approach -77. [ ] Improve code organization with better package structure -78. [ ] Standardize file naming conventions -79. [ ] Implement a code style guide and enforce with linters -80. [ ] Refactor platform-specific code to improve maintainability - -## Documentation Improvements - -81. [ ] Create comprehensive API documentation -82. [ ] Document the architecture and design decisions -83. [ ] Create developer onboarding documentation -84. [ ] Document the build and release process -85. [ ] Create user guides for all features -86. [ ] Document troubleshooting procedures -87. [ ] Create diagrams for system architecture and data flow -88. [ ] Document security considerations and best practices -89. [ ] Create change management documentation -90. [ ] Document performance tuning recommendations - -## Future Enhancements - -91. [ ] Implement support for additional data sources and integrations -92. [ ] Add machine learning capabilities for anomaly detection -93. [ ] Implement real-time alerting based on log patterns -94. [ ] Create a plugin marketplace for community contributions -95. [ ] Implement advanced data correlation features -96. [ ] Add support for custom log parsing rules -97. [ ] Implement advanced visualization capabilities -98. [ ] Add support for compliance reporting -99. [ ] Implement predictive analytics for security events -100. [ ] Create an ecosystem of complementary tools and integrations \ No newline at end of file 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/logs/utmstack_agent.log b/agent/logs/utmstack_agent.log deleted file mode 100644 index 602489253..000000000 --- a/agent/logs/utmstack_agent.log +++ /dev/null @@ -1 +0,0 @@ -2025-04-16T13:37:14.854518Z ERROR f18ed04e-83e4-49d7-b82b-b96385b8b0bd /Users/osmany/Projects/UTMStack/agent/serv/service.go 36 error getting config: error reading config file: open /Users/osmany/Projects/UTMStack/agent/config.yml: no such file or directory diff --git a/agent/templates/filebeat.yml b/agent/templates/filebeat.yml deleted file mode 100644 index 376c20867..000000000 --- a/agent/templates/filebeat.yml +++ /dev/null @@ -1,33 +0,0 @@ -filebeat.inputs: - -- type: log - enabled: false - paths: - - /var/log/*.log - -# ============================== Filebeat modules ============================== -filebeat.config.modules: - path: ${path.config}/modules.d/*.yml - reload.enabled: false - -# ======================= Elasticsearch template setting ======================= -setup.template.settings: - index.number_of_shards: 1 - -# =================================== Kibana =================================== -setup.kibana: - -# ------------------------------ File Output ------------------------------- -output.file: - path: '{{.LogsPath}}' - filename: '{{.LogFileName}}' - rotate_every_kb: 10000 - number_of_files: 7 - -# ================================= Processors ================================= -processors: - - add_host_metadata: - when.not.contains.tags: forwarded - - add_cloud_metadata: ~ - - add_docker_metadata: ~ - - add_kubernetes_metadata: ~ diff --git a/agent/templates/winlogbeat.yml b/agent/templates/winlogbeat.yml deleted file mode 100644 index 2c4cb3901..000000000 --- a/agent/templates/winlogbeat.yml +++ /dev/null @@ -1,29 +0,0 @@ -winlogbeat.event_logs: - - name: Application - ignore_older: 72h - - name: System - - name: Security - - name: Microsoft-Windows-Sysmon/Operational - - name: Windows PowerShell - event_id: 400, 403, 600, 800 - - name: Microsoft-Windows-PowerShell/Operational - event_id: 4103, 4104, 4105, 4106 - - name: ForwardedEvents - tags: [forwarded] - -#==================== Elasticsearch template setting ========================== -setup.template.settings: - index.number_of_shards: 3 - -# ------------------------------ File Output ------------------------------- -output.file: - path: '{{.LogsPath}}' - filename: '{{.LogFileName}}' - rotate_every_kb: 10000 - number_of_files: 7 - -#================================ Processors ===================================== -processors: - - add_host_metadata: - when.not.contains.tags: forwarded - - add_cloud_metadata: ~ \ No newline at end of file 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= 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" } diff --git a/backend/Dockerfile b/backend/Dockerfile index b1e8eb732..29b7052da 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,6 +1,8 @@ FROM eclipse-temurin:17 ADD target/utmstack.war ./ +COPY filters /utmstack/filters +COPY rules /utmstack/rules HEALTHCHECK --start-period=60s --interval=60s --timeout=60s --retries=3 \ CMD curl -f http://localhost:8080/api/healthcheck || exit 1 diff --git a/backend/pom.xml b/backend/pom.xml index 022fdd657..80dde92ed 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -8,7 +8,7 @@ com.atlasinside utmstack ${revision} - + war UTMStack-API @@ -267,9 +267,10 @@ 1.8 - com.lowagie - itext - 2.1.7 + com.itextpdf + itext7-core + 7.1.7 + pom org.xhtmlrenderer @@ -284,7 +285,7 @@ com.utmstack opensearch-connector - 1.0.4 + 1.0.5 jakarta.json @@ -348,7 +349,7 @@ org.apache.tika tika-core - 2.9.1 + 3.3.0 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/ApplicationStartProcessor.java b/backend/src/main/java/com/park/utmstack/ApplicationStartProcessor.java index 91505f553..5b88a450a 100644 --- a/backend/src/main/java/com/park/utmstack/ApplicationStartProcessor.java +++ b/backend/src/main/java/com/park/utmstack/ApplicationStartProcessor.java @@ -10,6 +10,7 @@ import java.sql.SQLException; import java.util.Objects; + public class ApplicationStartProcessor implements EnvironmentPostProcessor { private static final String CLASSNAME = "ApplicationStartProcessor"; private Connection con; @@ -36,8 +37,6 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp // Checking elasticsearch connection elasticsearchConnectionCheck(); - ConsoleColors.magentaBold(); - System.out.println("------------------------------------------------"); ConsoleColors.reset(); } catch (Exception e) { if (!Objects.isNull(con)) { diff --git a/backend/src/main/java/com/park/utmstack/UtmstackApp.java b/backend/src/main/java/com/park/utmstack/UtmstackApp.java index cf98c4be0..6635bc1c5 100644 --- a/backend/src/main/java/com/park/utmstack/UtmstackApp.java +++ b/backend/src/main/java/com/park/utmstack/UtmstackApp.java @@ -82,6 +82,8 @@ private static void logApplicationStartup(Environment env) { } catch (UnknownHostException e) { log.warn("The host name could not be determined, using `localhost` as fallback"); } + + log.info( "\n----------------------------------------------------------\n\t" + "Application '{}' is running! Access URLs:\n\t" + "Local: \t\t{}://localhost:{}{}\n\t" + "External: \t{}://{}:{}{}\n\t" + "Profile(s): \t{}\n----------------------------------------------------------", env.getProperty("spring.application.name"), protocol, serverPort, contextPath, protocol, hostAddress, serverPort, diff --git a/backend/src/main/java/com/park/utmstack/checks/ElasticsearchConnectionCheck.java b/backend/src/main/java/com/park/utmstack/checks/ElasticsearchConnectionCheck.java index 9d6ad10cc..abab40444 100644 --- a/backend/src/main/java/com/park/utmstack/checks/ElasticsearchConnectionCheck.java +++ b/backend/src/main/java/com/park/utmstack/checks/ElasticsearchConnectionCheck.java @@ -1,10 +1,15 @@ package com.park.utmstack.checks; import com.park.utmstack.config.Constants; +import okhttp3.Credentials; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; import java.util.Objects; public class ElasticsearchConnectionCheck { @@ -53,17 +58,45 @@ public void connectionCheck(int retries) { private void pingElasticsearch() { try { - final String ELASTIC_URL = String.format("http://%1$s:%2$s", + final String ELASTIC_URL = String.format("https://%1$s:%2$s", System.getenv(Constants.ENV_ELASTICSEARCH_HOST), System.getenv(Constants.ENV_ELASTICSEARCH_PORT)); - OkHttpClient client = new OkHttpClient().newBuilder().build(); - Request rq = new Request.Builder().url(ELASTIC_URL).build(); + String user = System.getenv(Constants.ENV_ELASTICSEARCH_USER); + String password = System.getenv(Constants.ENV_ELASTICSEARCH_PASSWORD); + + OkHttpClient client = createTrustAllClient(); + Request rq = new Request.Builder() + .url(ELASTIC_URL) + .header("Authorization", Credentials.basic(user, password)) + .build(); Response rs = client.newCall(rq).execute(); Objects.requireNonNull(rs.body()).close(); if (!rs.isSuccessful()) - throw new RuntimeException(); + throw new RuntimeException("HTTP " + rs.code()); } catch (Exception e) { throw new RuntimeException(e.getLocalizedMessage()); } } + + private OkHttpClient createTrustAllClient() { + try { + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } + public void checkClientTrusted(X509Certificate[] certs, String authType) {} + public void checkServerTrusted(X509Certificate[] certs, String authType) {} + } + }; + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + + return new OkHttpClient.Builder() + .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0]) + .hostnameVerifier((hostname, session) -> true) + .build(); + } catch (Exception e) { + throw new RuntimeException("Failed to create SSL client: " + e.getMessage()); + } + } } 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..2b81857b8 100644 --- a/backend/src/main/java/com/park/utmstack/config/Constants.java +++ b/backend/src/main/java/com/park/utmstack/config/Constants.java @@ -93,6 +93,8 @@ public final class Constants { */ public static final String ENV_ELASTICSEARCH_HOST = "ELASTICSEARCH_HOST"; public static final String ENV_ELASTICSEARCH_PORT = "ELASTICSEARCH_PORT"; + public static final String ENV_ELASTICSEARCH_USER = "ELASTICSEARCH_USER"; + public static final String ENV_ELASTICSEARCH_PASSWORD = "ELASTICSEARCH_PASSWORD"; public static final String ENV_DB_HOST = "DB_HOST"; public static final String ENV_DB_PORT = "DB_PORT"; public static final String ENV_DB_NAME = "DB_NAME"; @@ -159,12 +161,16 @@ public final class Constants { public static final String CONF_TYPE_PASSWORD = "password"; public static final String CONF_TYPE_FILE = "file"; + public static final String MASKED_VALUE = "*****"; public static final String API_KEY_HEADER = "Utm-Api-Key"; 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 = "/updates/version.json"; + + public static final String APP_FILTER_DEFINITIONS = "/utmstack/filters"; + public static final String APP_RULE_DEFINITIONS = "/utmstack/rules"; public static final String ADMIN_EMAIL = "admin@localhost"; diff --git a/backend/src/main/java/com/park/utmstack/domain/UtmServerModule.java b/backend/src/main/java/com/park/utmstack/domain/UtmServerModule.java index 670e497be..4c7c367b9 100644 --- a/backend/src/main/java/com/park/utmstack/domain/UtmServerModule.java +++ b/backend/src/main/java/com/park/utmstack/domain/UtmServerModule.java @@ -1,15 +1,18 @@ package com.park.utmstack.domain; +import com.park.utmstack.service.dto.auditable.AuditableDTO; + import javax.persistence.*; import java.io.Serializable; +import java.util.Map; /** * A UtmServerModule. */ @Entity @Table(name = "utm_server_module") -public class UtmServerModule implements Serializable { +public class UtmServerModule implements Serializable, AuditableDTO { private static final long serialVersionUID = 1L; @@ -100,4 +103,12 @@ public UtmServer getServer() { public void setServer(UtmServer server) { this.server = server; } + + @Override + public Map toAuditMap() { + return Map.of( + "moduleName", moduleName != null ? moduleName : "", + "prettyName", prettyName != null ? prettyName : "" + ); + } } diff --git a/backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java b/backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java index 96b7f303a..3cc3391a6 100644 --- a/backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java +++ b/backend/src/main/java/com/park/utmstack/domain/alert_response_rule/UtmAlertResponseRule.java @@ -64,6 +64,10 @@ public class UtmAlertResponseRule implements Serializable { @Column(name = "last_modified_date") private Instant lastModifiedDate; + @Size(max = 20) + @Column(name = "rule_shell", length = 20) + private String ruleShell; + @Column(name = "system_owner", nullable = false) private Boolean systemOwner; @@ -92,6 +96,7 @@ public UtmAlertResponseRule(UtmAlertResponseRuleDTO dto) { this.ruleActive = dto.getActive(); this.agentPlatform = dto.getAgentPlatform(); this.defaultAgent = dto.getDefaultAgent(); + this.ruleShell = dto.getShell(); this.systemOwner = dto.getSystemOwner(); if (!CollectionUtils.isEmpty(dto.getExcludedAgents())) this.excludedAgents = String.join(",", dto.getExcludedAgents()); diff --git a/backend/src/main/java/com/park/utmstack/domain/application_events/enums/ApplicationEventType.java b/backend/src/main/java/com/park/utmstack/domain/application_events/enums/ApplicationEventType.java index 4b4ee6484..a0e2d0f04 100644 --- a/backend/src/main/java/com/park/utmstack/domain/application_events/enums/ApplicationEventType.java +++ b/backend/src/main/java/com/park/utmstack/domain/application_events/enums/ApplicationEventType.java @@ -50,5 +50,53 @@ public enum ApplicationEventType { COLLECTOR_DELETE_SUCCESS, RESET_USER_PASSWORD_ATTEMPT, RESET_USER_PASSWORD_SUCCESS, + USER_CREATION_ATTEMPT, + USER_CREATION_SUCCESS, + USER_UPDATE_ATTEMPT, + USER_UPDATE_SUCCESS, + USER_DELETE_ATTEMPT, + USER_DELETE_SUCCESS, + PASSWORD_CHANGE_ATTEMPT, + PASSWORD_CHANGE_SUCCESS, + IDP_CONFIG_CREATE_ATTEMPT, + IDP_CONFIG_CREATE_SUCCESS, + IDP_CONFIG_UPDATE_ATTEMPT, + IDP_CONFIG_UPDATE_SUCCESS, + IDP_CONFIG_DELETE_ATTEMPT, + IDP_CONFIG_DELETE_SUCCESS, + TFA_ENABLE_ATTEMPT, + TFA_ENABLE_SUCCESS, + TFA_DISABLE_ATTEMPT, + TFA_DISABLE_SUCCESS, + API_KEY_CREATE_ATTEMPT, + API_KEY_CREATE_SUCCESS, + API_KEY_DELETE_ATTEMPT, + API_KEY_DELETE_SUCCESS, + CORRELATION_RULE_CREATE_ATTEMPT, + CORRELATION_RULE_CREATE_SUCCESS, + CORRELATION_RULE_UPDATE_ATTEMPT, + CORRELATION_RULE_UPDATE_SUCCESS, + CORRELATION_RULE_DELETE_ATTEMPT, + CORRELATION_RULE_DELETE_SUCCESS, + LOGSTASH_FILTER_CREATE_ATTEMPT, + LOGSTASH_FILTER_CREATE_SUCCESS, + LOGSTASH_FILTER_UPDATE_ATTEMPT, + LOGSTASH_FILTER_UPDATE_SUCCESS, + LOGSTASH_FILTER_DELETE_ATTEMPT, + LOGSTASH_FILTER_DELETE_SUCCESS, + SERVER_MODULE_CREATE_ATTEMPT, + SERVER_MODULE_CREATE_SUCCESS, + SERVER_MODULE_UPDATE_ATTEMPT, + SERVER_MODULE_UPDATE_SUCCESS, + SERVER_MODULE_DELETE_ATTEMPT, + SERVER_MODULE_DELETE_SUCCESS, + COMPLIANCE_SCHEDULE_CREATE_ATTEMPT, + COMPLIANCE_SCHEDULE_CREATE_SUCCESS, + COMPLIANCE_SCHEDULE_DELETE_ATTEMPT, + COMPLIANCE_SCHEDULE_DELETE_SUCCESS, + COMPLIANCE_STANDARD_CREATE_ATTEMPT, + COMPLIANCE_STANDARD_CREATE_SUCCESS, + REPORT_IMPORT_ATTEMPT, + REPORT_IMPORT_SUCCESS, UNDEFINED } diff --git a/backend/src/main/java/com/park/utmstack/domain/application_modules/UtmModule.java b/backend/src/main/java/com/park/utmstack/domain/application_modules/UtmModule.java index 36a7e8068..627ad4b4c 100644 --- a/backend/src/main/java/com/park/utmstack/domain/application_modules/UtmModule.java +++ b/backend/src/main/java/com/park/utmstack/domain/application_modules/UtmModule.java @@ -32,7 +32,7 @@ public class UtmModule implements Serializable { @Column(name = "pretty_name") private String prettyName; - @Enumerated(EnumType.STRING) + @Convert(converter = com.park.utmstack.domain.application_modules.enums.ModuleNameConverter.class) @Column(name = "module_name") private ModuleName moduleName; @@ -62,9 +62,11 @@ public class UtmModule implements Serializable { @JoinColumn(name = "server_id", insertable = false, updatable = false) private UtmServer server; + @JsonIgnore @OneToMany(mappedBy = "module", fetch = FetchType.LAZY) private Set moduleGroups = new HashSet<>(); + @JsonIgnore @OneToMany(mappedBy = "module", fetch = FetchType.LAZY) private Set filters; diff --git a/backend/src/main/java/com/park/utmstack/domain/application_modules/enums/ModuleName.java b/backend/src/main/java/com/park/utmstack/domain/application_modules/enums/ModuleName.java index 68bd3001b..7fe135106 100644 --- a/backend/src/main/java/com/park/utmstack/domain/application_modules/enums/ModuleName.java +++ b/backend/src/main/java/com/park/utmstack/domain/application_modules/enums/ModuleName.java @@ -66,5 +66,7 @@ public enum ModuleName { ORACLE, SURICATA, UTMSTACK, - CROWDSTRIKE + CROWDSTRIKE, + SYSLOG_GENERIC, + WINDOWS_EVENTS } diff --git a/backend/src/main/java/com/park/utmstack/domain/application_modules/enums/ModuleNameConverter.java b/backend/src/main/java/com/park/utmstack/domain/application_modules/enums/ModuleNameConverter.java new file mode 100644 index 000000000..9661939b3 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/domain/application_modules/enums/ModuleNameConverter.java @@ -0,0 +1,29 @@ +package com.park.utmstack.domain.application_modules.enums; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Converter(autoApply = true) +public class ModuleNameConverter implements AttributeConverter { + private static final Logger log = LoggerFactory.getLogger(ModuleNameConverter.class); + + @Override + public String convertToDatabaseColumn(ModuleName attribute) { + return attribute == null ? null : attribute.name(); + } + + @Override + public ModuleName convertToEntityAttribute(String dbData) { + if (dbData == null) { + return null; + } + try { + return ModuleName.valueOf(dbData); + } catch (IllegalArgumentException e) { + log.warn("Unknown ModuleName in database: '{}'. Mapping to null to prevent crash. ---", dbData); + return null; + } + } +} diff --git a/backend/src/main/java/com/park/utmstack/domain/application_modules/factory/impl/ModuleSocAi.java b/backend/src/main/java/com/park/utmstack/domain/application_modules/factory/impl/ModuleSocAi.java index 3fde5c21d..79f2b42b1 100644 --- a/backend/src/main/java/com/park/utmstack/domain/application_modules/factory/impl/ModuleSocAi.java +++ b/backend/src/main/java/com/park/utmstack/domain/application_modules/factory/impl/ModuleSocAi.java @@ -45,16 +45,6 @@ public List checkRequirements(Long serverId) throws Exception public List getConfigurationKeys(Long groupId) throws Exception { List keys = new ArrayList<>(); - // soc_ai_key - keys.add(ModuleConfigurationKey.builder() - .withGroupId(groupId) - .withConfKey("utmstack.socai.key") - .withConfName("Key") - .withConfDescription("OpenAI Connection key") - .withConfDataType("password") - .withConfRequired(true) - .build()); - keys.add(ModuleConfigurationKey.builder() .withGroupId(groupId) .withConfKey("utmstack.socai.incidentCreation") @@ -127,20 +117,13 @@ public boolean validateConfiguration(UtmModule module, List !"utmstack.socai.provider".equals(c.getConfKey())) .toList(); - List filteredConfigs = providerConfig != null && "custom".equals(providerConfig.getConfValue()) - ? filterCustomConfigs(configs) - : filterStandardConfigs(configs); + List filteredConfigs = filterStandardConfigs(configs); filteredConfigs.add(providerConfig); return utmStackConfigValidator.validate(module, configuration, filteredConfigs); } - private List filterCustomConfigs(List configs) { - return configs.stream() - .filter(config -> !config.getConfKey().equals("utmstack.socai.model")) - .collect(Collectors.toList()); - } private List filterStandardConfigs(List configs) { return configs.stream() diff --git a/backend/src/main/java/com/park/utmstack/domain/application_modules/validators/UtmModuleConfigValidator.java b/backend/src/main/java/com/park/utmstack/domain/application_modules/validators/UtmModuleConfigValidator.java index 7758e16ff..09fd01758 100644 --- a/backend/src/main/java/com/park/utmstack/domain/application_modules/validators/UtmModuleConfigValidator.java +++ b/backend/src/main/java/com/park/utmstack/domain/application_modules/validators/UtmModuleConfigValidator.java @@ -35,12 +35,15 @@ public boolean validate(UtmModule module, List keys List configDTOs = dbConfigs.stream() .map(dbConf -> { UtmModuleGroupConfiguration override = findInKeys(keys, dbConf.getConfKey()); - UtmModuleGroupConfiguration source = override != null ? override : dbConf; - - return new UtmModuleGroupConfDTO( - source.getConfKey(), - override != null ? source.getConfValue() : decryptIfNeeded(source.getConfDataType(), source.getConfValue()) - ); + String value; + if (override != null && !Constants.MASKED_VALUE.equals(override.getConfValue())) { + // User provided a new value — use it as plaintext + value = override.getConfValue(); + } else { + // No override or masked — decrypt from DB + value = decryptIfNeeded(dbConf.getConfDataType(), dbConf.getConfValue()); + } + return new UtmModuleGroupConfDTO(dbConf.getConfKey(), value); }) .toList(); 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..68b167fb5 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceControlConfig.java @@ -0,0 +1,69 @@ +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 javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.ArrayList; +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; + + @Column(name = "standard_section_id", + nullable = false + ) + private Long standardSectionId; + + @ManyToOne + @JoinColumn(name = "standard_section_id", + referencedColumnName = "id", + insertable = false, + updatable = false + ) + private UtmComplianceStandardSection section; + + @Column(name = "control_name", + nullable = false + ) + @Size(min = 10, max = 200) + private String controlName; + + @Column(name = "control_solution", + length = 2000 + ) + private String controlSolution; + + @Column(name = "control_remediation", + length = 2000 + ) + private String controlRemediation; + + @Enumerated(EnumType.STRING) + @Column(name = "control_strategy", + nullable = false + ) + private ComplianceStrategy controlStrategy; + + @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 new file mode 100644 index 000000000..73435f9a2 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceQueryConfig.java @@ -0,0 +1,76 @@ +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 javax.validation.constraints.Size; +import java.io.Serializable; + +@Getter +@Setter +@Entity +@Table(name = "utm_compliance_query_config") +public class UtmComplianceQueryConfig 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_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", + nullable = false + ) + private EvaluationRule evaluationRule; + + private Integer ruleValue; + + @Column(name = "index_pattern_id", + nullable = false + ) + private Long indexPatternId; + + @ManyToOne + @JoinColumn(name = "index_pattern_id", + insertable = false, + updatable = false + ) + private UtmIndexPattern indexPattern; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn( + name = "control_config_id", + nullable = false + ) + private UtmComplianceControlConfig controlConfig; +} diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceReportConfig.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceReportConfig.java index 68a461af7..f90fcd0d7 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceReportConfig.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceReportConfig.java @@ -11,6 +11,7 @@ import com.park.utmstack.domain.compliance.enums.ComplianceType; import com.park.utmstack.domain.compliance.types.RequestParamFilter; import com.park.utmstack.domain.shared_types.DataColumn; +import com.park.utmstack.service.dto.auditable.AuditableDTO; import com.park.utmstack.util.UtilSerializer; import com.park.utmstack.util.exceptions.UtmSerializationException; import org.hibernate.annotations.GenericGenerator; @@ -20,13 +21,14 @@ import javax.persistence.*; import java.io.Serializable; import java.util.List; +import java.util.Map; /** * A ComplianceTemplate. */ @Entity @Table(name = "utm_compliance_report_config") -public class UtmComplianceReportConfig implements Serializable { +public class UtmComplianceReportConfig implements Serializable, AuditableDTO { private static final long serialVersionUID = 1L; @@ -351,4 +353,12 @@ public ComplianceStatus getConfigReportStatus() { public void setConfigReportStatus(ComplianceStatus complianceStatus) { this.configReportStatus = complianceStatus; } + + @Override + public Map toAuditMap() { + return Map.of( + "configReportName", configReportName != null ? configReportName : "", + "configSolution", configSolution != null ? configSolution : "" + ); + } } diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceReportSchedule.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceReportSchedule.java index 1cf98403f..08f35d110 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceReportSchedule.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceReportSchedule.java @@ -7,9 +7,12 @@ import com.park.utmstack.util.UtilSerializer; import com.park.utmstack.util.exceptions.UtmSerializationException; +import com.park.utmstack.service.dto.auditable.AuditableDTO; + import java.io.Serializable; import java.time.Instant; import java.util.List; +import java.util.Map; import javax.persistence.*; import javax.validation.constraints.Size; @@ -18,7 +21,7 @@ */ @Entity @Table(name = "utm_compliance_report_schedule") -public class UtmComplianceReportSchedule implements Serializable { +public class UtmComplianceReportSchedule implements Serializable, AuditableDTO { private static final long serialVersionUID = 1L; @@ -124,6 +127,14 @@ public void setUrlWithParams(String urlWithParams) { this.urlWithParams = urlWithParams; } + @Override + public Map toAuditMap() { + return Map.of( + "complianceId", complianceId != null ? complianceId : "", + "scheduleString", scheduleString != null ? scheduleString : "" + ); + } + @Override public boolean equals(Object o) { if (o instanceof UtmComplianceReportSchedule) { diff --git a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceStandard.java b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceStandard.java index 5b58e242c..df8c56bf4 100644 --- a/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceStandard.java +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/UtmComplianceStandard.java @@ -1,17 +1,19 @@ package com.park.utmstack.domain.compliance; +import com.park.utmstack.service.dto.auditable.AuditableDTO; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.io.Serializable; +import java.util.Map; @Setter @Getter @Entity @Table(name = "utm_compliance_standard") -public class UtmComplianceStandard implements Serializable { +public class UtmComplianceStandard implements Serializable, AuditableDTO { private static final long serialVersionUID = 1L; @Id @@ -28,4 +30,11 @@ public class UtmComplianceStandard implements Serializable { @Column(name = "system_owner") private Boolean systemOwner; + @Override + public Map toAuditMap() { + return Map.of( + "standardName", standardName != null ? standardName : "" + ); + } + } 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..f76c56de6 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/domain/compliance/enums/ComplianceStrategy.java @@ -0,0 +1,6 @@ +package com.park.utmstack.domain.compliance.enums; + +public enum ComplianceStrategy { + ALL, + 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 new file mode 100644 index 000000000..3019c82ea --- /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, // 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/domain/correlation/config/UtmDataTypes.java b/backend/src/main/java/com/park/utmstack/domain/correlation/config/UtmDataTypes.java index d75d493c8..eadba77a0 100644 --- a/backend/src/main/java/com/park/utmstack/domain/correlation/config/UtmDataTypes.java +++ b/backend/src/main/java/com/park/utmstack/domain/correlation/config/UtmDataTypes.java @@ -46,6 +46,10 @@ public class UtmDataTypes implements Serializable { @Column(name = "system_owner", nullable = false) private Boolean systemOwner; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "module_id") + private com.park.utmstack.domain.application_modules.UtmModule module; + @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE @@ -121,4 +125,12 @@ public Boolean getSystemOwner() { public void setSystemOwner(Boolean systemOwner) { this.systemOwner = systemOwner; } + + public com.park.utmstack.domain.application_modules.UtmModule getModule() { + return module; + } + + public void setModule(com.park.utmstack.domain.application_modules.UtmModule module) { + this.module = module; + } } diff --git a/backend/src/main/java/com/park/utmstack/domain/logstash_filter/UtmLogstashFilter.java b/backend/src/main/java/com/park/utmstack/domain/logstash_filter/UtmLogstashFilter.java index 813f00894..be1bf87ed 100644 --- a/backend/src/main/java/com/park/utmstack/domain/logstash_filter/UtmLogstashFilter.java +++ b/backend/src/main/java/com/park/utmstack/domain/logstash_filter/UtmLogstashFilter.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.park.utmstack.domain.application_modules.UtmModule; import com.park.utmstack.domain.correlation.config.UtmDataTypes; +import com.park.utmstack.service.dto.auditable.AuditableDTO; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; @@ -11,13 +12,14 @@ import javax.validation.constraints.NotNull; import java.io.Serializable; import java.time.Instant; +import java.util.Map; /** * A UtmLogstashFilter. */ @Entity @Table(name = "utm_logstash_filter") -public class UtmLogstashFilter implements Serializable { +public class UtmLogstashFilter implements Serializable, AuditableDTO { private static final long serialVersionUID = 1L; @@ -65,8 +67,9 @@ public class UtmLogstashFilter implements Serializable { private Instant updatedAt; @JsonIgnore - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "module_name", referencedColumnName = "module_name",insertable = false, updatable = false) + @ManyToOne(fetch = FetchType.LAZY, optional = true) + @org.hibernate.annotations.NotFound(action = org.hibernate.annotations.NotFoundAction.IGNORE) + @JoinColumn(name = "module_name", referencedColumnName = "module_name", insertable = false, updatable = false, nullable = true) private UtmModule module; public UtmLogstashFilter() { @@ -181,4 +184,12 @@ public Instant getUpdatedAt() { public void setUpdatedAt(Instant updatedAt) { this.updatedAt = updatedAt; } + + @Override + public Map toAuditMap() { + return Map.of( + "filterName", filterName != null ? filterName : "", + "moduleName", moduleName != null ? moduleName : "" + ); + } } 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..5d9d1b9a0 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceControlConfigRepository.java @@ -0,0 +1,47 @@ +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.domain.Specification; +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, JpaSpecificationExecutor { + @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); + + @Query(""" + SELECT DISTINCT c + FROM UtmComplianceControlConfig c + LEFT JOIN FETCH c.section s + JOIN FETCH s.standard st + LEFT JOIN FETCH c.queriesConfigs q + WHERE c.id IN :ids + """) + List findWithQueriesByIdIn( + @Param("ids") List ids); + + 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/repository/compliance/UtmComplianceQueryConfigRepository.java b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java new file mode 100644 index 000000000..362d4a2a1 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/repository/compliance/UtmComplianceQueryConfigRepository.java @@ -0,0 +1,10 @@ +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; + +@Repository +public interface UtmComplianceQueryConfigRepository extends JpaRepository { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/repository/correlation/rules/UtmCorrelationRulesRepository.java b/backend/src/main/java/com/park/utmstack/repository/correlation/rules/UtmCorrelationRulesRepository.java index f0f0bc36c..4357c4c83 100644 --- a/backend/src/main/java/com/park/utmstack/repository/correlation/rules/UtmCorrelationRulesRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/correlation/rules/UtmCorrelationRulesRepository.java @@ -54,5 +54,9 @@ Page searchByFilters(@Param("ruleName") String ruleName, @Param("ruleSearch") String ruleSearch, Pageable pageable); + Optional findOneByRuleName(String ruleName); + + List findAllBySystemOwnerIsTrue(); + Optional findFirstBySystemOwnerIsTrueOrderByIdDesc(); } diff --git a/backend/src/main/java/com/park/utmstack/repository/logstash_filter/UtmLogstashFilterRepository.java b/backend/src/main/java/com/park/utmstack/repository/logstash_filter/UtmLogstashFilterRepository.java index 4826bf418..0e315dc23 100644 --- a/backend/src/main/java/com/park/utmstack/repository/logstash_filter/UtmLogstashFilterRepository.java +++ b/backend/src/main/java/com/park/utmstack/repository/logstash_filter/UtmLogstashFilterRepository.java @@ -8,6 +8,7 @@ import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; /** @@ -19,9 +20,19 @@ public interface UtmLogstashFilterRepository extends JpaRepository ids); + List findAllBySystemOwnerIsTrue(); + @Query(nativeQuery = true, value = "select utm_logstash_filter.* from utm_logstash_filter where :nameShort = any(string_to_array(utm_logstash_filter.module_name, ','))") List findAllByModuleName(@Param("nameShort") String nameShort); + Optional findOneByModuleName(String moduleName); + + Optional findFirstByDatatypeDataType(String dataType); + + Optional findFirstBySystemOwnerIsTrueOrderByIdDesc(); + + Optional findFirstByLogstashFilterAndSystemOwnerIsTrue(String logstashFilter); + @Query("select ulf from UtmLogstashFilter ulf where ulf.id in (:filterList) and ulf.systemOwner=false") List findAllByListOfId(@Param("filterList") List filterList); diff --git a/backend/src/main/java/com/park/utmstack/service/DefinitionSyncService.java b/backend/src/main/java/com/park/utmstack/service/DefinitionSyncService.java new file mode 100644 index 000000000..1a7a72456 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/DefinitionSyncService.java @@ -0,0 +1,293 @@ +package com.park.utmstack.service; + +import com.park.utmstack.config.Constants; +import com.park.utmstack.domain.correlation.config.UtmDataTypes; +import com.park.utmstack.domain.correlation.rules.UtmCorrelationRules; +import com.park.utmstack.domain.logstash_filter.UtmLogstashFilter; +import com.park.utmstack.repository.correlation.config.UtmDataTypesRepository; +import com.park.utmstack.repository.correlation.rules.UtmCorrelationRulesRepository; +import com.park.utmstack.repository.logstash_filter.UtmLogstashFilterRepository; +import com.park.utmstack.service.correlation.rules.UtmCorrelationRulesService; +import com.park.utmstack.service.dto.correlation.AdversaryType; +import com.park.utmstack.service.dto.correlation.UtmCorrelationRulesDTO; +import com.park.utmstack.service.dto.correlation.UtmCorrelationRulesMapper; +import com.park.utmstack.service.dto.correlation.RuleYaml; +import com.park.utmstack.service.logstash_filter.UtmLogstashFilterService; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.yaml.snakeyaml.Yaml; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Service +@RequiredArgsConstructor +public class DefinitionSyncService implements CommandLineRunner { + + private final Logger log = LoggerFactory.getLogger(DefinitionSyncService.class); + + private final UtmLogstashFilterRepository filterRepository; + private final UtmCorrelationRulesRepository rulesRepository; + private final UtmDataTypesRepository dataTypesRepository; + private final UtmCorrelationRulesService rulesService; + private final UtmCorrelationRulesMapper rulesMapper; + private final UtmLogstashFilterService filterService; + + @Override + @Transactional + public void run(String... args) { + log.info("Starting definition sync from filesystem... ---"); + try { + Set filesystemFilters = syncFilters(); + Set filesystemRules = syncRules(); + + cleanupOrphanedFilters(filesystemFilters); + cleanupOrphanedRules(filesystemRules); + + log.info("Definition sync completed successfully. ---"); + } catch (Exception e) { + log.error("CRITICAL: Definition sync failed. Reason: {} ---", e.getMessage(), e); + } + } + + private Set syncFilters() { + Set foundFilters = new HashSet<>(); + Path filtersPath = Paths.get(".",Constants.APP_FILTER_DEFINITIONS); + if (!Files.exists(filtersPath) || !Files.isDirectory(filtersPath)) { + log.warn("Filters directory not found: {}", Constants.APP_FILTER_DEFINITIONS); + return foundFilters; + } + + // Regex to extract the first dataType from the pipeline structure: + // pipeline: + // - dataTypes: + // - value + java.util.regex.Pattern dataTypePattern = java.util.regex.Pattern.compile( + "pipeline:\\s*\\n\\s*-\\s*dataTypes:\\s*\\n\\s*-\\s*([^\\s\\n]+)", + java.util.regex.Pattern.MULTILINE + ); + + try (Stream paths = Files.walk(filtersPath)) { + paths.filter(path -> Files.isRegularFile(path) && isYamlFile(path)).forEach(path -> { + try { + String content = Files.readString(path); + java.util.regex.Matcher matcher = dataTypePattern.matcher(content); + if (!matcher.find()) { + log.warn("Skipping filter file without dataType: {}", path); + return; + } + + String dataTypeStr = matcher.group(1).trim().replace("\"", "").replace("'", ""); + log.info("found dataType: {}", dataTypeStr); + + Optional dataTypeEntity = dataTypesRepository.findOneByDataType(dataTypeStr.toLowerCase()); + + String moduleName = null; + if ("generic".equalsIgnoreCase(dataTypeStr)) { + moduleName = "GENERIC"; + } else if (dataTypeEntity.isPresent() && dataTypeEntity.get().getModule() != null) { + moduleName = dataTypeEntity.get().getModule().getModuleName().toString(); + } + + if(moduleName==null){ + log.error("module name for filter: {} with dataType: {} not found, ignoring...",path,dataTypeStr); + return; + } + + + Optional filterOpt = filterRepository.findFirstByLogstashFilterAndSystemOwnerIsTrue(content); + + if (filterOpt.isPresent()) { + UtmLogstashFilter filter = filterOpt.get(); + foundFilters.add(filter.getId()); + if (!content.equals(filter.getLogstashFilter())) { + log.info("Updating existing filter for module: {}", moduleName); + filter.setLogstashFilter(content); + filter.setUpdatedAt(Instant.now()); + try{ + filterService.save(filter); + } + catch (Exception e) { + log.error("Error updating filter on file {}: {}", path, e.getMessage()); + } + } + } else { + UtmLogstashFilter filter = new UtmLogstashFilter(); + filter.setId(filterService.getSystemSequenceNextValue()); + filter.setModuleName(moduleName); + filter.setFilterName(moduleName + " Filter"); + filter.setLogstashFilter(content); + filter.setSystemOwner(true); + filter.setActive(true); + filter.setUpdatedAt(Instant.now()); + foundFilters.add(filter.getId()); + + + if (dataTypeEntity.isPresent()) { + filter.setDatatype(dataTypeEntity.get()); + } + + log.info("Creating filter from file {} for module: {} and dataType {}, filter: {}",path,moduleName, dataTypeStr,filter); + try{ + filterService.save(filter); + } + catch (Exception e) { + log.error("Error creating filter on file {}: {}", path, e.getMessage()); + } + + } + } catch (IOException e) { + log.error("Error reading filter file {}: {}", path, e.getMessage()); + } catch (Exception e) { + log.error("Error processing filter file {}: {}", path, e.getMessage()); + } + }); + } catch (IOException e) { + log.error("Error listing filters directory: {}", e.getMessage()); + } + return foundFilters; + } + + private Set syncRules() { + Set foundRules = new HashSet<>(); + Path rulesPath = Paths.get(".",Constants.APP_RULE_DEFINITIONS); + if (!Files.exists(rulesPath) || !Files.isDirectory(rulesPath)) { + log.warn("Rules directory not found: {}", Constants.APP_RULE_DEFINITIONS); + return foundRules; + } + + Yaml yaml = new Yaml(); + try (Stream paths = Files.walk(rulesPath)) { + + paths.filter(path -> Files.isRegularFile(path) && isYamlFile(path)).forEach(path -> { + try { + String content = Files.readString(path); + Object yamlObj = yaml.load(content); + List> rawRules = new ArrayList<>(); + + if (yamlObj instanceof List) { + rawRules.addAll((List>) yamlObj); + } else if (yamlObj instanceof Map) { + rawRules.add((Map) yamlObj); + } + + for (Map rawRule : rawRules) { + RuleYaml ruleYaml = mapToRuleYaml(rawRule); + if (ruleYaml == null || ruleYaml.getName() == null) { + log.warn("Skipping invalid rule in file: {}", path); + continue; + } + + foundRules.add(ruleYaml.getName()); + Optional ruleOpt = rulesRepository.findOneByRuleName(ruleYaml.getName()); + UtmCorrelationRulesDTO ruleDto = new UtmCorrelationRulesDTO(); + + if (ruleOpt.isPresent()) { + ruleDto.setId(ruleOpt.get().getId()); + } else if (ruleYaml.getId() != null) { + ruleDto.setId(ruleYaml.getId()); + } else { + ruleDto.setId(rulesService.getSystemSequenceNextValue()); + } + + ruleDto.setName(ruleYaml.getName()); + ruleDto.setCategory(ruleYaml.getCategory()); + ruleDto.setTechnique(ruleYaml.getTechnique()); + ruleDto.setAdversary(ruleYaml.getAdversary() != null ? ruleYaml.getAdversary() : AdversaryType.origin); + ruleDto.setDescription(ruleYaml.getDescription()); + ruleDto.setReferences(ruleYaml.getReferences()); + ruleDto.setDefinition(ruleYaml.getWhere()); + ruleDto.setGroupBy(ruleYaml.getGroupBy()); + ruleDto.setDeduplicateBy(ruleYaml.getDeduplicateBy()); + ruleDto.setAfterEvents(ruleYaml.getAfterEvents()); + ruleDto.setSystemOwner(true); + ruleDto.setRuleActive(true); + + if (ruleYaml.getImpact() != null) { + ruleDto.setConfidentiality(ruleYaml.getImpact().getConfidentiality()); + ruleDto.setIntegrity(ruleYaml.getImpact().getIntegrity()); + ruleDto.setAvailability(ruleYaml.getImpact().getAvailability()); + } + + // Map dataTypes strings to UtmDataTypes entities + if (ruleYaml.getDataTypes() != null) { + Set dataTypes = ruleYaml.getDataTypes().stream() + .map(dtName -> dataTypesRepository.findOneByDataType(dtName.toLowerCase())) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()); + ruleDto.setDataTypes(dataTypes); + } + + UtmCorrelationRules entity = rulesMapper.toEntity(ruleDto); + if (ruleOpt.isPresent()) { + rulesService.updateRule(entity, true); + } else { + rulesService.save(entity, true); + } + } + + } catch (Exception e) { + log.error("Error processing rule file {}: {}", path, e.getMessage()); + } + }); + } catch (IOException e) { + log.error("Error walking rules directory: {}", e.getMessage()); + } + return foundRules; + } + + private RuleYaml mapToRuleYaml(Map map) { + Yaml yaml = new Yaml(); + String dump = yaml.dump(map); + return yaml.loadAs(dump, RuleYaml.class); + } + + private void cleanupOrphanedFilters(Set currentFilterIds) { + if (currentFilterIds.isEmpty()) return; + List systemFilters = filterRepository.findAllBySystemOwnerIsTrue(); + systemFilters.stream() + .filter(filter -> !currentFilterIds.contains(filter.getId())) + .forEach(filter -> { + log.info("Deleting orphaned system filter: {}", filter.getModuleName()); + filterService.delete(filter.getId()); + }); + } + + private void cleanupOrphanedRules(Set currentFilesystemRules) { + if (currentFilesystemRules.isEmpty()) return; + + List systemRules = rulesRepository.findAllBySystemOwnerIsTrue(); + systemRules.stream() + .filter(rule -> !currentFilesystemRules.contains(rule.getRuleName())) + .forEach(rule -> { + log.info("Deleting orphaned system rule: {}", rule.getRuleName()); + try { + rulesService.deleteRule(rule.getId(), true); + } catch (Exception e) { + log.error("Error deleting orphaned system rule {}: {}", rule.getRuleName(), e.getMessage()); + } + }); + } + + private boolean isYamlFile(Path path) { + String fileName = path.getFileName().toString().toLowerCase(); + return fileName.endsWith(".yaml") || fileName.endsWith(".yml"); + } + + private String getFileNameWithoutExtension(Path path) { + String fileName = path.getFileName().toString(); + int lastDotIndex = fileName.lastIndexOf('.'); + return (lastDotIndex == -1) ? fileName : fileName.substring(0, lastDotIndex); + } +} diff --git a/backend/src/main/java/com/park/utmstack/service/UtmIntegrationConfService.java b/backend/src/main/java/com/park/utmstack/service/UtmIntegrationConfService.java index e36b39a52..cc6975db2 100644 --- a/backend/src/main/java/com/park/utmstack/service/UtmIntegrationConfService.java +++ b/backend/src/main/java/com/park/utmstack/service/UtmIntegrationConfService.java @@ -40,7 +40,8 @@ public UtmIntegrationConf save(UtmIntegrationConf utmIntegrationConf) throws Exc final String ctx = CLASSNAME + ".save"; try { String dataType = utmIntegrationConf.getConfDatatype(); - if (StringUtils.hasText(dataType) && dataType.equals("password")) + if (StringUtils.hasText(dataType) && dataType.equals("password") + && !Constants.MASKED_VALUE.equals(utmIntegrationConf.getConfValue())) utmIntegrationConf.setConfValue(CipherUtil.encrypt(utmIntegrationConf.getConfValue(), System.getenv(Constants.ENV_ENCRYPTION_KEY))); return utmIntegrationConfRepository.save(utmIntegrationConf); } catch (Exception e) { diff --git a/backend/src/main/java/com/park/utmstack/service/alert_response_rule/UtmAlertResponseRuleService.java b/backend/src/main/java/com/park/utmstack/service/alert_response_rule/UtmAlertResponseRuleService.java index 07b3cdd36..7f4489c00 100644 --- a/backend/src/main/java/com/park/utmstack/service/alert_response_rule/UtmAlertResponseRuleService.java +++ b/backend/src/main/java/com/park/utmstack/service/alert_response_rule/UtmAlertResponseRuleService.java @@ -283,8 +283,9 @@ public void executeRuleCommands() { if (agent.getStatus().equals(AgentStatusEnum.ONLINE)) { String reason = "The incident response automation executed this command because it was accomplished the conditions of the rule with ID: " + cmd.getRuleId(); final StringBuilder results = new StringBuilder(); + String shell = cmd.getRule() != null ? cmd.getRule().getRuleShell() : null; incidentResponseCommandService.sendCommand(String.valueOf(agent.getId()), utmIncidentVariableService.replaceVariablesInCommand(cmd.getCommand()), "INCIDENT_RESPONSE_AUTOMATION", - cmd.getRuleId().toString(), reason, Constants.SYSTEM_ACCOUNT, new StreamObserver<>() { + cmd.getRuleId().toString(), reason, Constants.SYSTEM_ACCOUNT, shell, new StreamObserver<>() { @Override public void onNext(CommandResult commandResult) { results.append(commandResult.getResult()); diff --git a/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupConfigurationService.java b/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupConfigurationService.java index e2b649c2c..a0231e944 100644 --- a/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupConfigurationService.java +++ b/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupConfigurationService.java @@ -50,22 +50,41 @@ public void createConfigurationKeys(List keys) thro } /** - * Update configuration of the application modules - * - * @param keys List of configuration keys to save + * Update configuration of the application modules. + * Password/file fields with the masked value are skipped (not changed). + * Password/file fields with a new value are encrypted before saving. */ public UtmModule updateConfigurationKeys(Long moduleId, List keys) { final String ctx = CLASSNAME + ".updateConfigurationKeys"; try { if (CollectionUtils.isEmpty(keys)) throw new ApiException("No configuration keys were provided to update", HttpStatus.BAD_REQUEST); + for (UtmModuleGroupConfiguration key : keys) { + boolean isSensitive = isSensitiveType(key.getConfDataType()); + + // Skip masked values — the user did not change this field + if (isSensitive && Constants.MASKED_VALUE.equals(key.getConfValue())) { + continue; + } + if (key.getConfRequired() && !StringUtils.hasText(key.getConfValue())) throw new Exception(String.format("No value was found for required configuration: %1$s (%2$s)", key.getConfName(), key.getConfKey())); - if (key.getConfDataType().equals("password") || key.getConfDataType().equals("file")) + + // Encrypt new sensitive values + if (isSensitive) { key.setConfValue(CipherUtil.encrypt(key.getConfValue(), System.getenv(Constants.ENV_ENCRYPTION_KEY))); + } + } + + // Remove masked entries so they don't overwrite DB values + List toSave = keys.stream() + .filter(k -> !(isSensitiveType(k.getConfDataType()) && Constants.MASKED_VALUE.equals(k.getConfValue()))) + .collect(Collectors.toList()); + + if (!toSave.isEmpty()) { + moduleConfigurationRepository.saveAll(toSave); } - moduleConfigurationRepository.saveAll(keys); List needRestartModules = Arrays.asList(ModuleName.AWS_IAM_USER, ModuleName.AZURE, ModuleName.GCP, ModuleName.SOPHOS); @@ -83,16 +102,15 @@ public UtmModule updateConfigurationKeys(Long moduleId, List findAllByGroupId(Long groupId) throws Exception { final String ctx = CLASSNAME + ".findAllByGroupId"; try { - return moduleConfigurationRepository.findAllByGroupId(groupId); + List configs = moduleConfigurationRepository.findAllByGroupId(groupId); + maskSensitiveValues(configs); + return configs; } catch (Exception e) { throw new Exception(ctx + ": " + e.getMessage()); } @@ -100,15 +118,11 @@ public List findAllByGroupId(Long groupId) throws E /** * Gets all configuration parameter for a group and convert it to a map - * - * @param groupId Identifier of a group - * @return A map with the module group configuration - * @throws Exception In case of any error */ public Map getGroupConfigurationAsMap(Long groupId) throws Exception { final String ctx = CLASSNAME + ".getGroupConfigurationAsMap"; try { - List configurations = findAllByGroupId(groupId); + List configurations = moduleConfigurationRepository.findAllByGroupId(groupId); if (CollectionUtils.isEmpty(configurations)) return Collections.emptyMap(); @@ -121,18 +135,30 @@ public Map getGroupConfigurationAsMap(Long groupId) throws Excep /** * Find a configuration parameter by his group and key - * - * @param groupId Identifier of the group to the param belongs - * @param confKey Key word of the configuration parameter - * @return A ${@link UtmModuleGroupConfiguration} object with the configuration parameter information - * @throws Exception In case of any error */ public UtmModuleGroupConfiguration findByGroupIdAndConfKey(Long groupId, String confKey) throws Exception { final String ctx = CLASSNAME + ".findByGroupIdAndConfKey"; try { - return moduleConfigurationRepository.findByGroupIdAndConfKey(groupId, confKey); + UtmModuleGroupConfiguration config = moduleConfigurationRepository.findByGroupIdAndConfKey(groupId, confKey); + if (config != null && isSensitiveType(config.getConfDataType())) { + config.setConfValue(Constants.MASKED_VALUE); + } + return config; } catch (Exception e) { throw new Exception(ctx + ": " + e.getMessage()); } } + + private boolean isSensitiveType(String dataType) { + return Constants.CONF_TYPE_PASSWORD.equals(dataType) || Constants.CONF_TYPE_FILE.equals(dataType); + } + + private void maskSensitiveValues(List configs) { + if (configs == null) return; + for (UtmModuleGroupConfiguration config : configs) { + if (isSensitiveType(config.getConfDataType()) && StringUtils.hasText(config.getConfValue())) { + config.setConfValue(Constants.MASKED_VALUE); + } + } + } } diff --git a/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupService.java b/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupService.java index 28e89d7a1..750898f30 100644 --- a/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupService.java +++ b/backend/src/main/java/com/park/utmstack/service/application_modules/UtmModuleGroupService.java @@ -250,6 +250,9 @@ public void updateCollectorConfigurationKeys(CollectorConfigDTO collectorConfig) } else { for (UtmModuleGroupConfiguration key : keys) { if (key.getConfDataType().equals("password")) { + if (Constants.MASKED_VALUE.equals(key.getConfValue())) { + continue; + } key.setConfValue(CipherUtil.encrypt(key.getConfValue(), System.getenv(Constants.ENV_ENCRYPTION_KEY))); } } diff --git a/backend/src/main/java/com/park/utmstack/service/collectors/CollectorOpsService.java b/backend/src/main/java/com/park/utmstack/service/collectors/CollectorOpsService.java index 5e9579ae3..a8f6f872d 100644 --- a/backend/src/main/java/com/park/utmstack/service/collectors/CollectorOpsService.java +++ b/backend/src/main/java/com/park/utmstack/service/collectors/CollectorOpsService.java @@ -436,6 +436,9 @@ public void updateCollectorConfigurationKeys(CollectorConfigDTO collectorConfig) utmModuleGroupRepository.deleteAll(configs); } else { for (UtmModuleGroupConfiguration key : keys) { + if (key.getConfDataType().equals("password") && Constants.MASKED_VALUE.equals(key.getConfValue())) { + continue; + } if (key.getConfRequired() && !StringUtils.hasText(key.getConfValue())) throw new Exception(String.format("No value was found for required configuration: %1$s (%2$s)", key.getConfName(), key.getConfKey())); if (key.getConfDataType().equals("password")) diff --git a/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigCriteriaService.java b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigCriteriaService.java new file mode 100644 index 000000000..3407adac8 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigCriteriaService.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 UtmComplianceControlConfigCriteriaService extends QueryService { + + private final UtmComplianceControlConfigRepository complianceControlConfigRepository; + private final UtmComplianceControlConfigMapper mapper; + + public UtmComplianceControlConfigCriteriaService(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 new file mode 100644 index 000000000..41d073a20 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlConfigService.java @@ -0,0 +1,150 @@ +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.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.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; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +@Service +public class UtmComplianceControlConfigService { + + private final UtmComplianceControlConfigRepository repository; + private final UtmComplianceControlConfigMapper mapper; + private final UtmComplianceQueryConfigMapper queryMapper; + + public UtmComplianceControlConfigService(UtmComplianceControlConfigRepository repository, + UtmComplianceControlConfigMapper mapper, + UtmComplianceQueryConfigMapper queryMapper) { + this.repository = repository; + this.mapper = mapper; + this.queryMapper = queryMapper; + } + + @Transactional + public UtmComplianceControlConfigDto create(UtmComplianceControlConfigDto dto) { + + validateControlConfig(dto); + + UtmComplianceControlConfig entity = mapper.toEntity(dto); + + for (var qdto : dto.getQueriesConfigs()) { + var q = queryMapper.toEntity(qdto); + q.setControlConfig(entity); + entity.getQueriesConfigs().add(q); + } + + entity = repository.save(entity); + + return mapper.toDto(entity); + } + + @Transactional + public UtmComplianceControlConfigDto update(Long id, UtmComplianceControlConfigDto dto) { + + validateControlConfig(dto); + + UtmComplianceControlConfig entity = repository.findByIdWithQueries(id) + .orElseThrow(() -> new NoSuchElementException("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()) { + 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); + } + } + return mapper.toDto(entity); + } + + 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 NoSuchElementException("Control not found")); + + return mapper.toDto(entity); + } + + 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" + ); + } + } + } + + public Page findBySection(Long sectionId, String search, Pageable pageable) { + + Specification spec = Specification.where(UtmComplianceControlConfigRepository.bySection(sectionId)); + + 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(ids); + + 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()); + } + +} 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..b032c9469 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationHistoryService.java @@ -0,0 +1,114 @@ +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.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..1b721528e --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/compliance/config/UtmComplianceControlEvaluationLatestService.java @@ -0,0 +1,49 @@ +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 javax.persistence.EntityNotFoundException; + +@Service +public class UtmComplianceControlEvaluationLatestService { + + private final UtmComplianceControlConfigService configService; + private final ElasticsearchService elasticsearchService; + private final UtmComplianceControlConfigMapper controlMapper; + + public UtmComplianceControlEvaluationLatestService(UtmComplianceControlConfigService configService, + ElasticsearchService elasticsearchService, + UtmComplianceControlConfigMapper controlMapper) { + this.configService = configService; + this.elasticsearchService = elasticsearchService; + this.controlMapper = controlMapper; + } + + public Page getControlsWithLastEvaluation( + Long sectionId, String search, Pageable pageable) { + + Page controls = configService.findBySection(sectionId, search, pageable); + + return controls.map(control -> { + UtmComplianceControlConfigDto controlDto = controlMapper.toDto(control); + var lastEval = elasticsearchService.getLatestControlEvaluation(control.getId()); + return UtmComplianceControlLatestEvaluationMapper.toDto(controlDto, lastEval); + }); + } + + public UtmComplianceControlLatestEvaluationDto getControlWithLastEvaluation(Long controlId) { + UtmComplianceControlConfigDto controlDto = configService.findById(controlId); + var lastEval = elasticsearchService.getLatestControlEvaluation(controlId); + return UtmComplianceControlLatestEvaluationMapper.toDto(controlDto, lastEval); + } +} + + diff --git a/backend/src/main/java/com/park/utmstack/service/correlation/rules/UtmCorrelationRulesService.java b/backend/src/main/java/com/park/utmstack/service/correlation/rules/UtmCorrelationRulesService.java index 97033db62..540bc0ed9 100644 --- a/backend/src/main/java/com/park/utmstack/service/correlation/rules/UtmCorrelationRulesService.java +++ b/backend/src/main/java/com/park/utmstack/service/correlation/rules/UtmCorrelationRulesService.java @@ -62,6 +62,10 @@ public UtmCorrelationRulesService(UtmCorrelationRulesRepository utmCorrelationRu * @return the persisted entity. */ public UtmCorrelationRules save(UtmCorrelationRules rule) { + return save(rule, false); + } + + public UtmCorrelationRules save(UtmCorrelationRules rule, boolean forcedSystemMode) { final String ctx = CLASSNAME + ".saveRule"; log.debug("Request to save UtmCorrelationRules : {}", rule); @@ -72,6 +76,10 @@ public UtmCorrelationRules save(UtmCorrelationRules rule) { } } + if (forcedSystemMode) { + rule.setSystemOwner(true); + } + rule.setDataTypes(this.saveDataTypes(rule)); rule.setRuleLastUpdate(Instant.now(Clock.systemUTC())); return utmCorrelationRulesRepository.save(rule); @@ -86,6 +94,11 @@ public UtmCorrelationRules save(UtmCorrelationRules rule) { * */ @Transactional public void updateRule(UtmCorrelationRules correlationRule) throws Exception { + updateRule(correlationRule, false); + } + + @Transactional + public void updateRule(UtmCorrelationRules correlationRule, boolean forcedSystemMode) throws Exception { final String ctx = CLASSNAME + ".updateRule"; Long id = correlationRule.getId(); if (id == null) { @@ -99,7 +112,12 @@ public void updateRule(UtmCorrelationRules correlationRule) throws Exception { if (correlationRule.getDataTypes().isEmpty()) { throw new BadRequestException(ctx + ": The rule must have at least one data type."); } - if(optionalCorrelationRule.get().getSystemOwner() && !utmStackService.isInDevelop()) { + + if (forcedSystemMode) { + correlationRule.setSystemOwner(true); + } + + if(optionalCorrelationRule.get().getSystemOwner() && !utmStackService.isInDevelop() && !forcedSystemMode) { throw new BadRequestException(ctx + ": System's rules can't be updated."); } correlationRule.setDataTypes(this.saveDataTypes(correlationRule)); @@ -140,12 +158,17 @@ public void setRuleActivation(Long ruleId, boolean setActive) throws Exception { * */ @Transactional public void deleteRule (Long id) throws Exception { + deleteRule(id, false); + } + + @Transactional + public void deleteRule (Long id, boolean forcedSystemMode) throws Exception { final String ctx = CLASSNAME + ".deleteRule"; Optional find = utmCorrelationRulesRepository.findById(id); if (find.isEmpty()) { throw new BadRequestException(ctx + ": The rule you're trying to delete is not present in database."); } - if(find.get().getSystemOwner()) { + if(find.get().getSystemOwner() && !forcedSystemMode) { throw new BadRequestException(ctx + ": System's rules can't be removed."); } utmCorrelationRulesRepository.deleteById(id); diff --git a/backend/src/main/java/com/park/utmstack/service/dto/PasswordChangeDTO.java b/backend/src/main/java/com/park/utmstack/service/dto/PasswordChangeDTO.java index 0611a7ca6..48772dd31 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/PasswordChangeDTO.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/PasswordChangeDTO.java @@ -1,9 +1,12 @@ package com.park.utmstack.service.dto; +import com.park.utmstack.service.dto.auditable.AuditableDTO; +import java.util.Map; + /** * A DTO representing a password change required data - current and new password. */ -public class PasswordChangeDTO { +public class PasswordChangeDTO implements AuditableDTO { private String currentPassword; private String newPassword; @@ -16,6 +19,11 @@ public PasswordChangeDTO(String currentPassword, String newPassword) { this.newPassword = newPassword; } + @Override + public Map toAuditMap() { + return Map.of("action", "password_change"); + } + public String getCurrentPassword() { return currentPassword; diff --git a/backend/src/main/java/com/park/utmstack/service/dto/UserDTO.java b/backend/src/main/java/com/park/utmstack/service/dto/UserDTO.java index 4d0670ee1..a55bc5083 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/UserDTO.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/UserDTO.java @@ -4,18 +4,21 @@ import com.park.utmstack.domain.Authority; import com.park.utmstack.domain.User; +import com.park.utmstack.service.dto.auditable.AuditableDTO; + import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import java.time.Instant; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** * A DTO representing a user, with his authorities. */ -public class UserDTO { +public class UserDTO implements AuditableDTO { private Long id; @@ -187,6 +190,15 @@ public void setTfaSecret(String tfaSecret) { this.tfaSecret = tfaSecret; } + @Override + public Map toAuditMap() { + return Map.of( + "login", login != null ? login : "", + "email", email != null ? email : "", + "authorities", authorities != null ? authorities.toString() : "" + ); + } + @Override public String toString() { return "UserDTO{" + "login='" + login + '\'' + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", email='" + email + '\'' + ", imageUrl='" + imageUrl + '\'' + ", activated=" + activated + ", langKey='" + langKey + '\'' + ", createdBy=" + createdBy + ", createdDate=" + createdDate + ", lastModifiedBy='" + lastModifiedBy + '\'' + ", lastModifiedDate=" + lastModifiedDate + ", authorities=" + authorities + "}"; diff --git a/backend/src/main/java/com/park/utmstack/service/dto/UtmAlertResponseRuleDTO.java b/backend/src/main/java/com/park/utmstack/service/dto/UtmAlertResponseRuleDTO.java index 7c6cfa8ad..b26641c56 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/UtmAlertResponseRuleDTO.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/UtmAlertResponseRuleDTO.java @@ -46,6 +46,9 @@ public class UtmAlertResponseRuleDTO { @Size(max = 500) private String defaultAgent; + @Size(max = 20) + private String shell; + private List excludedAgents = new ArrayList<>(); @JsonProperty(access = JsonProperty.Access.READ_ONLY) @@ -76,6 +79,7 @@ public UtmAlertResponseRuleDTO(UtmAlertResponseRule rule) { this.active = rule.getRuleActive(); this.agentPlatform = rule.getAgentPlatform(); this.defaultAgent = rule.getDefaultAgent(); + this.shell = rule.getRuleShell(); if (StringUtils.hasText(rule.getExcludedAgents())) { this.excludedAgents.addAll(Arrays.asList(rule.getExcludedAgents().split(","))); } 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..7bf9931fb --- /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 UtmComplianceStrategyFilter controlStrategy; +} \ No newline at end of file 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 new file mode 100644 index 000000000..9721650eb --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlConfigDto.java @@ -0,0 +1,34 @@ +package com.park.utmstack.service.dto.compliance; + +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; + + private UtmComplianceStandardSectionDto section; + + @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; +} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationGroupedDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationGroupedDto.java new file mode 100644 index 000000000..cf19524c7 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationGroupedDto.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 UtmComplianceControlEvaluationGroupedDto { + 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/UtmComplianceControlEvaluationHistoryDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryDto.java new file mode 100644 index 000000000..2cdbb1c3c --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryDto.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 UtmComplianceControlEvaluationHistoryDto { + 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/UtmComplianceControlEvaluationHistoryResponseDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryResponseDto.java new file mode 100644 index 000000000..fbc433503 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceControlEvaluationHistoryResponseDto.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 UtmComplianceControlEvaluationHistoryResponseDto { + 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/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/UtmComplianceIndexPatternQueriesGroupDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceIndexPatternQueriesGroupDto.java new file mode 100644 index 000000000..3d0979513 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceIndexPatternQueriesGroupDto.java @@ -0,0 +1,12 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Data; + +import java.util.List; + +@Data +public class UtmComplianceIndexPatternQueriesGroupDto { + 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/UtmComplianceQueryConfigDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java new file mode 100644 index 000000000..a02b40297 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryConfigDto.java @@ -0,0 +1,36 @@ +package com.park.utmstack.service.dto.compliance; + +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/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..8611e8399 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceQueryEvaluationDto.java @@ -0,0 +1,24 @@ +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 String queryDescription; + private String evaluationRule; + private Integer ruleValue; + private Long indexPatternId; + private String indexPatternName; + private Integer hits; + private String status; + private String errorMessage; + private List> evidence; +} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStandardDto.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStandardDto.java new file mode 100644 index 000000000..a05c69df6 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStandardDto.java @@ -0,0 +1,10 @@ +package com.park.utmstack.service.dto.compliance; + +import lombok.Data; + +@Data +public class UtmComplianceStandardDto { + private Long id; + private String standardName; + private String standardDescription; +} \ No newline at end of file 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..bb579d763 --- /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 UtmComplianceStandardDto standard; +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStrategyFilter.java b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStrategyFilter.java new file mode 100644 index 000000000..4948c2e03 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/compliance/UtmComplianceStrategyFilter.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 UtmComplianceStrategyFilter extends Filter { + +} + diff --git a/backend/src/main/java/com/park/utmstack/service/dto/correlation/RuleYaml.java b/backend/src/main/java/com/park/utmstack/service/dto/correlation/RuleYaml.java new file mode 100644 index 000000000..7b2567e45 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/dto/correlation/RuleYaml.java @@ -0,0 +1,30 @@ +package com.park.utmstack.service.dto.correlation; + +import com.park.utmstack.domain.correlation.rules.SearchRequest; +import com.park.utmstack.domain.shared_types.alert.Impact; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RuleYaml { + private Long id; + private List dataTypes; + private String name; + private Impact impact; + private String category; + private String technique; + private AdversaryType adversary; + private String description; + private List references; + private String where; + private List afterEvents; + private List groupBy; + private List deduplicateBy; +} diff --git a/backend/src/main/java/com/park/utmstack/service/dto/correlation/UtmCorrelationRulesDTO.java b/backend/src/main/java/com/park/utmstack/service/dto/correlation/UtmCorrelationRulesDTO.java index ba02274f8..f7a561110 100644 --- a/backend/src/main/java/com/park/utmstack/service/dto/correlation/UtmCorrelationRulesDTO.java +++ b/backend/src/main/java/com/park/utmstack/service/dto/correlation/UtmCorrelationRulesDTO.java @@ -4,6 +4,7 @@ import com.park.utmstack.domain.correlation.rules.AfterEvents; import com.park.utmstack.domain.correlation.rules.RuleDefinition; import com.park.utmstack.domain.correlation.rules.SearchRequest; +import com.park.utmstack.service.dto.auditable.AuditableDTO; import lombok.Data; import lombok.Getter; import lombok.Setter; @@ -12,10 +13,11 @@ import javax.validation.constraints.*; import java.io.Serializable; import java.util.List; +import java.util.Map; import java.util.Set; @Data -public class UtmCorrelationRulesDTO implements Serializable { +public class UtmCorrelationRulesDTO implements Serializable, AuditableDTO { private static final long serialVersionUID = 1L; @@ -64,5 +66,14 @@ public class UtmCorrelationRulesDTO implements Serializable { private List groupBy; + @Override + public Map toAuditMap() { + return Map.of( + "name", name != null ? name : "", + "category", category != null ? category : "", + "technique", technique != null ? technique : "" + ); + } + } 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 e11fa6bde..dcddeac7e 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 @@ -11,6 +11,9 @@ import com.park.utmstack.service.UtmSpaceNotificationControlService; import com.park.utmstack.service.application_events.ApplicationEventService; import com.park.utmstack.service.index_policy.IndexPolicyService; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationHistoryDto; +import com.park.utmstack.service.mapper.compliance.UtmComplianceControlLatestEvaluationMapper; +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; @@ -22,6 +25,7 @@ import com.utmstack.opensearch_connector.types.SearchSqlResponse; import com.utmstack.opensearch_connector.types.SqlQueryRequest; import lombok.extern.slf4j.Slf4j; +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; @@ -419,4 +423,63 @@ 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(30) + .sort(s -> s.field(f -> f + .field("timestamp") + .order(SortOrder.Desc) + )) + .build(); + + SearchResponse response = search(request, Map.class); + + var evaluations = response.hits().hits().stream() + .map(hit -> UtmComplianceControlEvaluationHistoryMapper.mapToEvaluationDto(hit.source())) + .toList(); + + return evaluations; + + } catch (Exception e) { + throw new RuntimeException(ctx + ": " + e.getMessage(), e); + } + } + + public UtmComplianceControlEvaluationHistoryDto getLatestControlEvaluation(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 UtmComplianceControlLatestEvaluationMapper.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/elasticsearch/OpensearchClientBuilder.java b/backend/src/main/java/com/park/utmstack/service/elasticsearch/OpensearchClientBuilder.java index d1f6f9471..f6f62d042 100644 --- a/backend/src/main/java/com/park/utmstack/service/elasticsearch/OpensearchClientBuilder.java +++ b/backend/src/main/java/com/park/utmstack/service/elasticsearch/OpensearchClientBuilder.java @@ -27,9 +27,18 @@ public void init() throws Exception { Assert.hasText(host, "Environment variable ELASTICSEARCH_HOST is missing or his value is null or empty"); String port = System.getenv(Constants.ENV_ELASTICSEARCH_PORT); - Assert.hasText(host, "Environment variable ELASTICSEARCH_PORT is missing or his value is null or empty"); + Assert.hasText(port, "Environment variable ELASTICSEARCH_PORT is missing or his value is null or empty"); - client = OpenSearch.builder().withHost(host, Integer.parseInt(port), HttpScheme.http).build(); + String user = System.getenv(Constants.ENV_ELASTICSEARCH_USER); + Assert.hasText(user, "Environment variable ELASTICSEARCH_USER is missing or his value is null or empty"); + + String password = System.getenv(Constants.ENV_ELASTICSEARCH_PASSWORD); + Assert.hasText(password, "Environment variable ELASTICSEARCH_PASSWORD is missing or his value is null or empty"); + + client = OpenSearch.builder() + .withHost(host, Integer.parseInt(port), HttpScheme.https) + .withCredentials(user, password) + .build(); } catch (Exception e) { String msg = ctx + ": " + e.getMessage(); log.error(msg); 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/java/com/park/utmstack/service/impl/UtmAlertServiceImpl.java b/backend/src/main/java/com/park/utmstack/service/impl/UtmAlertServiceImpl.java index c3b3f0d3e..c414e5cda 100644 --- a/backend/src/main/java/com/park/utmstack/service/impl/UtmAlertServiceImpl.java +++ b/backend/src/main/java/com/park/utmstack/service/impl/UtmAlertServiceImpl.java @@ -126,7 +126,7 @@ public void checkForNewAlerts() { alertResponseRuleService.evaluateRules(alerts); if (moduleService.isModuleActive(ModuleName.SOC_AI)) - socAIService.requestSocAiProcess(alerts.stream().map(UtmAlert::getId).collect(Collectors.toList())); + alerts.forEach(socAIService::analyzeAlert); } catch (Exception e) { String msg = ctx + ": " + e.getMessage(); log.error(msg); diff --git a/backend/src/main/java/com/park/utmstack/service/incident_response/grpc_impl/IncidentResponseCommandService.java b/backend/src/main/java/com/park/utmstack/service/incident_response/grpc_impl/IncidentResponseCommandService.java index ebdb57086..d4dd60633 100644 --- a/backend/src/main/java/com/park/utmstack/service/incident_response/grpc_impl/IncidentResponseCommandService.java +++ b/backend/src/main/java/com/park/utmstack/service/incident_response/grpc_impl/IncidentResponseCommandService.java @@ -22,18 +22,22 @@ public void sendCommand(String agentId, String originId, String reason, String executedBy, + String shell, StreamObserver responseObserver) { - // Get the stub - // Create the UtmCommand with the provided agent key and command - UtmCommand utmCommand = UtmCommand.newBuilder() + UtmCommand.Builder builder = UtmCommand.newBuilder() .setAgentId(agentId) .setCommand(command) .setOriginId(originId) .setOriginType(originType) .setReason(reason) - .setExecutedBy(executedBy) - .build(); + .setExecutedBy(executedBy); + + if (shell != null && !shell.isEmpty()) { + builder.setShell(shell); + } + + UtmCommand utmCommand = builder.build(); // Send command using the bidirectional stream StreamObserver requestObserver = nonBlockingStub.processCommand(responseObserver); diff --git a/backend/src/main/java/com/park/utmstack/service/logstash_filter/UtmLogstashFilterService.java b/backend/src/main/java/com/park/utmstack/service/logstash_filter/UtmLogstashFilterService.java index 4afb5dd94..8eb360b3e 100644 --- a/backend/src/main/java/com/park/utmstack/service/logstash_filter/UtmLogstashFilterService.java +++ b/backend/src/main/java/com/park/utmstack/service/logstash_filter/UtmLogstashFilterService.java @@ -38,7 +38,6 @@ public UtmLogstashFilter save(UtmLogstashFilter logstashFilter) { final String ctx = CLASSNAME + ".save"; try { logstashFilter.setUpdatedAt(Instant.now()); - logstashFilter.setSystemOwner(false); return logstashFilterRepository.save(logstashFilter); } catch (Exception e) { throw new RuntimeException(ctx + ": " + e.getMessage()); @@ -115,4 +114,10 @@ public List filtersByPipelineId(Long pipelineId) { throw new RuntimeException(ctx + ": " + e.getMessage()); } } + + public Long getSystemSequenceNextValue() { + return logstashFilterRepository.findFirstBySystemOwnerIsTrueOrderByIdDesc() + .map(filter -> filter.getId() + 1) + .orElse(1L); + } } 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..679951875 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlConfigMapper.java @@ -0,0 +1,23 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceControlConfig; +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; + +@Mapper(componentModel = "spring", uses = { + UtmComplianceQueryConfigMapper.class, + UtmComplianceStandardSectionMapper.class, + UtmComplianceStandardMapper.class}) +public interface UtmComplianceControlConfigMapper { + + @Mapping(target = "queriesConfigs", ignore = true) + UtmComplianceControlConfig toEntity(UtmComplianceControlConfigDto dto); + + UtmComplianceControlConfigDto toDto(UtmComplianceControlConfig entity); + + @Mapping(target = "id", ignore = true) + @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/UtmComplianceControlEvaluationHistoryMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationHistoryMapper.java new file mode 100644 index 000000000..7ca83715d --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlEvaluationHistoryMapper.java @@ -0,0 +1,55 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import com.park.utmstack.service.dto.compliance.UtmComplianceControlEvaluationHistoryDto; +import com.park.utmstack.service.dto.compliance.UtmComplianceQueryEvaluationDto; + +import java.time.Instant; +import java.util.List; +import java.util.Map; +public class UtmComplianceControlEvaluationHistoryMapper { + + private UtmComplianceControlEvaluationHistoryMapper() { + + } + + 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")); + dto.setStatus((String) src.get("status")); + dto.setTimestamp(Instant.parse((String) src.get("timestamp"))); + + + ObjectMapper mapper = new ObjectMapper(); + List> q = mapper.convertValue(src.get("query_evaluations"), new TypeReference<>() {}); + if (q != null) { + dto.setQueryEvaluations(q.stream().map(UtmComplianceControlEvaluationHistoryMapper::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.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")); + + ObjectMapper mapper = new ObjectMapper(); + List> evidence = mapper.convertValue(src.get("evidence"), new TypeReference<>() {}); + dto.setEvidence(evidence); + + return dto; + } +} diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlLatestEvaluationMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlLatestEvaluationMapper.java new file mode 100644 index 000000000..28a648f3e --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceControlLatestEvaluationMapper.java @@ -0,0 +1,64 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.service.dto.compliance.UtmComplianceControlConfigDto; +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 UtmComplianceControlLatestEvaluationMapper { + + public static UtmComplianceControlLatestEvaluationDto toDto( + UtmComplianceControlConfigDto control, + UtmComplianceControlEvaluationHistoryDto controlEvaluationHistory + ) { + UtmComplianceControlLatestEvaluationDto dto = new UtmComplianceControlLatestEvaluationDto(); + + 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()); + + if (controlEvaluationHistory != null) { + dto.setLastEvaluationStatus(controlEvaluationHistory.getStatus()); + dto.setLastEvaluationTimestamp( + controlEvaluationHistory.getTimestamp() != null ? controlEvaluationHistory.getTimestamp().toString() : null + ); + } + + return dto; + } + + public static UtmComplianceControlEvaluationHistoryDto mapToEvaluationDto(Map source) { + if (source == null) { + return null; + } + + UtmComplianceControlEvaluationHistoryDto dto = new UtmComplianceControlEvaluationHistoryDto(); + dto.setControlId(getLong(source.get("control_id"))); + dto.setControlName(getString(source.get("control_name"))); + dto.setStatus(getString(source.get("status"))); + + 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/UtmComplianceQueryConfigMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java new file mode 100644 index 000000000..62fd44223 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceQueryConfigMapper.java @@ -0,0 +1,20 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceQueryConfig; +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/java/com/park/utmstack/service/mapper/compliance/UtmComplianceStandardMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceStandardMapper.java new file mode 100644 index 000000000..b16fb64ba --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceStandardMapper.java @@ -0,0 +1,10 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceStandard; +import com.park.utmstack.service.dto.compliance.UtmComplianceStandardDto; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface UtmComplianceStandardMapper { + UtmComplianceStandardDto toDto(UtmComplianceStandard entity); +} \ No newline at end of file diff --git a/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceStandardSectionMapper.java b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceStandardSectionMapper.java new file mode 100644 index 000000000..b0d78d3f1 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/service/mapper/compliance/UtmComplianceStandardSectionMapper.java @@ -0,0 +1,10 @@ +package com.park.utmstack.service.mapper.compliance; + +import com.park.utmstack.domain.compliance.UtmComplianceStandardSection; +import com.park.utmstack.service.dto.compliance.UtmComplianceStandardSectionDto; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring", uses = {UtmComplianceStandardMapper.class}) +public interface UtmComplianceStandardSectionMapper { + UtmComplianceStandardSectionDto toDto(UtmComplianceStandardSection entity); +} diff --git a/backend/src/main/java/com/park/utmstack/service/soc_ai/SocAIService.java b/backend/src/main/java/com/park/utmstack/service/soc_ai/SocAIService.java index 9afee1474..9cecc04a9 100644 --- a/backend/src/main/java/com/park/utmstack/service/soc_ai/SocAIService.java +++ b/backend/src/main/java/com/park/utmstack/service/soc_ai/SocAIService.java @@ -1,57 +1,68 @@ package com.park.utmstack.service.soc_ai; import com.google.gson.Gson; -import com.park.utmstack.domain.UtmAlertSocaiProcessingRequest; -import com.park.utmstack.domain.application_modules.enums.ModuleName; -import com.park.utmstack.service.UtmAlertSocaiProcessingRequestService; +import com.park.utmstack.config.Constants; +import com.park.utmstack.domain.shared_types.alert.UtmAlert; import com.park.utmstack.service.application_modules.UtmModuleService; import okhttp3.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; -import java.util.List; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; @Service public class SocAIService { private static final String CLASSNAME = "SocAIService"; private final Logger log = LoggerFactory.getLogger(SocAIService.class); - private final String SOCAI_PROCESS_URL; + private final String SOCAI_BASE_URL; + private final String SOCAI_ANALYZE_ENDPOINT = "/api/v1/analyze"; + private final OkHttpClient httpClient; - private final UtmAlertSocaiProcessingRequestService socaiProcessingRequestService; private final UtmModuleService moduleService; - public SocAIService(UtmAlertSocaiProcessingRequestService socaiProcessingRequestService, - UtmModuleService moduleService) { - this.socaiProcessingRequestService = socaiProcessingRequestService; + public SocAIService(UtmModuleService moduleService) { this.moduleService = moduleService; - SOCAI_PROCESS_URL = System.getenv("SOC_AI_BASE_URL"); + SOCAI_BASE_URL = System.getenv("SOC_AI_BASE_URL"); + this.httpClient = createTrustAllClient(); } - - public void sendData(Object data) { - final String ctx = CLASSNAME + ".sendData"; + /** + * Sends a complete alert to SOC-AI for analysis + */ + public void analyzeAlert(UtmAlert alert) { + final String ctx = CLASSNAME + ".analyzeAlert"; try { - OkHttpClient client = new OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) - .build(); + if (!StringUtils.hasText(SOCAI_BASE_URL)) { + throw new RuntimeException("SOC_AI_BASE_URL environment variable is not configured"); + } + + String internalKey = System.getenv(Constants.ENV_INTERNAL_KEY); + if (!StringUtils.hasText(internalKey)) { + throw new RuntimeException("INTERNAL_KEY environment variable is not configured"); + } + MediaType mediaType = MediaType.parse("application/json; charset=utf-8"); - RequestBody body = RequestBody.create(new Gson().toJson(data), mediaType); - Request request = new Request.Builder().url(SOCAI_PROCESS_URL).post(body) - .addHeader("Content-Type", "application/json").build(); + RequestBody body = RequestBody.create(new Gson().toJson(alert), mediaType); - try (Response rs = client.newCall(request).execute()) { - if (!rs.isSuccessful()) - throw new Exception(ctx + "Unexpected response: " + rs); + String url = SOCAI_BASE_URL + SOCAI_ANALYZE_ENDPOINT; + Request request = new Request.Builder() + .url(url) + .post(body) + .addHeader("Content-Type", "application/json") + .addHeader("X-Internal-Key", internalKey) + .build(); + + try (Response rs = httpClient.newCall(request).execute()) { + if (!rs.isSuccessful()) { + String responseBody = rs.body() != null ? rs.body().string() : "No response body"; + throw new Exception("Unexpected response: " + rs.code() + " - " + responseBody); + } } } catch (Exception e) { log.error(ctx + ": " + e.getLocalizedMessage()); @@ -59,43 +70,28 @@ public void sendData(Object data) { } } - /*@Scheduled(fixedDelay = 30000)*/ - public void sendRequests() { - final String ctx = CLASSNAME + ".sendRequests"; + private OkHttpClient createTrustAllClient() { try { - if (!moduleService.isModuleActive(ModuleName.SOC_AI)) - return; + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } + public void checkClientTrusted(X509Certificate[] certs, String authType) {} + public void checkServerTrusted(X509Certificate[] certs, String authType) {} + } + }; - if (!StringUtils.hasText(SOCAI_PROCESS_URL)) { - log.error(ctx + ": Environment variable SOC_AI_BASE_URL is missing or does not have a value"); - return; - } + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); - Page requests = socaiProcessingRequestService.findAll(PageRequest.of(0, 20)); - if (!requests.hasContent()) - return; - List ids = requests.getContent().stream().map(UtmAlertSocaiProcessingRequest::getAlertId) - .collect(Collectors.toList()); - try { - sendData(ids); - socaiProcessingRequestService.delete(ids); - } catch (Exception e) { - log.error(ctx + ": " + e.getLocalizedMessage()); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Async - public void requestSocAiProcess(List alertIds) { - final String ctx = CLASSNAME + ".requestSocAiProcess"; - try { - List ids = alertIds.stream().map(UtmAlertSocaiProcessingRequest::new) - .collect(Collectors.toList()); - socaiProcessingRequestService.saveAll(ids); + return new OkHttpClient.Builder() + .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0]) + .hostnameVerifier((hostname, session) -> true) + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build(); } catch (Exception e) { - throw new RuntimeException(ctx + ": " + e.getLocalizedMessage()); + throw new RuntimeException("Failed to create SSL client: " + e.getMessage()); } } } diff --git a/backend/src/main/java/com/park/utmstack/util/CipherUtil.java b/backend/src/main/java/com/park/utmstack/util/CipherUtil.java index 94ddad8f7..81d61db20 100644 --- a/backend/src/main/java/com/park/utmstack/util/CipherUtil.java +++ b/backend/src/main/java/com/park/utmstack/util/CipherUtil.java @@ -14,21 +14,32 @@ public class CipherUtil { private static final String CLASSNAME = "CipherUtil"; - private static SecretKeySpec secretKey; - private static IvParameterSpec iv; private static final String CIPHER_INSTANCE = "AES/CBC/PKCS5Padding"; + private static final int ITERATION_COUNT = 65536; + private static final int KEY_LENGTH = 128; - private static void setKey(String myKey) throws Exception { - final String ctx = CLASSNAME + "."; + private static class CryptoContext { + final SecretKeySpec secretKey; + final IvParameterSpec iv; + + CryptoContext(SecretKeySpec secretKey, IvParameterSpec iv) { + this.secretKey = secretKey; + this.iv = iv; + } + } + + private static CryptoContext getCryptoContext(String myKey) throws Exception { + final String ctx = CLASSNAME + ".getCryptoContext"; try { byte[] salt = myKey.getBytes(StandardCharsets.UTF_8); MessageDigest sha = MessageDigest.getInstance("SHA-1"); salt = sha.digest(salt); - KeySpec spec = new PBEKeySpec(myKey.toCharArray(), salt, 65536, 128); // AES-256 + KeySpec spec = new PBEKeySpec(myKey.toCharArray(), salt, ITERATION_COUNT, KEY_LENGTH); SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); byte[] key = f.generateSecret(spec).getEncoded(); - secretKey = new SecretKeySpec(key, "AES"); - iv = new IvParameterSpec(Arrays.copyOf(salt, 16)); + SecretKeySpec secretKey = new SecretKeySpec(key, "AES"); + IvParameterSpec iv = new IvParameterSpec(Arrays.copyOf(salt, 16)); + return new CryptoContext(secretKey, iv); } catch (Exception e) { throw new Exception(ctx + ": " + e.getMessage()); } @@ -37,9 +48,9 @@ private static void setKey(String myKey) throws Exception { public static String encrypt(String str, String secret) { final String ctx = CLASSNAME + ".encrypt"; try { - setKey(secret); + CryptoContext context = getCryptoContext(secret); Cipher cipher = Cipher.getInstance(CIPHER_INSTANCE); - cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); + cipher.init(Cipher.ENCRYPT_MODE, context.secretKey, context.iv); return Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8))); } catch (Exception e) { throw new RuntimeException(ctx + ": " + e.getMessage()); @@ -49,9 +60,9 @@ public static String encrypt(String str, String secret) { public static String decrypt(String str, String secret) { final String ctx = CLASSNAME + ".decrypt"; try { - setKey(secret); + CryptoContext context = getCryptoContext(secret); Cipher cipher = Cipher.getInstance(CIPHER_INSTANCE); - cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); + cipher.init(Cipher.DECRYPT_MODE, context.secretKey, context.iv); return new String(cipher.doFinal(Base64.getDecoder().decode(str))); } catch (Exception e) { throw new RuntimeException(ctx + ": " + e.getMessage()); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/AccountResource.java b/backend/src/main/java/com/park/utmstack/web/rest/AccountResource.java index 219c85241..5a1e21724 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/AccountResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/AccountResource.java @@ -1,28 +1,20 @@ package com.park.utmstack.web.rest; - import com.park.utmstack.aop.logging.AuditEvent; -import com.park.utmstack.aop.logging.Loggable; import com.park.utmstack.domain.User; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.repository.UserRepository; import com.park.utmstack.security.SecurityUtils; import com.park.utmstack.service.MailService; import com.park.utmstack.service.UserService; -import com.park.utmstack.service.application_events.ApplicationEventService; import com.park.utmstack.service.dto.PasswordChangeDTO; import com.park.utmstack.service.dto.UserDTO; -import com.park.utmstack.web.rest.errors.EmailAlreadyUsedException; -import com.park.utmstack.web.rest.errors.EmailNotFoundException; -import com.park.utmstack.web.rest.errors.InternalServerErrorException; -import com.park.utmstack.web.rest.errors.InvalidPasswordException; -import com.park.utmstack.web.rest.util.HeaderUtil; +import com.park.utmstack.service.application_events.ApplicationEventService; +import com.park.utmstack.web.rest.errors.*; import com.park.utmstack.web.rest.vm.KeyAndPasswordVM; import com.park.utmstack.web.rest.vm.ManagedUserVM; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; @@ -38,17 +30,19 @@ public class AccountResource { private static final String CLASSNAME = "AccountResource"; + private final Logger log = LoggerFactory.getLogger(AccountResource.class); private final UserRepository userRepository; + private final UserService userService; + private final MailService mailService; + private final ApplicationEventService applicationEventService; - public AccountResource(UserRepository userRepository, - UserService userService, - MailService mailService, - ApplicationEventService applicationEventService) { + public AccountResource(UserRepository userRepository, UserService userService, MailService mailService, ApplicationEventService applicationEventService) { + this.userRepository = userRepository; this.userService = userService; this.mailService = mailService; @@ -56,84 +50,65 @@ public AccountResource(UserRepository userRepository, } /** - * GET /authenticate : check if the user is authenticated, and return its login. + * {@code GET /authenticate} : check if the user is authenticated, and return its login. * * @param request the HTTP request * @return the login if the user is authenticated */ @GetMapping("/authenticate") - public ResponseEntity isAuthenticated(HttpServletRequest request) { - final String ctx = CLASSNAME + ".isAuthenticated"; - try { - String user = request.getRemoteUser(); - return StringUtils.hasText(user) ? ResponseEntity.ok(user) : ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(""); - } 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); - } + public String isAuthenticated(HttpServletRequest request) { + log.debug("REST request to check if the current user is authenticated"); + return request.getRemoteUser(); } /** - * GET /account : get the current user. + * {@code GET /account} : get the current user. * * @return the current user - * @throws RuntimeException 500 (Internal Server Error) if the user couldn't be returned + * @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be returned */ @GetMapping("/account") public UserDTO getAccount() { - final String ctx = CLASSNAME + ".getAccount"; - try { - return userService.getUserWithAuthorities() - .map(UserDTO::new) - .orElseThrow(() -> new InternalServerErrorException("User could not be found")); - } catch (InternalServerErrorException e) { - String msg = ctx + ": " + e.getMessage(); - log.error(msg); - applicationEventService.createEvent(msg, ApplicationEventType.ERROR); - throw new RuntimeException(msg); - } + return userService.getUserWithAuthorities() + .map(UserDTO::new) + .orElseThrow(() -> new InternalServerErrorException("User could not be found")); } /** - * POST /account : update the current user information. + * {@code POST /account} : update the current user information. * * @param userDTO the current user information - * @throws EmailAlreadyUsedException 400 (Bad Request) if the email is already used - * @throws RuntimeException 500 (Internal Server Error) if the user login wasn't found + * @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already used + * @throws RuntimeException {@code 500 (Internal Server Error)} if the user login wasn't found */ @PostMapping("/account") public void saveAccount(@Valid @RequestBody UserDTO userDTO) { - final String ctx = CLASSNAME + ".saveAccount"; - try { - String userLogin = SecurityUtils.getCurrentUserLogin().orElseThrow(() -> new InternalServerErrorException("Current user login not found")); - Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); - if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) { - throw new EmailAlreadyUsedException(); - } - Optional user = userRepository.findOneByLogin(userLogin); - if (user.isEmpty()) - throw new InternalServerErrorException("User could not be found"); - - userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(), - userDTO.getLangKey(), userDTO.getImageUrl()); - } catch (Exception e) { - String msg = ctx + ": " + e.getMessage(); - log.error(msg); - applicationEventService.createEvent(msg, ApplicationEventType.ERROR); - throw new RuntimeException(msg); + String userLogin = SecurityUtils.getCurrentUserLogin().orElseThrow(() -> new InternalServerErrorException("Current user login not found")); + Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()); + if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) { + throw new EmailAlreadyUsedException(); } + Optional user = userRepository.findOneByLogin(userLogin); + if (!user.isPresent()) { + throw new InternalServerErrorException("User could not be found"); + } + userService.updateUser(userDTO.getFirstName(), userDTO.getLastName(), userDTO.getEmail(), + userDTO.getLangKey(), userDTO.getImageUrl()); } /** - * POST /account/change-password : changes the current user's password + * {@code POST /account/change-password} : changes the current user's password. * * @param passwordChangeDto current and new password - * @throws InvalidPasswordException 400 (Bad Request) if the new password is incorrect + * @throws InvalidPasswordException {@code 400 (Bad Request)} if the new password is incorrect */ @PostMapping(path = "/account/change-password") + @AuditEvent( + attemptType = ApplicationEventType.PASSWORD_CHANGE_ATTEMPT, + attemptMessage = "Attempting to change current user's password", + successType = ApplicationEventType.PASSWORD_CHANGE_SUCCESS, + successMessage = "User's password changed successfully" + ) public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) { final String ctx = CLASSNAME + ".changePassword"; try { @@ -148,10 +123,10 @@ public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) { } /** - * POST /account/reset-password/init : Send an Email to reset the password of the user + * {@code POST /account/reset-password/init} : Send an Email to reset the password of the user. * * @param mail the mail of the user - * @throws EmailNotFoundException 400 (Bad Request) if the email address is not registered + * @throws EmailNotFoundException {@code 400 (Bad Request)} if the email address is not registered */ @PostMapping(path = "/account/reset-password/init") public void requestPasswordReset(@RequestBody String mail) { diff --git a/backend/src/main/java/com/park/utmstack/web/rest/UserResource.java b/backend/src/main/java/com/park/utmstack/web/rest/UserResource.java index 462d767df..b74256667 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/UserResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/UserResource.java @@ -1,8 +1,9 @@ package com.park.utmstack.web.rest; +import com.park.utmstack.aop.logging.AuditEvent; +import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.config.Constants; import com.park.utmstack.domain.User; -import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.repository.UserRepository; import com.park.utmstack.security.AuthoritiesConstants; import com.park.utmstack.security.SecurityUtils; @@ -93,6 +94,12 @@ public UserResource(UserService userService, */ @PostMapping("/users") @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + @AuditEvent( + attemptType = ApplicationEventType.USER_CREATION_ATTEMPT, + attemptMessage = "Attempting to create user {login}", + successType = ApplicationEventType.USER_CREATION_SUCCESS, + successMessage = "User {login} created successfully" + ) public ResponseEntity createUser(@Valid @RequestBody UserDTO userDTO) { final String ctx = CLASSNAME + ".createUser"; try { @@ -133,6 +140,12 @@ public ResponseEntity createUser(@Valid @RequestBody UserDTO userDTO) { */ @PutMapping("/users") @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + @AuditEvent( + attemptType = ApplicationEventType.USER_UPDATE_ATTEMPT, + attemptMessage = "Attempting to update user {login}", + successType = ApplicationEventType.USER_UPDATE_SUCCESS, + successMessage = "User {login} updated successfully" + ) public ResponseEntity updateUser(@Valid @RequestBody UserDTO userDTO) { final String ctx = CLASSNAME + ".updateUser"; try { diff --git a/backend/src/main/java/com/park/utmstack/web/rest/UtmServerModuleResource.java b/backend/src/main/java/com/park/utmstack/web/rest/UtmServerModuleResource.java index 0a36899f0..636e6e42b 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/UtmServerModuleResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/UtmServerModuleResource.java @@ -1,5 +1,6 @@ package com.park.utmstack.web.rest; +import com.park.utmstack.aop.logging.AuditEvent; import com.park.utmstack.domain.UtmServerModule; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.service.UtmServerModuleQueryService; @@ -56,6 +57,12 @@ public UtmServerModuleResource(UtmServerModuleService utmServerModuleService, * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/utm-server-modules") + @AuditEvent( + attemptType = ApplicationEventType.SERVER_MODULE_CREATE_ATTEMPT, + attemptMessage = "Attempting to create server module: {prettyName}", + successType = ApplicationEventType.SERVER_MODULE_CREATE_SUCCESS, + successMessage = "Server module {prettyName} created successfully" + ) public ResponseEntity createUtmServerModule(@RequestBody UtmServerModule utmServerModule) throws URISyntaxException { log.debug("REST request to save UtmServerModule : {}", utmServerModule); if (utmServerModule.getId() != null) { @@ -77,6 +84,12 @@ public ResponseEntity createUtmServerModule(@RequestBody UtmSer * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/utm-server-modules") + @AuditEvent( + attemptType = ApplicationEventType.SERVER_MODULE_UPDATE_ATTEMPT, + attemptMessage = "Attempting to update server module: {prettyName}", + successType = ApplicationEventType.SERVER_MODULE_UPDATE_SUCCESS, + successMessage = "Server module {prettyName} updated successfully" + ) public ResponseEntity updateUtmServerModule(@RequestBody UtmServerModule utmServerModule) throws URISyntaxException { log.debug("REST request to update UtmServerModule : {}", utmServerModule); if (utmServerModule.getId() == null) { @@ -135,6 +148,12 @@ public ResponseEntity getUtmServerModule(@PathVariable Long id) * @return the ResponseEntity with status 200 (OK) */ @DeleteMapping("/utm-server-modules/{id}") + @AuditEvent( + attemptType = ApplicationEventType.SERVER_MODULE_DELETE_ATTEMPT, + attemptMessage = "Attempting to delete server module with ID: {id}", + successType = ApplicationEventType.SERVER_MODULE_DELETE_SUCCESS, + successMessage = "Server module with ID {id} deleted successfully" + ) public ResponseEntity deleteUtmServerModule(@PathVariable Long id) { log.debug("REST request to delete UtmServerModule : {}", id); utmServerModuleService.delete(id); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/api_key/ApiKeyResource.java b/backend/src/main/java/com/park/utmstack/web/rest/api_key/ApiKeyResource.java index aa6b2052a..3ac87d736 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/api_key/ApiKeyResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/api_key/ApiKeyResource.java @@ -1,6 +1,8 @@ package com.park.utmstack.web.rest.api_key; +import com.park.utmstack.aop.logging.AuditEvent; +import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.domain.chart_builder.types.query.FilterType; import com.park.utmstack.security.AuthoritiesConstants; import com.park.utmstack.service.UserService; @@ -60,6 +62,12 @@ public class ApiKeyResource { }) }) @PostMapping + @AuditEvent( + attemptType = ApplicationEventType.API_KEY_CREATE_ATTEMPT, + attemptMessage = "Attempting to create API key: {name}", + successType = ApplicationEventType.API_KEY_CREATE_SUCCESS, + successMessage = "API key {name} created successfully" + ) public ResponseEntity createApiKey(@RequestBody ApiKeyUpsertDTO dto) { Long userId = userService.getCurrentUserLogin().getId(); ApiKeyResponseDTO responseDTO = apiKeyService.createApiKey(userId, dto); @@ -134,6 +142,12 @@ public ResponseEntity> listApiKeys(@ParameterObject Page }) }) @PutMapping("/{id}") + @AuditEvent( + attemptType = ApplicationEventType.CONFIG_UPDATE_ATTEMPT, + attemptMessage = "Attempting to update API key with ID: {id}", + successType = ApplicationEventType.CONFIG_UPDATE_SUCCESS, + successMessage = "API key with ID {id} updated successfully" + ) public ResponseEntity updateApiKey(@PathVariable("id") Long apiKeyId, @RequestBody ApiKeyUpsertDTO dto) { @@ -154,6 +168,12 @@ public ResponseEntity updateApiKey(@PathVariable("id") Long a }) }) @DeleteMapping("/{id}") + @AuditEvent( + attemptType = ApplicationEventType.API_KEY_DELETE_ATTEMPT, + attemptMessage = "Attempting to delete API key with ID: {id}", + successType = ApplicationEventType.API_KEY_DELETE_SUCCESS, + successMessage = "API key with ID {id} deleted successfully" + ) public ResponseEntity deleteApiKey(@PathVariable("id") Long apiKeyId) { Long userId = userService.getCurrentUserLogin().getId(); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleGroupResource.java b/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleGroupResource.java index a8090ad4d..3c7e179df 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleGroupResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/application_modules/UtmModuleGroupResource.java @@ -1,6 +1,7 @@ package com.park.utmstack.web.rest.application_modules; import com.park.utmstack.aop.logging.AuditEvent; +import com.park.utmstack.config.Constants; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.domain.application_modules.UtmModule; import com.park.utmstack.domain.application_modules.UtmModuleGroup; @@ -131,7 +132,19 @@ public ResponseEntity updateUtmConfigurationGroup(@Valid @Reques public ResponseEntity> getModuleGroups(@RequestParam Long moduleId) { final String ctx = CLASSNAME + ".getModuleGroups"; try { - return ResponseEntity.ok(moduleGroupService.findAllByModuleId(moduleId)); + List groups = moduleGroupService.findAllByModuleId(moduleId); + for (UtmModuleGroup group : groups) { + if (group.getModuleGroupConfigurations() != null) { + for (UtmModuleGroupConfiguration conf : group.getModuleGroupConfigurations()) { + if ((Constants.CONF_TYPE_PASSWORD.equals(conf.getConfDataType()) + || Constants.CONF_TYPE_FILE.equals(conf.getConfDataType())) + && conf.getConfValue() != null) { + conf.setConfValue(Constants.MASKED_VALUE); + } + } + } + } + return ResponseEntity.ok(groups); } catch (Exception e) { String msg = ctx + ": " + e.getMessage(); log.error(msg); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/UtmComplianceReportScheduleResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/UtmComplianceReportScheduleResource.java index c67e66573..d64d32c27 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/UtmComplianceReportScheduleResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/UtmComplianceReportScheduleResource.java @@ -1,5 +1,6 @@ package com.park.utmstack.web.rest.compliance; +import com.park.utmstack.aop.logging.AuditEvent; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.domain.compliance.UtmComplianceReportSchedule; import com.park.utmstack.repository.compliance.UtmComplianceReportScheduleRepository; @@ -62,6 +63,12 @@ public UtmComplianceReportScheduleResource( * @throws URISyntaxException if the Location URI syntax is incorrect. */ @PostMapping("/compliance-report-schedules") + @AuditEvent( + attemptType = ApplicationEventType.COMPLIANCE_SCHEDULE_CREATE_ATTEMPT, + attemptMessage = "Attempting to create compliance report schedule for report ID: {complianceId}", + successType = ApplicationEventType.COMPLIANCE_SCHEDULE_CREATE_SUCCESS, + successMessage = "Compliance report schedule for report ID {complianceId} created successfully" + ) public ResponseEntity createUtmComplianceReportSchedule( @Valid @RequestBody UtmComplianceReportSchedule utmComplianceReportSchedule ) throws URISyntaxException { @@ -95,6 +102,12 @@ public ResponseEntity createUtmComplianceReportSche * @throws URISyntaxException if the Location URI syntax is incorrect. */ @PutMapping("/compliance-report-schedules") + @AuditEvent( + attemptType = ApplicationEventType.CONFIG_UPDATE_ATTEMPT, + attemptMessage = "Attempting to update compliance report schedule with ID: {id}", + successType = ApplicationEventType.CONFIG_UPDATE_SUCCESS, + successMessage = "Compliance report schedule with ID {id} updated successfully" + ) public ResponseEntity updateUtmComplianceReportSchedule( @Valid @RequestBody UtmComplianceReportSchedule utmComplianceReportSchedule ) throws URISyntaxException { @@ -170,6 +183,12 @@ public ResponseEntity getUtmComplianceReportSchedul * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}. */ @DeleteMapping("/compliance-report-schedules/{id}") + @AuditEvent( + attemptType = ApplicationEventType.COMPLIANCE_SCHEDULE_DELETE_ATTEMPT, + attemptMessage = "Attempting to delete compliance report schedule with ID: {id}", + successType = ApplicationEventType.COMPLIANCE_SCHEDULE_DELETE_SUCCESS, + successMessage = "Compliance report schedule with ID {id} deleted successfully" + ) public ResponseEntity deleteUtmComplianceReportSchedule(@PathVariable Long id) { log.debug("REST request to delete UtmComplianceReportSchedule : {}", id); final String ctx = CLASSNAME + ".deleteUtmComplianceReportSchedule"; 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..25e792cda --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlConfigResource.java @@ -0,0 +1,99 @@ +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.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; +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-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 UtmComplianceControlConfigCriteriaService criteriaService; + private final ApplicationEventService applicationEventService; + + + public UtmComplianceControlConfigResource( + UtmComplianceControlConfigService controlService, + UtmComplianceControlConfigCriteriaService criteriaService, + ApplicationEventService applicationEventService + ) { + this.controlService = controlService; + this.criteriaService = criteriaService; + this.applicationEventService = applicationEventService; + } + + @PostMapping + public ResponseEntity createControl( + @RequestBody UtmComplianceControlConfigDto dto + ) { + var created = controlService.create(dto); + return ResponseEntity.ok(created); + } + + @GetMapping("/{id}") + public ResponseEntity getControl(@PathVariable Long id) { + var entity = controlService.findById(id); + if (entity == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(entity); + } + + @PutMapping("/{id}") + public ResponseEntity updateControl( + @PathVariable Long id, + @RequestBody UtmComplianceControlConfigDto dto + ) { + var updated = controlService.update(id, dto); + return ResponseEntity.ok(updated); + } + + @DeleteMapping("/{id}") + 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 = criteriaService.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/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/UtmComplianceControlLatestEvaluationResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java new file mode 100644 index 000000000..cf97559d0 --- /dev/null +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceControlLatestEvaluationResource.java @@ -0,0 +1,42 @@ +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 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.*; + +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, + @RequestParam(required = false) String search, + Pageable 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()); + } + + + @GetMapping("/get-by-id/{controlId}") + public ResponseEntity getControlLatestEvaluationById( + @PathVariable Long controlId) { + var control = latestEvaluationService.getControlWithLastEvaluation(controlId); + return ResponseEntity.ok(control); + } +} + diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceReportConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceReportConfigResource.java index acf3b2e63..bb36d6b75 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceReportConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceReportConfigResource.java @@ -1,5 +1,6 @@ package com.park.utmstack.web.rest.compliance.config; +import com.park.utmstack.aop.logging.AuditEvent; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.domain.compliance.UtmComplianceReportConfig; import com.park.utmstack.service.application_events.ApplicationEventService; @@ -60,6 +61,12 @@ public UtmComplianceReportConfigResource(UtmComplianceReportConfigService compli } @PostMapping("/report-config") + @AuditEvent( + attemptType = ApplicationEventType.CONFIG_UPDATE_ATTEMPT, + attemptMessage = "Attempting to create compliance report config: {configReportName}", + successType = ApplicationEventType.CONFIG_UPDATE_SUCCESS, + successMessage = "Compliance report config {configReportName} created successfully" + ) public ResponseEntity createComplianceReportConfig( @Valid @RequestBody UtmComplianceReportConfig complianceReportConfig) { final String ctx = CLASS_NAME + ".createComplianceReportConfig"; @@ -83,6 +90,12 @@ public ResponseEntity createComplianceReportConfig( } @PutMapping("/report-config") + @AuditEvent( + attemptType = ApplicationEventType.CONFIG_UPDATE_ATTEMPT, + attemptMessage = "Attempting to update compliance report config: {configReportName}", + successType = ApplicationEventType.CONFIG_UPDATE_SUCCESS, + successMessage = "Compliance report config {configReportName} updated successfully" + ) public ResponseEntity updateComplianceReportConfig( @Valid @RequestBody UtmComplianceReportConfig complianceReportConfig) { final String ctx = CLASS_NAME + ".updateComplianceReportConfig"; @@ -153,6 +166,12 @@ public ResponseEntity getComplianceReportConfig(@Path } @DeleteMapping("/report-config/{id}") + @AuditEvent( + attemptType = ApplicationEventType.CONFIG_GROUP_DELETE_ATTEMPT, + attemptMessage = "Attempting to delete compliance report config with ID: {id}", + successType = ApplicationEventType.CONFIG_GROUP_DELETE_SUCCESS, + successMessage = "Compliance report config with ID {id} deleted successfully" + ) public ResponseEntity deleteComplianceReportConfig(@PathVariable Long id) { final String ctx = CLASS_NAME + ".deleteComplianceReportConfig"; try { @@ -191,6 +210,12 @@ public ResponseEntity> getReportsByFilters(@Requ } @PostMapping("/report-config/import") + @AuditEvent( + attemptType = ApplicationEventType.REPORT_IMPORT_ATTEMPT, + attemptMessage = "Attempting to import compliance reports", + successType = ApplicationEventType.REPORT_IMPORT_SUCCESS, + successMessage = "Compliance reports imported successfully" + ) public ResponseEntity importReports(@Valid @RequestBody ImportReportsBody body) { final String ctx = CLASS_NAME + ".importReports"; try { diff --git a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceStandardResource.java b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceStandardResource.java index fb65ca4af..22f261851 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceStandardResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/compliance/config/UtmComplianceStandardResource.java @@ -1,5 +1,6 @@ package com.park.utmstack.web.rest.compliance.config; +import com.park.utmstack.aop.logging.AuditEvent; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.domain.compliance.UtmComplianceStandard; import com.park.utmstack.service.application_events.ApplicationEventService; @@ -47,6 +48,12 @@ public UtmComplianceStandardResource(UtmComplianceStandardService complianceStan } @PostMapping("/standard") + @AuditEvent( + attemptType = ApplicationEventType.COMPLIANCE_STANDARD_CREATE_ATTEMPT, + attemptMessage = "Attempting to create compliance standard: {standardName}", + successType = ApplicationEventType.COMPLIANCE_STANDARD_CREATE_SUCCESS, + successMessage = "Compliance standard {standardName} created successfully" + ) public ResponseEntity createComplianceStandard( @Valid @RequestBody UtmComplianceStandard complianceStandard) { final String ctx = CLASS_NAME + ".createComplianceStandard"; @@ -75,6 +82,12 @@ public ResponseEntity createComplianceStandard( } @PutMapping("/standard") + @AuditEvent( + attemptType = ApplicationEventType.CONFIG_UPDATE_ATTEMPT, + attemptMessage = "Attempting to update compliance standard: {standardName}", + successType = ApplicationEventType.CONFIG_UPDATE_SUCCESS, + successMessage = "Compliance standard {standardName} updated successfully" + ) public ResponseEntity updateComplianceStandard( @Valid @RequestBody UtmComplianceStandard complianceStandard) { final String ctx = CLASS_NAME + ".updateComplianceStandard"; @@ -132,6 +145,12 @@ public ResponseEntity getComplianceStandard(@PathVariable } @DeleteMapping("/standard/{id}") + @AuditEvent( + attemptType = ApplicationEventType.CONFIG_GROUP_DELETE_ATTEMPT, + attemptMessage = "Attempting to delete compliance standard with ID: {id}", + successType = ApplicationEventType.CONFIG_GROUP_DELETE_SUCCESS, + successMessage = "Compliance standard with ID {id} deleted successfully" + ) public ResponseEntity deleteComplianceStandard(@PathVariable Long id) { final String ctx = CLASS_NAME + ".deleteComplianceStandard"; try { diff --git a/backend/src/main/java/com/park/utmstack/web/rest/correlation/rules/UtmCorrelationRulesResource.java b/backend/src/main/java/com/park/utmstack/web/rest/correlation/rules/UtmCorrelationRulesResource.java index 63e313c67..d7d084378 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/correlation/rules/UtmCorrelationRulesResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/correlation/rules/UtmCorrelationRulesResource.java @@ -1,5 +1,6 @@ package com.park.utmstack.web.rest.correlation.rules; +import com.park.utmstack.aop.logging.AuditEvent; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.domain.correlation.rules.UtmCorrelationRules; import com.park.utmstack.domain.correlation.rules.UtmCorrelationRulesFilter; @@ -74,6 +75,12 @@ protected void initBinder(WebDataBinder binder) { * @return the {@link ResponseEntity} with status {@code 204 (No Content)}, with status {@code 400 (Bad Request)}, or with status {@code 500 (Internal)} if errors occurred. */ @PostMapping("/correlation-rule") + @AuditEvent( + attemptType = ApplicationEventType.CORRELATION_RULE_CREATE_ATTEMPT, + attemptMessage = "Attempting to create correlation rule: {name}", + successType = ApplicationEventType.CORRELATION_RULE_CREATE_SUCCESS, + successMessage = "Correlation rule {name} created successfully" + ) public ResponseEntity addCorrelationRule(@Valid @RequestBody UtmCorrelationRulesDTO utmCorrelationRulesDTO) { final String ctx = CLASSNAME + ".addCorrelationRule"; @@ -107,6 +114,12 @@ public ResponseEntity addCorrelationRule(@Valid @RequestBody UtmCorrelatio * @return the {@link ResponseEntity} with status {@code 204 (No Content)}, with status {@code 400 (Bad Request)}, or with status {@code 500 (Internal)} if errors occurred. */ @PutMapping("/correlation-rule/activate-deactivate") + @AuditEvent( + attemptType = ApplicationEventType.CORRELATION_RULE_UPDATE_ATTEMPT, + attemptMessage = "Attempting to change activation status for correlation rule with ID: {id}", + successType = ApplicationEventType.CORRELATION_RULE_UPDATE_SUCCESS, + successMessage = "Activation status for correlation rule with ID {id} changed successfully" + ) public ResponseEntity activateOrDeactivateCorrelationRule(@RequestParam Long id, @RequestParam Boolean active) { final String ctx = CLASSNAME + ".activateOrDeactivateCorrelationRule"; @@ -133,6 +146,12 @@ public ResponseEntity activateOrDeactivateCorrelationRule(@RequestParam Lo * @return the {@link ResponseEntity} with status {@code 204 (No Content)}, with status {@code 400 (Bad Request)}, or with status {@code 500 (Internal)} if errors occurred. */ @PutMapping("/correlation-rule") + @AuditEvent( + attemptType = ApplicationEventType.CORRELATION_RULE_UPDATE_ATTEMPT, + attemptMessage = "Attempting to update correlation rule: {name}", + successType = ApplicationEventType.CORRELATION_RULE_UPDATE_SUCCESS, + successMessage = "Correlation rule {name} updated successfully" + ) public ResponseEntity updateCorrelationRule(@Valid @RequestBody UtmCorrelationRulesDTO correlationRulesDTO) { final String ctx = CLASSNAME + ".updateCorrelationRule"; try { @@ -225,6 +244,12 @@ public ResponseEntity getRule(@PathVariable Long id) { * @return the {@link ResponseEntity} with status {@code 204 (No Content)}, with status {@code 400 (Bad Request)}, or with status {@code 500 (Internal)} if errors occurred. */ @DeleteMapping("/correlation-rule/{id}") + @AuditEvent( + attemptType = ApplicationEventType.CORRELATION_RULE_DELETE_ATTEMPT, + attemptMessage = "Attempting to delete correlation rule with ID: {id}", + successType = ApplicationEventType.CORRELATION_RULE_DELETE_SUCCESS, + successMessage = "Correlation rule with ID {id} deleted successfully" + ) public ResponseEntity removeCorrelationRule(@PathVariable Long id) { final String ctx = CLASSNAME + ".removeCorrelationRule"; try { diff --git a/backend/src/main/java/com/park/utmstack/web/rest/idp_provider/IdentityProviderConfigResource.java b/backend/src/main/java/com/park/utmstack/web/rest/idp_provider/IdentityProviderConfigResource.java index c8ca58691..a6ab0a320 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/idp_provider/IdentityProviderConfigResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/idp_provider/IdentityProviderConfigResource.java @@ -1,6 +1,8 @@ package com.park.utmstack.web.rest.idp_provider; +import com.park.utmstack.aop.logging.AuditEvent; +import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.domain.idp_provider.enums.ProviderType; import com.park.utmstack.service.dto.idp_provider.dto.*; import com.park.utmstack.service.idp_provider.IdentityProviderService; @@ -33,6 +35,12 @@ public class IdentityProviderConfigResource { private final IdentityProviderMapper mapper; @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @AuditEvent( + attemptType = ApplicationEventType.IDP_CONFIG_CREATE_ATTEMPT, + attemptMessage = "Attempting to create Identity Provider configuration: {name}", + successType = ApplicationEventType.IDP_CONFIG_CREATE_SUCCESS, + successMessage = "Identity Provider configuration {name} created successfully" + ) public ResponseEntity create(@RequestParam String name, @RequestParam String providerType, @RequestParam String metadataUrl, @@ -54,6 +62,12 @@ public ResponseEntity create(@RequestParam St @PutMapping("/{id}") + @AuditEvent( + attemptType = ApplicationEventType.IDP_CONFIG_UPDATE_ATTEMPT, + attemptMessage = "Attempting to update Identity Provider configuration with ID: {id}", + successType = ApplicationEventType.IDP_CONFIG_UPDATE_SUCCESS, + successMessage = "Identity Provider configuration with ID {id} updated successfully" + ) public ResponseEntity update(@PathVariable Long id, @RequestParam String name, @RequestParam String providerType, @@ -89,6 +103,12 @@ public ResponseEntity getById(@PathVariable L } @DeleteMapping("/{id}") + @AuditEvent( + attemptType = ApplicationEventType.IDP_CONFIG_DELETE_ATTEMPT, + attemptMessage = "Attempting to delete Identity Provider configuration with ID: {id}", + successType = ApplicationEventType.IDP_CONFIG_DELETE_SUCCESS, + successMessage = "Identity Provider configuration with ID {id} deleted successfully" + ) 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/incident_response/UTMIncidentCommandWebsocket.java b/backend/src/main/java/com/park/utmstack/web/rest/incident_response/UTMIncidentCommandWebsocket.java index b4bb8091c..bdcdf120d 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/incident_response/UTMIncidentCommandWebsocket.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/incident_response/UTMIncidentCommandWebsocket.java @@ -61,7 +61,7 @@ public void processCommand(@NotNull String command, @DestinationVariable @NotNul String commandVar = utmIncidentVariableService.replaceVariablesInCommand(commandVM.getCommand()); incidentResponseCommandService.sendCommand(String.valueOf(agentDTO.getId()), commandVar, commandVM.getOriginType(), - commandVM.getOriginId(), commandVM.getReason(), executedBy, new StreamObserver<>() { + commandVM.getOriginId(), commandVM.getReason(), executedBy, commandVM.getShell(), new StreamObserver<>() { @Override public void onNext(CommandResult value) { String output = utmIncidentVariableService.replaceSecretVariableValuesWithPlaceholders(value.getResult()); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/logstash_filter/UtmFilterResource.java b/backend/src/main/java/com/park/utmstack/web/rest/logstash_filter/UtmFilterResource.java index 12060773c..917253e11 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/logstash_filter/UtmFilterResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/logstash_filter/UtmFilterResource.java @@ -1,5 +1,6 @@ package com.park.utmstack.web.rest.logstash_filter; +import com.park.utmstack.aop.logging.AuditEvent; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; import com.park.utmstack.domain.logstash_filter.UtmLogstashFilter; import com.park.utmstack.domain.logstash_pipeline.UtmGroupLogstashPipelineFilters; @@ -62,6 +63,12 @@ public UtmFilterResource(UtmLogstashFilterService utmLogstashFilterService, * @return the ResponseEntity with status 201 (Created) and with body the new utmLogstashFilter, or with status 400 (Bad Request) if the utmLogstashFilter has already an ID */ @PostMapping + @AuditEvent( + attemptType = ApplicationEventType.LOGSTASH_FILTER_CREATE_ATTEMPT, + attemptMessage = "Attempting to create Logstash filter: {filterName}", + successType = ApplicationEventType.LOGSTASH_FILTER_CREATE_SUCCESS, + successMessage = "Logstash filter {filterName} created successfully" + ) public ResponseEntity createLogstashFilter(@Valid @RequestBody UtmLogstashFilter logstashFilter, @RequestParam Long pipelineId) { final String ctx = CLASSNAME + ".createLogstashFilter"; @@ -105,6 +112,12 @@ public ResponseEntity createLogstashFilter(@Valid @RequestBod * or with status 500 (Internal Server Error) if the utmLogstashFilter couldn't be updated */ @PutMapping + @AuditEvent( + attemptType = ApplicationEventType.LOGSTASH_FILTER_UPDATE_ATTEMPT, + attemptMessage = "Attempting to update Logstash filter: {filterName}", + successType = ApplicationEventType.LOGSTASH_FILTER_UPDATE_SUCCESS, + successMessage = "Logstash filter {filterName} updated successfully" + ) public ResponseEntity updateLogstashFilter(@Valid @RequestBody UtmLogstashFilter logstashFilter) { final String ctx = CLASSNAME + ".updateLogstashFilter"; try { @@ -197,6 +210,12 @@ public ResponseEntity getLogstashFilter(@PathVariable Long id * @return the ResponseEntity with status 200 (OK) */ @DeleteMapping("/{id}") + @AuditEvent( + attemptType = ApplicationEventType.LOGSTASH_FILTER_DELETE_ATTEMPT, + attemptMessage = "Attempting to delete Logstash filter with ID: {id}", + successType = ApplicationEventType.LOGSTASH_FILTER_DELETE_SUCCESS, + successMessage = "Logstash filter with ID {id} deleted successfully" + ) public ResponseEntity deleteLogstashFilter(@PathVariable Long id) { final String ctx = CLASSNAME + ".deleteLogstashFilter"; try { diff --git a/backend/src/main/java/com/park/utmstack/web/rest/soc_ai/UtmSocAiResource.java b/backend/src/main/java/com/park/utmstack/web/rest/soc_ai/UtmSocAiResource.java index 6f74e9b08..9b0b00a5b 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/soc_ai/UtmSocAiResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/soc_ai/UtmSocAiResource.java @@ -1,6 +1,7 @@ package com.park.utmstack.web.rest.soc_ai; import com.park.utmstack.domain.application_events.enums.ApplicationEventType; +import com.park.utmstack.domain.shared_types.alert.UtmAlert; import com.park.utmstack.service.application_events.ApplicationEventService; import com.park.utmstack.service.soc_ai.SocAIService; import com.park.utmstack.web.rest.AccountResource; @@ -25,23 +26,42 @@ public class UtmSocAiResource { private final ApplicationEventService applicationEventService; private final SocAIService socAIService; + public UtmSocAiResource(SocAIService socAIService, ApplicationEventService applicationEventService) { this.socAIService = socAIService; this.applicationEventService = applicationEventService; } - @PostMapping("/alerts") - public ResponseEntity sendData(@RequestBody String[] alertsId) { - final String ctx = CLASSNAME + ".sendAlertsIds"; + /** + * POST /api/soc-ai/analyze : Submit an alert for SOC-AI analysis + * + * @param alert the complete alert object to analyze + * @return status of the submission + */ + @PostMapping("/analyze") + public ResponseEntity analyzeAlert(@RequestBody UtmAlert alert) { + final String ctx = CLASSNAME + ".analyzeAlert"; try { - socAIService.sendData(alertsId); - return ResponseEntity.ok().body(Map.of("status", "success", "message", "Processing successful")); + if (alert == null || alert.getId() == null) { + return ResponseEntity.badRequest().body(Map.of("status", "error", "message", "Alert ID is required")); + } + + socAIService.analyzeAlert(alert); + return ResponseEntity.accepted().body(Map.of( + "status", "queued", + "alertId", alert.getId(), + "message", "Alert queued for SOC-AI analysis" + )); } catch (Exception e) { String msg = ctx + ": " + e.getMessage(); log.error(msg); applicationEventService.createEvent(msg, ApplicationEventType.ERROR); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("status", "error", "message", msg)); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of( + "status", "error", + "message", msg + )); } } + } diff --git a/backend/src/main/java/com/park/utmstack/web/rest/tfa/TfaResource.java b/backend/src/main/java/com/park/utmstack/web/rest/tfa/TfaResource.java index 03d612f7f..c7bbce553 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/tfa/TfaResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/tfa/TfaResource.java @@ -102,6 +102,12 @@ public ResponseEntity generateChallenge() { } @PostMapping("/complete") + @AuditEvent( + attemptType = ApplicationEventType.TFA_ENABLE_ATTEMPT, + attemptMessage = "Attempting to modify MFA configuration", + successType = ApplicationEventType.TFA_ENABLE_SUCCESS, + successMessage = "MFA configuration modified successfully" + ) public ResponseEntity completeTfa(@RequestBody TfaSaveRequest request) { final String ctx = CLASSNAME + ".completeTfa"; try { diff --git a/backend/src/main/java/com/park/utmstack/web/rest/vm/CommandVM.java b/backend/src/main/java/com/park/utmstack/web/rest/vm/CommandVM.java index f04a588da..a26038ffd 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/vm/CommandVM.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/vm/CommandVM.java @@ -12,6 +12,8 @@ public class CommandVM { @NotBlank String reason; + String shell; + public String getCommand() { return command; } @@ -43,4 +45,12 @@ public String getReason() { public void setReason(String reason) { this.reason = reason; } + + public String getShell() { + return shell; + } + + public void setShell(String shell) { + this.shell = 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; } + diff --git a/backend/src/main/resources/config/application-dev.yml b/backend/src/main/resources/config/application-dev.yml index 420dd0eb8..15c927ce7 100644 --- a/backend/src/main/resources/config/application-dev.yml +++ b/backend/src/main/resources/config/application-dev.yml @@ -29,7 +29,9 @@ spring: database: POSTGRESQL # For Postgresql database elasticsearch: # This configuration is for the elasticsearch health indicator, please do not remove rest: - uris: http://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT} + uris: https://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT} + username: ${ELASTICSEARCH_USER} + password: ${ELASTICSEARCH_PASSWORD} liquibase: contexts: dev mail: diff --git a/backend/src/main/resources/config/application-prod.yml b/backend/src/main/resources/config/application-prod.yml index 90c98cbba..33bacc55c 100644 --- a/backend/src/main/resources/config/application-prod.yml +++ b/backend/src/main/resources/config/application-prod.yml @@ -22,7 +22,9 @@ spring: database-platform: tech.jhipster.domain.util.FixedPostgreSQL10Dialect elasticsearch: # This configuration is for the elasticsearch health indicator, please do not remove rest: - uris: http://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT} + uris: https://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT} + username: ${ELASTICSEARCH_USER} + password: ${ELASTICSEARCH_PASSWORD} liquibase: contexts: prod mail: diff --git a/backend/src/main/resources/config/application.yml b/backend/src/main/resources/config/application.yml index f28e03ba0..610c42ef4 100644 --- a/backend/src/main/resources/config/application.yml +++ b/backend/src/main/resources/config/application.yml @@ -16,6 +16,8 @@ management: git: mode: full health: + elasticsearch: + enabled: false group: liveness: include: livenessState diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_config.xml new file mode 100644 index 000000000..be7522914 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260112002_create_table_compliance_control_config.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260112003_create_table_compliance_query_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260112003_create_table_compliance_query_config.xml new file mode 100644 index 000000000..bd8a032d0 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260112003_create_table_compliance_query_config.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/filters/filebeat/system_linux_module.yml b/backend/src/main/resources/config/liquibase/changelog/20260327001_update_linux_filter.xml similarity index 72% rename from filters/filebeat/system_linux_module.yml rename to backend/src/main/resources/config/liquibase/changelog/20260327001_update_linux_filter.xml index eaac62e6b..500513b41 100644 --- a/filters/filebeat/system_linux_module.yml +++ b/backend/src/main/resources/config/liquibase/changelog/20260327001_update_linux_filter.xml @@ -1,5 +1,19 @@ -# System Linux filter version 4.0.0 -# Support for systemd/journald JSON format from filebeat/journald + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331001_update_o365_sync_uploaded_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331001_update_o365_sync_uploaded_visualization.xml new file mode 100644 index 000000000..accea0244 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331001_update_o365_sync_uploaded_visualization.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331002_update_o365_filesync_downloaded_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331002_update_o365_filesync_downloaded_visualization.xml new file mode 100644 index 000000000..8f0c7379d --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331002_update_o365_filesync_downloaded_visualization.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331003_update_o365_ad_successful_login_location_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331003_update_o365_ad_successful_login_location_visualization.xml new file mode 100644 index 000000000..73c2e97c0 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331003_update_o365_ad_successful_login_location_visualization.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331004_update_o365_secure_link_operation_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331004_update_o365_secure_link_operation_visualization.xml new file mode 100644 index 000000000..53abe06fc --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331004_update_o365_secure_link_operation_visualization.xml @@ -0,0 +1,157 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331005_update_o365_mailitems_accessed_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331005_update_o365_mailitems_accessed_visualization.xml new file mode 100644 index 000000000..6672b3783 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331005_update_o365_mailitems_accessed_visualization.xml @@ -0,0 +1,181 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331006_update_o365_ad_unsuccessful_login_location_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331006_update_o365_ad_unsuccessful_login_location_visualization.xml new file mode 100644 index 000000000..89a95c644 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331006_update_o365_ad_unsuccessful_login_location_visualization.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331007_update_o365_sharing_set_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331007_update_o365_sharing_set_visualization.xml new file mode 100644 index 000000000..dd5bb6e0d --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331007_update_o365_sharing_set_visualization.xml @@ -0,0 +1,134 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331008_update_o365_file_access_and_activity_by_client_ip_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331008_update_o365_file_access_and_activity_by_client_ip_visualization.xml new file mode 100644 index 000000000..f93fa17c9 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331008_update_o365_file_access_and_activity_by_client_ip_visualization.xml @@ -0,0 +1,38 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331009_update_o365_file_renamed_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331009_update_o365_file_renamed_visualization.xml new file mode 100644 index 000000000..9a359f89f --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331009_update_o365_file_renamed_visualization.xml @@ -0,0 +1,194 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331010_update_o365_onedrive_file_download_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331010_update_o365_onedrive_file_download_visualization.xml new file mode 100644 index 000000000..55da49698 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331010_update_o365_onedrive_file_download_visualization.xml @@ -0,0 +1,182 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331011_update_o365_file_access_and_activity_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331011_update_o365_file_access_and_activity_visualization.xml new file mode 100644 index 000000000..58c9a892b --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331011_update_o365_file_access_and_activity_visualization.xml @@ -0,0 +1,182 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331012_update_o365_sharepoint_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331012_update_o365_sharepoint_visualization.xml new file mode 100644 index 000000000..b11b65577 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331012_update_o365_sharepoint_visualization.xml @@ -0,0 +1,98 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331013_update_o365_secure_link_operation_by_client_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331013_update_o365_secure_link_operation_by_client_visualization.xml new file mode 100644 index 000000000..69cfaa8d9 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331013_update_o365_secure_link_operation_by_client_visualization.xml @@ -0,0 +1,38 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331014_update_o365_email_access_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331014_update_o365_email_access_visualization.xml new file mode 100644 index 000000000..a22781f02 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331014_update_o365_email_access_visualization.xml @@ -0,0 +1,86 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331015_update_o365_exchange_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331015_update_o365_exchange_visualization.xml new file mode 100644 index 000000000..b4dbeb9a7 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331015_update_o365_exchange_visualization.xml @@ -0,0 +1,110 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331016_update_o365_sharing_link_operation_by_client_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331016_update_o365_sharing_link_operation_by_client_visualization.xml new file mode 100644 index 000000000..7a5afbd61 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331016_update_o365_sharing_link_operation_by_client_visualization.xml @@ -0,0 +1,39 @@ + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331017_update_o365_file_accessed_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331017_update_o365_file_accessed_visualization.xml new file mode 100644 index 000000000..2758124ad --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331017_update_o365_file_accessed_visualization.xml @@ -0,0 +1,121 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331018_update_o365_sharing_link_operation_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331018_update_o365_sharing_link_operation_visualization.xml new file mode 100644 index 000000000..a2bc47091 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331018_update_o365_sharing_link_operation_visualization.xml @@ -0,0 +1,158 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331019_update_o365_filesyncdownloadedfull_by_ip_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331019_update_o365_filesyncdownloadedfull_by_ip_visualization.xml new file mode 100644 index 000000000..b03fc75b2 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331019_update_o365_filesyncdownloadedfull_by_ip_visualization.xml @@ -0,0 +1,38 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260331020_update_o365_activity_visualization.xml b/backend/src/main/resources/config/liquibase/changelog/20260331020_update_o365_activity_visualization.xml new file mode 100644 index 000000000..41b699cc7 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260331020_update_o365_activity_visualization.xml @@ -0,0 +1,122 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260401001_update_windows_filter.xml b/backend/src/main/resources/config/liquibase/changelog/20260401001_update_windows_filter.xml new file mode 100644 index 000000000..74cf54278 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260401001_update_windows_filter.xml @@ -0,0 +1,3039 @@ + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260401002_update_window_rules.xml b/backend/src/main/resources/config/liquibase/changelog/20260401002_update_window_rules.xml new file mode 100644 index 000000000..712e76a70 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260401002_update_window_rules.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260401003_update_windows_rule_data_types.xml b/backend/src/main/resources/config/liquibase/changelog/20260401003_update_windows_rule_data_types.xml new file mode 100644 index 000000000..187b90883 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260401003_update_windows_rule_data_types.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260403001_update_socai_group_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260403001_update_socai_group_config.xml new file mode 100644 index 000000000..f063c39d4 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260403001_update_socai_group_config.xml @@ -0,0 +1,87 @@ + + + + + Refactor SOCAI configuration to support multi-provider presets and visibility rules + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260408001_add_module_id_to_utm_data_types.xml b/backend/src/main/resources/config/liquibase/changelog/20260408001_add_module_id_to_utm_data_types.xml new file mode 100644 index 000000000..6bc4cc16c --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260408001_add_module_id_to_utm_data_types.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260408002_seed_module_id_in_utm_data_types.xml b/backend/src/main/resources/config/liquibase/changelog/20260408002_seed_module_id_in_utm_data_types.xml new file mode 100644 index 000000000..3031ebd71 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260408002_seed_module_id_in_utm_data_types.xml @@ -0,0 +1,67 @@ + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260409001_add_shell_to_alert_response_rule.xml b/backend/src/main/resources/config/liquibase/changelog/20260409001_add_shell_to_alert_response_rule.xml new file mode 100644 index 000000000..751453a58 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260409001_add_shell_to_alert_response_rule.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/backend/src/main/resources/config/liquibase/changelog/20260409002_update_socai_config.xml b/backend/src/main/resources/config/liquibase/changelog/20260409002_update_socai_config.xml new file mode 100644 index 000000000..0b4f90987 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/changelog/20260409002_update_socai_config.xml @@ -0,0 +1,26 @@ + + + + + + UPDATE utm_module + SET module_description = 'SOC AI uses advanced language models to investigate Security Operations Center alerts by analyzing large volumes of data, identifying patterns, and providing insights into potential security incidents. By leveraging natural language processing capabilities, security analysts can efficiently triage alerts, prioritize threats, and gather contextual information to aid in incident response and remediation.', + module_icon = 'soc-ai.svg' + WHERE module_name = 'SOC_AI'; + + UPDATE utm_module_group_configuration + SET conf_visibility = '{"dependsOn": "utmstack.socai.provider", "values": ["custom"]}' + WHERE conf_key = 'utmstack.socai.url'; + + UPDATE utm_module_group_configuration + SET conf_visibility = '{"dependsOn": "utmstack.socai.provider", "values": ["anthropic", "custom"]}' + WHERE conf_key = 'utmstack.socai.maxTokens'; + + DELETE FROM utm_module_group_configuration + WHERE conf_key = 'utmstack.socai.key'; + + + diff --git a/backend/src/main/resources/config/liquibase/data/20260401/windows/utm_correlation_rules.sql b/backend/src/main/resources/config/liquibase/data/20260401/windows/utm_correlation_rules.sql new file mode 100644 index 000000000..f523000b1 --- /dev/null +++ b/backend/src/main/resources/config/liquibase/data/20260401/windows/utm_correlation_rules.sql @@ -0,0 +1,359 @@ +INSERT INTO public.utm_correlation_rules (id,rule_name,rule_confidentiality,rule_integrity,rule_availability,rule_category,rule_technique,rule_description,rule_references_def,rule_definition_def,rule_last_update,rule_active,system_owner,rule_adversary,rule_deduplicate_by_def,rule_after_events_def,rule_group_by_def) VALUES (1356,'Windows audit log was cleared',1,2,3,'Defense Evasion','T1070.001 - Indicator Removal: Clear Windows Event Logs','Detects when the Windows audit log (Security event log) has been cleared. Adversaries may clear event logs to remove evidence of an intrusion.','["https://attack.mitre.org/techniques/T1070/001/"]','equals("log.eventCode", 1102)','2026-04-01 17:58:34.362',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1357,'Windows: Possible Brute Force Attack',2,2,3,'Credential Access','T1110 - Brute Force','This rule is triggered when a pattern of repeated and rapid login attempts from the same IP address or source is detected. These login attempts may target specific user accounts or services in an attempt to crack passwords through automated brute force. The purpose of this rule is to identify possible malicious unauthorized access attempts and prevent a brute force attack against the system.','["https://attack.mitre.org/tactics/TA0006/","https://attack.mitre.org/techniques/T1110/"]','equals("log.eventCode", 4625)','2026-04-01 17:58:36.932',true,true,'origin','["origin.host","target.user"]','[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"log.eventCode","operator":"filter_term","value":"{{.log.eventCode}}"},{"field":"target.user.keyword","operator":"filter_term","value":"{{.target.user}}"}],"or":null,"within":"now-5m","count":10}]',NULL), (1358,'Windows: Multiple Logon Failure Followed by Logon Success',2,2,3,'Credential Access','T1110 - Brute Force','This rule is triggered when a sequence of multiple failed login attempts followed immediately by a successful login from the same IP address or source is detected. This unusual sequence of events may indicate a possible unauthorized access attempt using a brute force or password guessing technique. The purpose of this rule is to identify suspicious patterns of login activity and alert you to potential unauthorized access attempts.','["https://attack.mitre.org/tactics/TA0006/","https://attack.mitre.org/techniques/T1110/"]','equals("log.eventCode", 4624)','2026-04-01 17:58:39.500',true,true,'origin','["origin.ip","target.user"]','[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"log.eventCode","operator":"filter_term","value":4625},{"field":"target.user.keyword","operator":"filter_term","value":"{{.target.user}}"}],"or":null,"within":"now-5m","count":10}]',NULL), (1359,'Windows: LSASS Memory Dump Handle Access',2,3,3,'Credential Access','T1003.001 - OS Credential Dumping: LSASS Memory','Identifies handle requests for the Local Security Authority Subsystem Service (LSASS) object access with specific access masks that many tools with a capability to dump memory to disk use (0x1fffff, 0x1010, 0x120089). This rule is tool agnostic as it has been validated against a host of various LSASS dump tools such as SharpDump, Procdump, Mimikatz, Comsvcs etc. It detects this behavior at a low level and does not depend on a specific tool or dump file name.','["https://attack.mitre.org/tactics/TA0006/","https://attack.mitre.org/techniques/T1003/","https://attack.mitre.org/techniques/T1003/001/"]','equals("log.eventCode", 4656) && regexMatch("log.eventDataObjectName", "(:\\Windows\\System32\\lsass.exe|\\Device\\HarddiskVolume[A-Za-z?:\\]([A-Za-z?])?\\Windows\\System32\\lsass.exe)") && !regexMatch("log.eventDataProcessName", "(:\\Program Files\\(.+).exe|:\\Program Files (x86)\\(.+).exe|:\\Windows\\system32\\wbem\\WmiPrvSE.exe|:\\Windows\\System32\\dllhost.exe|:\\Windows\\System32\\svchost.exe|:\\Windows\\System32\\msiexec.exe|:\\ProgramData\\Microsoft\\Windows Defender\\(.+).exe|:\\Windows\\explorer.exe)") && oneOf("log.eventDataAccessMask", ["2097151", "4112", "1040", "1180185", "2031615"])','2026-04-01 17:58:41.906',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1360,'Windows: User logged using Remote Desktop Connection from loopback address, possible exploit over reverse tunneling using stolen credentials',3,2,1,'Credential Access','T1021.001 - Remote Services: Remote Desktop Protocol','Adversaries may use Valid Accounts to log into a computer using the Remote Desktop Protocol (RDP). The adversary may then perform actions as the logged-on user.','["https://attack.mitre.org/techniques/T1021/001/"]','equals("log.eventDataLogonType", "10") && oneOf("origin.ip", ["::1", "127.0.0.1"]) && oneOf("log.eventCode", [528, 540, 673, 4624, 4769])','2026-04-01 17:58:44.018',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1361,'Windows: Printer driver failed to load, possible remote code execution using PrinterNightmare exploit: CVE-2021-34527',3,2,1,'Lateral Movement','T1210 - Exploitation of Remote Services','Adversaries may exploit remote services to gain unauthorized access to internal systems once inside of a network. Exploitation of a software vulnerability occurs when an adversary takes advantage of a programming error in a program, service, or within the operating system software or kernel itself to execute adversary-controlled code. A common goal for post-compromise exploitation of remote services is for lateral movement to enable access to a remote system.','["https://attack.mitre.org/techniques/T1210/"]','equals("log.eventCode", 4663) && regexMatch("log.eventDataObjectName", "\\Windows\\System32\\spool\\drivers\\") && regexMatch("log.eventDataObjectName", "\\.(dll|exe)$") && !contains("log.eventDataProcessName", "spoolsv.exe")','2026-04-01 17:58:46.512',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1362,'Windows: Persistence via PowerShell profile',2,3,1,'Persistence','T1546.013 - Event Triggered Execution: PowerShell Profile','Identifies the creation or modification of a PowerShell profile. PowerShell profile is a script that is executed when PowerShell starts to customize the user environment, which can be abused by attackers to persist in a environment where PowerShell is common.','["https://attack.mitre.org/tactics/TA0003/","https://attack.mitre.org/techniques/T1098/002/"]','equals("log.eventCode", 4663) && regexMatch("log.eventDataObjectName", "(:\\Users\\.*\\Documents\\(WindowsPowerShell|PowerShell)\\.*profile\\.ps1$|:\\Windows\\System32\\WindowsPowerShell\\.*profile\\.ps1$)")','2026-04-01 17:58:49.133',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1363,'Windows: Suspicious PrintSpooler Service Executable File Creation',2,3,1,'Privilege Escalation','T1068 - Exploitation for Privilege Escalation','Detects attempts to exploit privilege escalation vulnerabilities related to the Print Spooler service. For more information refer to the following CVE''s - CVE-2020-1048, CVE-2020-1337 and CVE-2020-1300 and verify that the impacted system is patched','["https://attack.mitre.org/tactics/TA0004/","https://attack.mitre.org/techniques/T1068/"]','contains("log.eventDataProcessName", "spoolsv.exe") && !regexMatch("log.eventDataProcessPath", "^C:\\\\Windows\\\\System32\\\\spoolsv.exe$")','2026-04-01 17:58:51.519',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1364,'Windows: Suspicious Print Spooler SPL File Created',1,3,2,'Privilege Escalation','T1068 - Exploitation for Privilege Escalation','Detects attempts to exploit privilege escalation vulnerabilities related to the Print Spooler service including CVE-2020-1048 and CVE-2020-1337.','["https://attack.mitre.org/tactics/TA0004/","https://attack.mitre.org/techniques/T1068/"]','!regexMatch("log.eventDataProcessName", "(spoolsv.exe|printfilterpipelinesvc.exe|PrintIsolationHost.exe|splwow64.exe|msiexec.exe|poqexec.exe)") && regexMatch("log.eventDataObjectName", ":\\Windows\\System32\\spool\\PRINTERS\\") +','2026-04-01 17:58:54.019',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1365,'Windows: Possible ransomware attack detected. Multiple File Deletion.',1,3,2,'Impact','T1486 - Data Encrypted for Impact','Detects potential ransomware activity by monitoring multiple file write/modification events (Event ID 4663) with write access masks in user directories within a short timeframe. Modern ransomware typically encrypts files in-place rather than deleting them, making write access monitoring more effective than deletion monitoring alone.','["https://attack.mitre.org/tactics/TA0040/"]','equals("log.eventCode", 4663) && +oneOf("log.eventDataAccessMask", ["2", "4", "6"]) && +!(regexMatch("log.eventDataProcessName", "(?i).*(trustedinstaller|svchost|wuauclt|msiexec|windows10upgrade|setuphost|tiworker|dism).*")) && +regexMatch("log.eventDataObjectName", "(?i).*\\\\(users|documents|desktop|downloads|pictures|videos|music)\\\\.*") && +!(regexMatch("log.eventDataObjectName", "(?i).*(\\\\windows\\\\|\\\\program files|\\\\programdata\\\\|\\\\temp\\\\|\\\\appdata\\\\local\\\\temp|\\\\softwaredistribution\\\\|\\\\winsxs\\\\|\\\\logs\\\\|\\\\prefetch\\\\).*")) && +!(regexMatch("log.eventDataObjectName", "(?i).*\\.(tmp|log|etl|dmp|pf|evtx|cache|dat|bak)$")) && +regexMatch("log.eventDataObjectName", "(?i).*\\.(doc[x]?|xls[x]?|ppt[x]?|pdf|txt|jpg|jpeg|png|gif|bmp|mp4|avi|mp3|zip|rar|7z)$") +','2026-04-01 17:58:56.644',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"log.eventCode","operator":"filter_term","value":"4663"},{"field":"target.user.keyword","operator":"filter_term","value":"{{.target.user}}"}],"or":null,"within":"now-5m","count":50}]','["origin.ip","target.user"]');INSERT INTO public.utm_correlation_rules (id,rule_name,rule_confidentiality,rule_integrity,rule_availability,rule_category,rule_technique,rule_description,rule_references_def,rule_definition_def,rule_last_update,rule_active,system_owner,rule_adversary,rule_deduplicate_by_def,rule_after_events_def,rule_group_by_def) VALUES (1366,'Windows: Possible ransomware attack detected. Ransomware Note Creation.',3,3,2,'Impact','T1486 - Data Encrypted for Impact','Ransomware, is a type of malware that prevents users from accessing their system or personal files and requires payment of a ransom in order to gain access to them again. Identifies ransomware attempts. A known ransomware note file has been detected, potentially indicating an active ransomware infection.','["https://attack.mitre.org/tactics/TA0040/"]','equals("log.eventCode", 4663) && regexMatch("log.EventDataFileName", "(README_TO_RESTORE_FILES|INSTRUCTION_TO_GET_FILES_BACK|HOW_TO_DECRYPT_FILES|DECRYPT_INSTRUCTION|RECOVER_INSTRUCTION|RESTORE_FILES|READ_ME_NOW|YOUR_FILES_ARE_ENCRYPTED|IMPORTANT_INSTRUCTIONS|NOTICE|DECRYPT_YOUR_FILES|HOW_TO_RESTORE_FILES|HELP_DECRYPT|RECOVERY_FILE|RECOVER-FILES|INSTRUCTION)\\.(txt|html|php)$")','2026-04-01 17:58:59.193',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"log.eventCode","operator":"filter_term","value":"{{.log.eventCode}}"},{"field":"log.EventDataFileName.keyword","operator":"filter_term","value":"{{.log.EventDataFileName}}"}],"or":null,"within":"now-60s","count":5}]','["origin.ip","target.user"]'), (1367,'Windows: Possible ransomware attack detected. Unusual File Extensions.',3,3,3,'Impact','T1486 - Data Encrypted for Impact','Ransomware, is a type of malware that prevents users from accessing their system or personal files and requires payment of a ransom in order to gain access to them again. Identifies ransomware attempts. Files with unusual file extensions have been detected, potentially indicating encrypted files created by ransomware.','["https://attack.mitre.org/tactics/TA0040/"]','equals("log.eventCode", 4663) && regexMatch("log.eventDataFileName", "\\.(7z\\.encrypted|aaa|abcd|abtc|acc|aes256|aes_ni|aes256ctr|aes256encrypted|aes_gcm|ajp|alcatraz_locked|alfa|amnesia[1-9]?|amsi|apocalypse666|armadillo|arrow|asasin|asi|atom128|auditor|aurora|autoit|avastvirusinfo|avenger|av666|azero|barak|barrax|bart|beef|beetle|bip|bit|bitcoin|bl2r|blackblock|blackmail|blast|blind|bmw|boot|braincrypt[3-8]?|broken|btcware|budak|bull|buydecryptor|cakl|calipso|calum|carote|cats|cbf|cccmn|ccrypt|cerber[3-9]?|chifrator|chimera|ciphered|crypted|clover|cobra|codnat3|combo|comrade|conficker|coot|cpt|crash|crimson|cry|crypt\\d{3,4}|crypt38|crypt72|crypt888|cryptinfinite|cryptolocker|cryptowall|cryptxxx|crypz|csfr|csone|ctb[1-4]|ctb-locker|ctrsa|cryptowin|cube|dcrpt|ddtf|dr2|dragon|dried|druid|ducky|ecrpt|eeta|etr|ee|f[0-9]{3,4}|flock|grt|grt[0-9]+|grtlock|gwz|h3ll|hades|hakunamatata|hallucinating|happy|harmful|harrow|havoc|headdesk|helpdecrypt|hermes|hidden|hideous|hijack|hilda|hitler|hjg|hmpl|hrosas|hsdf|hushed|hwrm|ihsdj|ikarus|ikasir|ikayed|ill|imbtc|img|encrypted|improved|indrik|injected|innocent|insane|interesante|jungle|kaos|karl|katana|kimcilware|kin|kiratos|kiss|kjh|locked|locky|lokf|losers|lukitus|m3g4c0rtx|m4n1fest0|m4s4g3|maas|madmax|mafi|magic|maktub|malware|manamecrypt|mandelbrot|manic|matrix|max|md5|medusa|mega|melme|merry|mesmerize|metropolitan|mikey|mikibackup|milarepa.lotos@aol.com|mirror|mmnn|mole|monro|mosk|muslat|n1n1n1|nabr|napoleon|narrow|nasoh|nataniel|neitrino|neras|nlah|nosu|novasof|nozelesn|nuclear|nwa|nymaim|obelisk|off|offwhite|ogdo|omega|omerta|onion|ooss|opencode|openme|opqz|osiris|otx|p3rf0rm4|pabluk|pack14|packagetrackr@india.com|packrat|pahd|panda|pandemic|pandora|pansy|paradise|paris|paym3|paymer|payms|pcap|pclock|peet|pelikan|penis|petya|pewcrypt|phoenix|photominr|phobos|phps|pirated|pluto|po1|point|poop|potato|pr0tect|preppy|princesa|princess|prosper|prosperity|prq|pshy|pumas|pumax|pure|purple|purpler|pwnd|pysa|q9q9|qbtex|qiuu|qkkd|qscx|qtyop|quimera|r2d2|r5a|rabit|radman|raid10|rainbow|rakhni|rambo|ramses|rat|rcrypted|react|reactor|realtek|reaper|redlion|redmat|redrum|rekt|remk|removal|remsec|remy|renaming|revenge|rezuc|rhino|ribd|rich|rip|rire|rizonesoft@protonmail.ch|rk|rmdir|robinhood|rocke|rogue|roldat|rolin|ronzware|rosenquist|rotten|roza|rpcminer|rsalive|rumba|run|rxx|uak|udjvu|unlock92|unlckr|upd|urcp|usam|usbc|v8|vag|vandt|varasto|vault|vauw|vb|ve|vendetta|venom|veracrypt|versiegelt|veton|vhd|vindows|violate|virus|vivin|vk_677|vma|vmx|volcano|vorasto|vorphal|vos|vscrypt|vxl|w4b|wakanda|wannacash|wannacry|wanted|war|wasted|wcry|weapologize|webmafia|weird|weui|whatthefuck|whistler|white|whitenoise|whiterabbit|whorus|why!decryptor|wicked|wildfire|windows10|windows7|windows8|windowsupdate|winlock|wipe|wisconsin|wizard|wlu|woolger|worm|wormfubuki|wow|wpencrypt|wq!decryptor|wrui|wtg|x1881|x3m|xampug|xdata|xencrypt|xfiles|xhelper|xlr|xman|xmd|xmd|xtbl|xtbl|xtr|xtt|xtz|xyz|yakuza|yatron|ybn|year|yellow|yheq|yty|yuke|yxo|yyto|z3|zatrov|zax|zbot|zbt|zbt|zeppelin|zerber|zet|zet|zfj|zfj|zimbra|zip|zix|zlz|zobm|zoh|zorro|zphs)$")','2026-04-01 17:59:01.291',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"log.eventCode","operator":"filter_term","value":"4663"},{"field":"target.user.keyword","operator":"filter_term","value":"{{.target.user}}"}],"or":null,"within":"now-5m","count":20}]','["origin.ip","target.user"]'), (1368,'Windows: Remote File Download via Desktopimgdownldr Utility',2,3,1,'Command and Control','T1105 - Ingress Tool Transfer','Identifies the desktopimgdownldr utility being used to download a remote file. An adversary may use desktopimgdownldr to download arbitrary files as an alternative to certutil.','["https://attack.mitre.org/tactics/TA0011/","https://attack.mitre.org/techniques/T1105/"]','equals("log.eventCode", 4663) && contains("log.eventDataProcessName", "desktopimgdownldr.exe") && !regexMatch("log.eventDataObjectName", "(:\\Windows\\Web\\|:\\ProgramData\\Microsoft\\Windows\\SystemData\\)") && regexMatch("log.eventDataObjectName", "\\.(exe|dll|bat|ps1|zip|rar|7z)$")','2026-04-01 17:59:03.732',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1369,'Windows: New Windows Service Created to start from windows root path. Suspicious event as the binary may have been dropped using Windows Admin Shares',1,2,3,'Execution','T1021.002 - Remote Services: SMB/Windows Admin Shares','Adversaries may use Valid Accounts to interact with a remote network share using Server Message Block (SMB). The adversary may then perform actions as the logged-on user.','["https://attack.mitre.org/techniques/T1021/002/"]','regexMatch("log.eventDataImagePath", "(^%systemroot%\\(.+)\\(.+).exe)") && equals("log.eventCode", 7045) && oneOf("log.channel", ["system", "System"])','2026-04-01 17:59:06.525',true,true,'target',NULL,'[]','["origin.host","target.user"]'), (1370,'Windows: Suspicious Managed Code Hosting Process',3,3,2,'Defense Evasion','T1055 - Process Injection','Identifies a suspicious managed code hosting process which could indicate code injection or other form of suspicious code execution.','["https://attack.mitre.org/tactics/TA0005/","https://attack.mitre.org/techniques/T1055/"]','regexMatch("log.eventDataProcessName", "(wscript.exe|cscript.exe|mshta.exe|wmic.exe|regsvr32.exe|svchost.exe|dllhost.exe|cmstp.exe)")','2026-04-01 17:59:08.779',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"log.eventDataProcessName.keyword","operator":"filter_term","value":"{{.log.eventDataProcessName}}"},{"field":"log.eventDataProcessID","operator":"filter_term","value":"{{.log.eventDataProcessID}}"}],"or":null,"within":"now-5m","count":3}]','["origin.ip","target.user"]'), (1371,'Windows: UAC Bypass Attempt via Privileged IFileOperation COM Interface',1,3,2,'Privilege Escalation','T1548.002 - Abuse Elevation Control Mechanism: Bypass User Account Control','Identifies attempts to bypass User Account Control (UAC) via DLL side-loading. Attackers may attempt to bypass UAC to stealthily execute code with elevated permissions.','["https://attack.mitre.org/tactics/TA0004/","https://attack.mitre.org/techniques/T1548/002/"]','regexMatch("log.eventDataFileName", "(wow64log.dll|comctl32.dll|DismCore.dll|OskSupport.dll|duser.dll|Accessibility.ni.dll)") && regexMatch("log.eventDataProcessName", "(dllhost.exe|eventvwr.exe|computerdefaults.exe|sdclt.exe|fodhelper.exe|wsreset.exe|slui.exe)") && !regexMatch("log.eventDataFileName", "(C:\\\\Windows\\\\SoftwareDistribution\\\\|C:\\\\Windows\\\\WinSxS\\\\)")','2026-04-01 17:59:11.347',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1372,'Windows: Unusual File Modification by dns.exe',1,3,2,'Lateral Movement','T1210 - Exploitation of Remote Services','Identifies an unexpected file being modified by dns.exe, the process responsible for Windows DNS Server services, which may indicate activity related to remote code execution or other forms of exploitation.','["https://attack.mitre.org/tactics/TA0001/","https://attack.mitre.org/techniques/T1133/"]','equals("log.eventCode", 4663) && contains("log.eventDataProcessName", "dns.exe") && !regexMatch("log.eventDataFileName", "(dns\\.log$|\\.dns$|\\Windows\\System32\\dns\\)") && regexMatch("log.eventDataFileName", "\\.(dll|exe|bat|ps1|vbs)$")','2026-04-01 17:59:13.312',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1373,'Windows: Unusual Network Connection via DllHost or via RunDLL32',2,3,2,'Defense Evasion','T1218 - System Binary Proxy Execution','Identifies unusual instances of dllhost.exe making outbound network connections. This may indicate adversarial Command and Control activity. Identifies unusual instances of rundll32.exe making outbound network connections. This may indicate adversarial Command and Control activity.','["https://attack.mitre.org/tactics/TA0005/","https://attack.mitre.org/techniques/T1218/"]','regexMatch("log.eventDataProcessName", "(dllhost.exe|rundll32.exe)") && !inCIDR("origin.ip", "10.0.0.0/8") && !inCIDR("origin.ip", "172.16.0.0/12") && !inCIDR("origin.ip", "192.168.0.0/16") && !inCIDR("origin.ip", "127.0.0.0/8") && !inCIDR("origin.ip", "169.254.0.0/16") && !inCIDR("origin.ip", "198.18.0.0/15") && !inCIDR("origin.ip", "224.0.0.0/4") && !inCIDR("origin.ip", "240.0.0.0/4")','2026-04-01 17:59:16.116',true,true,'target',NULL,'[]','["origin.host","target.user"]'), (1374,'Windows: Unusual Process Network Connection',3,3,2,'Defense Evasion','Trusted Developer Utilities Proxy Execution','Identifies network activity from unexpected system applications. This may indicate adversarial activity as these applications are often leveraged by adversaries to execute code and evade detection.','["https://attack.mitre.org/tactics/TA0005/","https://attack.mitre.org/techniques/T1127/"]','regexMatch("log.eventDataProcessName", "(Microsoft.Workflow.Compiler.exe|bginfo.exe|cdb.exe|cmstp.exe|csi.exe|dnx.exe|fsi.exe|ieexec.exe|iexpress.exe|odbcconf.exe|rcsi.exe|xwizard.exe)")','2026-04-01 17:59:18.862',true,true,'origin',NULL,'[]','["origin.ip","target.user"]'), (1375,'ADFS Authentication Anomalies',3,2,2,'Defense Evasion, Persistence, Privilege Escalation, Initial Access','T1078 - Valid Accounts','Detects anomalous authentication attempts against Active Directory Federation Services (ADFS) including multiple failed attempts that could indicate password spraying or brute force attacks. This rule monitors for authentication failures, token validation failures, and other ADFS security events that may indicate malicious activity. + +Next Steps: +1. Review the source IP address and determine if it''s from a known/trusted location +2. Check for patterns of failed authentication attempts across multiple users +3. Examine ADFS audit logs for additional context around the authentication failures +4. Verify if the targeted user accounts are valid and active +5. Consider implementing IP-based blocking if malicious activity is confirmed +6. Review ADFS configuration for security hardening opportunities +7. Correlate with other authentication events across the domain +','["https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging","https://attack.mitre.org/techniques/T1078/"]','equals("log.providerName", "AD FS") && (equals("log.eventId", "411") || equals("log.eventId", "342") || equals("log.eventId", "516")) && contains("log.message", "token validation failed")','2026-04-01 17:59:21.713',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"origin.ip.keyword","operator":"filter_term","value":"{{.origin.ip}}"}],"or":null,"within":"now-10m","count":10}]','["origin.ip","target.user"]');INSERT INTO public.utm_correlation_rules (id,rule_name,rule_confidentiality,rule_integrity,rule_availability,rule_category,rule_technique,rule_description,rule_references_def,rule_definition_def,rule_last_update,rule_active,system_owner,rule_adversary,rule_deduplicate_by_def,rule_after_events_def,rule_group_by_def) VALUES (1376,'AdminSDHolder Abuse Detection',3,3,2,'Persistence, Privilege Escalation','T1098 - Account Manipulation','Detects modifications to the AdminSDHolder object which can be used for persistence by granting elevated privileges. The SDProp process propagates these permissions to protected groups every 60 minutes, making this a critical security event. + +Next Steps: +1. Immediately review the user account that performed the modification +2. Check if the modification was authorized and part of legitimate administrative activities +3. Examine the specific permissions that were changed on the AdminSDHolder object +4. Monitor for privilege escalation activities in the next 60 minutes (SDProp cycle) +5. Review all members of protected groups for unauthorized additions +6. Audit recent administrative activities by the same user account +7. Consider temporarily disabling the user account if unauthorized activity is suspected +','["https://attack.mitre.org/techniques/T1098/","https://adsecurity.org/?p=1906","https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory"]','oneOf("log.eventCode", ["4662", "5136", "4670"]) && +equals("log.channel", "Security") && +( + contains("log.eventDataObjectName", "CN=AdminSDHolder,CN=System") +) && +( + oneOf("log.eventDataOperationType", ["Object Access", "Write Property"]) || + oneOf("log.eventDataAccessMask", ["131072", "262144", "524288"]) +) && +!equals("log.eventDataSubjectUserName", "SYSTEM") +','2026-04-01 17:59:24.437',true,true,'origin',NULL,'[]','["lastEvent.log.eventDataObjectName","lastEvent.log.eventDataSubjectUserName"]'), (1377,'AS-REP Roasting Attack Detection',3,2,1,'Credential Access','T1558.004 - Steal or Forge Kerberos Tickets: AS-REP Roasting','Detects AS-REP Roasting attacks targeting accounts with Kerberos pre-authentication disabled. +Attackers request AS-REP messages encrypted with RC4 (0x17) for accounts that do not require +pre-authentication, enabling offline password cracking. This is a companion technique to Kerberoasting +and targets a different set of vulnerable accounts. + +Next Steps: +1. Identify accounts with pre-authentication disabled and evaluate business justification +2. Enable Kerberos pre-authentication on all identified accounts +3. Verify the requesting source IP is not a known attack tool +4. Reset passwords for targeted accounts using strong, complex passwords +5. Audit Active Directory for accounts with DONT_REQUIRE_PREAUTH flag +6. Monitor for subsequent credential usage from the requesting IP +','["https://attack.mitre.org/techniques/T1558/004/","https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4768","https://blog.harmj0y.net/activedirectory/roasting-as-reps/"]','equals("log.eventCode", "4768") && +equals("log.channel", "Security") && +equals("log.eventDataTicketEncryptionType", "23") && +equals("log.eventDataPreAuthType", "0") && +!regexMatch("target.user", "(?i)\\$$") && +exists("target.user") +','2026-04-01 17:59:27.203',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"origin.ip.keyword","operator":"filter_term","value":"{{.origin.ip}}"}],"or":null,"within":"now-15m","count":3}]','["origin.ip","origin.host"]'), (1378,'Certificate Services Abuse Detection',3,3,1,'Credential Access','T1558 - Steal or Forge Kerberos Tickets','Detects suspicious certificate requests and issuance that could indicate Golden Certificate attacks or unauthorized certificate generation for persistence. This rule monitors Windows Certificate Services events for potentially malicious certificate operations, particularly those involving machine accounts or anonymous logons that could be leveraged for persistence and privilege escalation. + +Next Steps: +1. Investigate the certificate request details including the requesting user/machine +2. Verify if the certificate request was legitimate and authorized +3. Check for any recent changes to Certificate Authority policies or templates +4. Review Certificate Authority logs for other suspicious certificate issuance +5. Examine the requesting host for signs of compromise +6. Consider revoking any suspicious certificates issued +7. Validate Certificate Authority security configurations and access controls +','["https://www.splunk.com/en_us/blog/security/breaking-the-chain-defending-against-certificate-services-abuse.html","https://attack.mitre.org/techniques/T1558/"]','(equals("log.eventId", "4886") || equals("log.eventId", "4887")) && equals("log.providerName", "Microsoft-Windows-Security-Auditing") && (contains("log.eventDataSubjectUserName", "$") || equals("log.eventDataSubjectUserName", "ANONYMOUS LOGON"))','2026-04-01 17:59:29.862',true,true,'origin',NULL,'[]','["lastEvent.log.eventDataSubjectUserName","origin.host"]'), (1379,'Golden Ticket Attack Detection',3,3,3,'Credential Access','T1558.001 - Steal or Forge Kerberos Tickets: Golden Ticket','Detects Golden Ticket attacks where adversaries forge Kerberos TGTs using the KRBTGT account +hash, granting unlimited domain access. The rule detects anomalous TGT usage patterns including +TGS requests with unusual encryption types, tickets with abnormally long lifetimes, and Kerberos +authentication from non-domain-controller sources for the KRBTGT service. + +Next Steps: +1. Immediately verify if the KRBTGT account password has been compromised +2. Reset the KRBTGT password TWICE to invalidate all existing tickets +3. Identify the source host and investigate for full domain compromise +4. Review all domain admin activity from the suspected timeframe +5. Check for DCSync or NTDS.dit extraction as precursor activities +6. Audit all privileged account access across the domain +7. Consider rebuilding the domain if compromise is confirmed +8. Implement Kerberos armoring and constrained delegation +','["https://attack.mitre.org/techniques/T1558/001/","https://adsecurity.org/?p=1640","https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4769"]','( + equals("log.eventCode", "4769") && + equals("log.channel", "Security") && + equals("log.eventDataServiceName", "krbtgt") && + !equals("log.eventDataStatus", "0") && + exists("origin.ip") +) || +( + equals("log.eventCode", "4768") && + equals("log.channel", "Security") && + !oneOf("log.eventDataTicketEncryptionType", ["18", "17"]) && + exists("target.user") && + !regexMatch("target.user", "(?i)\\$$") +) || +( + equals("log.eventCode", "4672") && + equals("log.channel", "Security") && + contains("log.eventDataPrivilegeList", "SeTcbPrivilege") && + !regexMatch("log.eventDataSubjectUserName", "(?i)^(SYSTEM|LOCAL SERVICE|NETWORK SERVICE)$") && + !regexMatch("log.eventDataSubjectUserName", "(?i)\\$$") +) +','2026-04-01 17:59:32.300',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"origin.host","operator":"filter_term","value":"{{.origin.host}}"}],"or":null,"within":"now-30m","count":3}]','["origin.host","target.user"]'), (1380,'Kerberoasting Attack Detection',3,2,1,'Credential Access','T1558.003 - Steal or Forge Kerberos Tickets: Kerberoasting','Detects Kerberoasting attacks where adversaries request Kerberos TGS tickets encrypted with RC4 (0x17) for +service accounts in order to crack them offline and obtain plaintext credentials. This is the most common +Active Directory credential theft technique used in real-world compromises. The rule monitors Event ID 4769 +(Kerberos Service Ticket Operations) for RC4 encryption requests while excluding machine accounts (ending in $) +and legitimate system services. + +Next Steps: +1. Identify the requesting user account and verify if this is authorized security testing +2. Check which service account SPNs were targeted for TGS requests +3. Review if the requesting account has been compromised +4. Audit all service accounts with SPNs for weak passwords +5. Consider implementing AES-only Kerberos encryption policies +6. Rotate passwords for targeted service accounts immediately +7. Enable Group Managed Service Accounts (gMSA) where possible +8. Monitor for follow-up lateral movement using obtained credentials +','["https://attack.mitre.org/techniques/T1558/003/","https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4769","https://adsecurity.org/?p=2293"]','equals("log.eventCode", "4769") && +equals("log.channel", "Security") && +equals("log.eventDataTicketEncryptionType", "23") && +!regexMatch("log.eventDataServiceName", "(?i)\\$$") && +!equals("log.eventDataServiceName", "krbtgt") && +!oneOf("log.eventDataTicketOptions", ["1082195968", "1082130432", "1082130432"]) && +exists("log.eventDataServiceName") +','2026-04-01 17:59:34.648',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"origin.ip.keyword","operator":"filter_term","value":"{{.origin.ip}}"}],"or":null,"within":"now-15m","count":3}]','["origin.ip","target.user"]'), (1381,'Process Masquerading Detection',2,3,2,'Defense Evasion','T1036.005 - Masquerading: Match Legitimate Name or Location','Detects executables masquerading as legitimate Windows system processes but running from +incorrect locations. For example, svchost.exe should only run from C:\Windows\System32, +and explorer.exe should only run from C:\Windows. Malware commonly uses legitimate process +names to avoid detection by analysts and automated tools. + +Next Steps: +1. Identify the actual file path of the masquerading process +2. Compare the file hash against known good versions of the legitimate binary +3. Check the digital signature of the suspicious executable +4. Analyze the executable in a sandbox environment +5. Review the parent process that launched the masquerading binary +6. Kill the suspicious process and quarantine the file +7. Search for other instances of the same file across the environment +','["https://attack.mitre.org/techniques/T1036/005/","https://www.elastic.co/blog/how-hunt-masquerade-ball","https://redcanary.com/threat-detection-report/techniques/masquerading/"]','(equals("log.eventCode", "4688") || equals("log.eventCode", "1")) && +( + ( + regexMatch("log.eventDataProcessName", "(?i)\\\\csrss\\.exe$") && + !regexMatch("log.eventDataProcessName", "(?i)^C:\\\\Windows\\\\(System32|SysWOW64)\\\\csrss\\.exe$") + ) || + ( + regexMatch("log.eventDataProcessName", "(?i)\\\\services\\.exe$") && + !regexMatch("log.eventDataProcessName", "(?i)^C:\\\\Windows\\\\System32\\\\services\\.exe$") + ) || + ( + regexMatch("log.eventDataProcessName", "(?i)\\\\smss\\.exe$") && + !regexMatch("log.eventDataProcessName", "(?i)^C:\\\\Windows\\\\System32\\\\smss\\.exe$") + ) || + ( + regexMatch("log.eventDataProcessName", "(?i)\\\\wininit\\.exe$") && + !regexMatch("log.eventDataProcessName", "(?i)^C:\\\\Windows\\\\System32\\\\wininit\\.exe$") + ) || + ( + regexMatch("log.eventDataProcessName", "(?i)\\\\explorer\\.exe$") && + !regexMatch("log.eventDataProcessName", "(?i)^C:\\\\Windows\\\\explorer\\.exe$") + ) || + ( + regexMatch("log.eventDataProcessName", "(?i)\\\\svchost\\.exe$") && + !regexMatch("log.eventDataProcessName", "(?i)^C:\\\\Windows\\\\(System32|SysWOW64)\\\\svchost\\.exe$") + ) || + ( + regexMatch("log.eventDataProcessName", "(?i)\\\\lsass\\.exe$") && + !regexMatch("log.eventDataProcessName", "(?i)^C:\\\\Windows\\\\System32\\\\lsass\\.exe$") + ) +) +','2026-04-01 17:59:37.207',true,true,'origin',NULL,'[]','["origin.host","target.user"]'), (1382,'NTDS.dit Extraction Attempt',3,3,1,'Credential Access','T1003.003 - OS Credential Dumping: NTDS','Detects attempts to access or copy the Active Directory domain database (NTDS.dit) which contains password hashes for all domain users. This is a critical indicator of credential theft attempts and potential domain compromise. + +Next Steps: +1. Immediately isolate the affected system to prevent further compromise +2. Review all recent activity from the source host and user account +3. Check for signs of lateral movement from this system +4. Verify integrity of domain controllers and examine recent administrative actions +5. Look for evidence of credential harvesting tools (ntdsutil, vssadmin, mimikatz) +6. Review privileged account usage and consider forcing password resets +7. Examine network traffic for data exfiltration attempts +8. Check backup systems and shadow copies for unauthorized access +9. Coordinate with incident response team for full forensic analysis +','["https://attack.mitre.org/techniques/T1003/003/","https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4663"]','oneOf("log.eventCode", ["4663", "4656"]) && +equals("log.channel", "Security") && +( + endsWith("log.eventDataObjectName", "\\ntds.dit") || + contains("log.eventDataObjectName", "\\NTDS\\") || + endsWith("log.eventDataProcessName", "\\ntdsutil.exe") || + endsWith("log.eventDataProcessName", "\\vssadmin.exe") +) && +!equals("log.eventDataAccessMask", "0") +','2026-04-01 17:59:40.079',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"origin.host","operator":"filter_term","value":"{{.origin.host}}"}],"or":null,"within":"now-30m","count":2}]','["origin.host","target.user"]'), (1383,'NTLM Authentication Downgrade Attack',3,3,1,'Defense Evasion','T1562.001 - Impair Defenses: Disable or Modify Tools','Detects NTLM authentication downgrade attacks via registry modifications to LMCompatibilityLevel, +NtlmMinClientSec, and NtlmMinServerSec. Attackers modify these registry values to weaken NTLM +authentication security, enabling credential interception, relay attacks, and offline cracking +of captured NTLM hashes. Downgrading to LM or NTLMv1 authentication makes credential theft +significantly easier. + +Next Steps: +1. Check the new registry value to determine the downgrade severity +2. LMCompatibilityLevel < 3 enables NTLMv1 which is trivially crackable +3. Identify the process and user that made the registry modification +4. Restore the registry values to enforce NTLMv2 (LMCompatibilityLevel = 5) +5. Review Group Policy for conflicting NTLM settings +6. Check for NTLM relay attacks following the downgrade +7. Audit network traffic for NTLMv1 authentication attempts +8. Consider disabling NTLM entirely where possible +','["https://attack.mitre.org/techniques/T1562/001/","https://www.praetorian.com/blog/ntlm-relaying-attacks/","https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/network-security-lan-manager-authentication-level"]','equals("log.eventCode", "4657") && +equals("log.channel", "Security") && +( + regexMatch("log.eventDataObjectName", "(?i)\\\\CurrentControlSet\\\\Control\\\\Lsa\\\\LMCompatibilityLevel") || + regexMatch("log.eventDataObjectName", "(?i)\\\\CurrentControlSet\\\\Control\\\\Lsa\\\\MSV1_0\\\\NtlmMinClientSec") || + regexMatch("log.eventDataObjectName", "(?i)\\\\CurrentControlSet\\\\Control\\\\Lsa\\\\MSV1_0\\\\NtlmMinServerSec") || + regexMatch("log.eventDataObjectName", "(?i)\\\\CurrentControlSet\\\\Control\\\\Lsa\\\\MSV1_0\\\\RestrictSendingNTLMTraffic") || + regexMatch("log.eventDataObjectName", "(?i)\\\\CurrentControlSet\\\\Control\\\\Lsa\\\\MSV1_0\\\\AuditReceivingNTLMTraffic") || + regexMatch("log.eventDataObjectName", "(?i)\\\\CurrentControlSet\\\\Services\\\\Netlogon\\\\Parameters\\\\RequireSignOrSeal") +) && +!regexMatch("log.eventDataSubjectUserName", "(?i)^(SYSTEM|TrustedInstaller)$") +','2026-04-01 17:59:42.451',true,true,'origin',NULL,'[]','["origin.host","target.user"]'), (1384,'Pass-the-Hash Attack Detection',3,3,2,'Lateral Movement','T1550.002 - Use Alternate Authentication Material: Pass the Hash','Detects Pass-the-Hash attacks by monitoring for NTLM authentication (Event ID 4624) with +LogonType 9 (NewCredentials) or LogonType 3 (Network) from unusual sources, combined with +the use of Seclogon service. Attackers use stolen NTLM hashes to authenticate without +knowing the plaintext password, commonly through tools like Mimikatz sekurlsa::pth, +Impacket, or CrackMapExec. + +Next Steps: +1. Identify the source IP and user account used for the NTLM authentication +2. Verify if the source host should be authenticating with NTLM to this target +3. Check for prior credential dumping activity on the source host +4. Review if the authentication was followed by lateral movement or data access +5. Reset the compromised account password and any related accounts +6. Implement NTLM restrictions via Group Policy where possible +7. Enable Windows Defender Credential Guard to protect NTLM hashes +','["https://attack.mitre.org/techniques/T1550/002/","https://www.sans.org/blog/pass-the-hash-attack-detection/","https://stealthbits.com/blog/how-to-detect-pass-the-hash-attacks/"]','( + equals("log.eventCode", "4624") && + equals("log.channel", "Security") && + equals("log.eventDataLogonType", "9") && + equals("log.eventDataAuthenticationPackageName", "Negotiate") && + !regexMatch("log.eventDataSubjectUserName", "(?i)^(SYSTEM|LOCAL SERVICE|NETWORK SERVICE|ANONYMOUS LOGON|-|\\$)") && + exists("target.user") && + !regexMatch("target.user", "(?i)\\$$") +) || +( + equals("log.eventCode", "4624") && + equals("log.channel", "Security") && + equals("log.eventDataLogonType", "3") && + equals("log.eventDataLmPackageName", "NTLM V1") && + exists("origin.ip") && + !equals("origin.ip", "-") && + !equals("origin.ip", "::1") && + !equals("origin.ip", "127.0.0.1") +) +','2026-04-01 17:59:45.498',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"origin.ip.keyword","operator":"filter_term","value":"{{.origin.ip}}"},{"field":"log.eventCode","operator":"filter_term","value":"4624"}],"or":null,"within":"now-30m","count":3}]','["origin.ip","origin.host","target.user"]'), (1385,'PowerShell Empire Detection',3,3,2,'Execution','T1059.001 - Command and Scripting Interpreter: PowerShell','Detects potential PowerShell Empire framework usage based on characteristic command patterns, obfuscation techniques, and encoded payloads commonly used by this post-exploitation framework. PowerShell Empire is a post-exploitation framework that uses PowerShell and Python agents to maintain persistence and execute commands on compromised systems. + +Next Steps: +1. Immediately isolate the affected host to prevent lateral movement +2. Analyze the complete PowerShell script block content for additional IOCs +3. Check for persistence mechanisms (scheduled tasks, registry entries, services) +4. Review network connections from the host for C2 communication +5. Examine process tree and parent processes that spawned PowerShell +6. Search for additional Empire artifacts across the environment +7. Reset credentials for any accounts used on the compromised system +8. Conduct memory analysis to identify injected code or payloads +9. Review recent user activity and file access patterns +10. Update endpoint detection rules based on specific Empire techniques observed +','["https://attack.mitre.org/techniques/T1059/001/","https://www.powershellempire.com/","https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_logging"]','(equals("log.eventCode", "4104") || equals("log.eventId", 4104)) && +equals("log.providerName", "Microsoft-Windows-PowerShell") && +( + contains("log.eventDataScriptBlockText", "System.Management.Automation.AmsiUtils") || + regexMatch("log.eventDataScriptBlockText", "(?i)(empire|invoke-empire|invoke-psempire)") || + regexMatch("log.eventDataScriptBlockText", "(?i)\\[System\\.Convert\\]::FromBase64String") || + regexMatch("log.eventDataScriptBlockText", "(?i)IEX\\s*\\(\\s*New-Object") || + regexMatch("log.eventDataScriptBlockText", "(?i)-enc\\s+[A-Za-z0-9+/=]{100,}") || + regexMatch("log.eventDataScriptBlockText", "(?i)\\$DoIt\\s*=\\s*@") || + regexMatch("log.eventDataScriptBlockText", "(?i)\\[System\\.Text\\.Encoding\\]::Unicode\\.GetString") || + contains("log.eventDataScriptBlockText", "Invoke-Shellcode") || + contains("log.eventDataScriptBlockText", "Invoke-ReflectivePEInjection") || + contains("log.eventDataScriptBlockText", "Invoke-Mimikatz") +) +','2026-04-01 17:59:47.795',true,true,'origin',NULL,'[]','["origin.host","target.user"]');INSERT INTO public.utm_correlation_rules (id,rule_name,rule_confidentiality,rule_integrity,rule_availability,rule_category,rule_technique,rule_description,rule_references_def,rule_definition_def,rule_last_update,rule_active,system_owner,rule_adversary,rule_deduplicate_by_def,rule_after_events_def,rule_group_by_def) VALUES (1386,'RDP Brute Force Attack',3,2,2,'Credential Access','T1110.001 - Brute Force: Password Guessing','Detects multiple failed RDP login attempts from the same source IP address, indicating a potential brute force attack. This rule monitors Windows Event ID 4625 (failed logon) with focus on network logon types (type 3) which are commonly used for RDP connections. The rule triggers when 10 or more failed attempts occur from the same IP within 15 minutes. + +Next Steps: +1. Investigate the source IP address for malicious indicators and geolocation +2. Check if the targeted user accounts are legitimate and active +3. Review successful logons from the same IP after failed attempts +4. Implement IP blocking or rate limiting for the source address +5. Enable account lockout policies if not already configured +6. Consider implementing multi-factor authentication for RDP access +7. Review RDP access logs for any successful connections during the attack timeframe +','["https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4625","https://attack.mitre.org/techniques/T1110/001/"]','equals("log.eventCode", "4625") && equals("log.eventDataLogonType", "3") && exists("origin.ip") && !equals("origin.ip", "-") && !equals("origin.ip", "::1") && !equals("origin.ip", "127.0.0.1")','2026-04-01 17:59:50.462',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"origin.ip.keyword","operator":"filter_term","value":"{{.origin.ip}}"},{"field":"log.eventCode","operator":"filter_term","value":"4625"},{"field":"log.eventDataLogonType","operator":"filter_term","value":"3"}],"or":null,"within":"now-15m","count":10}]','["origin.ip","target.host"]'), (1387,'SAM Database Access Attempt',3,3,1,'Credential Access','T1003.002 - OS Credential Dumping: Security Account Manager','Detects attempts to access the Security Account Manager (SAM) database, which contains local user account hashes. This activity may indicate credential dumping attempts by attackers trying to extract password hashes for offline cracking or lateral movement. + +Next Steps: +1. Immediately investigate the user account and process that accessed the SAM database +2. Check for any unusual processes running on the affected system +3. Review recent logon events and privilege escalation activities +4. Examine network connections from the affected host for lateral movement +5. Consider isolating the affected system if malicious activity is confirmed +6. Review security policies for SAM database access permissions +7. Check for presence of credential dumping tools or suspicious files +','["https://attack.mitre.org/techniques/T1003/002/","https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4661"]','equals("log.eventCode", "4663") && +equals("log.channel", "Security") && +( + endsWith("log.eventDataObjectName", "\\SAM") || + endsWith("log.eventDataObjectName", "\\SECURITY") || + endsWith("log.eventDataObjectName", "\\SYSTEM") +) && +oneOf("log.eventDataAccessMask", ["131097", "2032127", "64", "32", "1"]) +','2026-04-01 17:59:53.256',true,true,'origin',NULL,'[]','["origin.host","target.user"]'), (1388,'SID History Injection Attempt',3,3,1,'Defense Evasion, Privilege Escalation','T1134.005 - Access Token Manipulation: SID-History Injection','Detects attempts to add SID History to an account, which can be used for privilege escalation. SID History injection allows attackers to inherit permissions from privileged accounts without being members of privileged groups. Both successful (4765) and failed (4766) attempts are monitored. + +Next Steps: +1. Immediately investigate the target user account and verify if SID History modification was legitimate +2. Check if the user performing the action has proper administrative privileges for this operation +3. Review the source SID being added to understand what permissions are being inherited +4. Examine recent authentication logs for the target account to identify potential unauthorized access +5. Verify Active Directory configuration and check for signs of domain controller compromise +6. Consider resetting the target account password and removing unauthorized SID History entries +7. Review domain administrator accounts and privileged group memberships for anomalies +','["https://attack.mitre.org/techniques/T1134/005/","https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4765","https://learn.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4766","https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventid=4765"]','oneOf("log.eventId", ["4765", "4766"]) && +equals("log.channel", "Security") +','2026-04-01 17:59:55.635',true,true,'origin',NULL,'[]','["origin.host","target.user"]'), (1389,'Silver Ticket Attack Detection',3,3,2,'Credential Access','T1558.002 - Steal or Forge Kerberos Tickets: Silver Ticket','Detects Silver Ticket attacks where adversaries forge Kerberos TGS tickets using a service +account''s NTLM hash, bypassing the KDC entirely. Unlike Golden Tickets, Silver Tickets target +specific services. The rule detects TGS tickets presented without corresponding TGT requests, +and service access events with anomalous Kerberos authentication patterns. + +Next Steps: +1. Identify the targeted service and its associated service account +2. Verify if the service account hash has been compromised via Kerberoasting +3. Reset the targeted service account password immediately +4. Review access logs for the targeted service for unauthorized activity +5. Check for prior Kerberoasting activity targeting the same service SPN +6. Investigate the source host for compromise indicators +7. Implement AES-only encryption for service accounts +8. Enable Kerberos PAC validation on the targeted services +','["https://attack.mitre.org/techniques/T1558/002/","https://adsecurity.org/?p=2011","https://www.sans.org/blog/kerberos-in-the-crosshairs-golden-tickets-silver-tickets-mitm-and-more/"]','equals("log.eventCode", "4769") && +equals("log.channel", "Security") && +( + equals("log.eventDataTicketEncryptionType", "23") && + !regexMatch("log.eventDataServiceName", "(?i)(krbtgt|\\$$)") && + !oneOf("log.eventDataStatus", ["0", "6"]) && + exists("origin.ip") +) +','2026-04-01 17:59:58.404',true,true,'origin',NULL,'[{"indexPattern":"v11-log-wineventlog-*","with":[{"field":"origin.ip.keyword","operator":"filter_term","value":"{{.origin.ip}}"}],"or":null,"within":"now-15m","count":5}]','["origin.ip","origin.host"]'), (1390,'SMBv1 Usage Detection',3,2,2,'Lateral Movement','T1210 - Exploitation of Remote Services','Detects usage of the deprecated and vulnerable SMBv1 protocol which could be exploited for lateral movement or ransomware propagation. SMBv1 is susceptible to numerous security vulnerabilities including EternalBlue and should be disabled in favor of SMBv2/SMBv3. + +Next Steps: +1. Immediately investigate the source system using SMBv1 and identify which service or application is still dependent on this protocol +2. Review network traffic logs to determine if this is internal communication or external access attempts +3. Check for any signs of exploitation attempts or successful compromises on the affected system +4. Identify all systems in the environment that may still have SMBv1 enabled +5. Plan migration to SMBv2/SMBv3 and disable SMBv1 on all systems where possible +6. Monitor for any lateral movement patterns that may indicate ongoing compromise +7. Consider implementing network segmentation to limit exposure if SMBv1 cannot be immediately disabled +','["https://learn.microsoft.com/en-us/windows-server/storage/file-server/troubleshoot/detect-enable-and-disable-smbv1-v2-v3","https://attack.mitre.org/techniques/T1210/"]','equals("log.eventId", "3000") && equals("log.providerName", "Microsoft-Windows-SMBServer") && contains("log.message", "SMB1")','2026-04-01 18:00:00.954',true,true,'origin',NULL,'[]','["origin.host","origin.ip"]'), (1391,'Windows Remote Management (WinRM) Abuse',3,3,2,'Lateral Movement','T1021.006 - Remote Services: Windows Remote Management','Detects potential abuse of Windows Remote Management (WinRM) for lateral movement. Monitors for successful logon events (4624) with network logon type 3 combined with privilege escalation (4672) and WinRM-related process activity, indicating remote command execution via WinRM. + +Next Steps: +1. Investigate the source IP address and verify if it''s an authorized administrative workstation +2. Review the target user account for any signs of compromise or unusual privilege usage +3. Examine recent PowerShell execution logs and command history on the target system +4. Check for concurrent suspicious activities from the same source IP across other systems +5. Verify if the WinRM connection aligns with scheduled maintenance or authorized administrative tasks +6. Review network traffic patterns between source and target systems for data exfiltration indicators +7. Validate the legitimacy of any processes spawned through the WinRM session +8. Consider implementing additional monitoring for WinRM usage if this represents unexpected activity +','["https://jpcertcc.github.io/ToolAnalysisResultSheet/details/WinRM.htm","https://attack.mitre.org/techniques/T1021/006/"]','equals("log.eventCode", "4624") && equals("log.eventDataLogonType", "3") && exists("log.eventDataProcessName") && (contains("log.eventDataProcessName", "wsmprovhost.exe") || contains("log.eventDataProcessName", "winrshost.exe") || contains("log.eventDataProcessName", "powershell.exe"))','2026-04-01 18:00:03.807',true,true,'origin',NULL,'[]','["target.user","origin.host","origin.ip"]'); + diff --git a/backend/src/main/resources/config/liquibase/data/20260401/windows/utm_group_rules_data_types.sql b/backend/src/main/resources/config/liquibase/data/20260401/windows/utm_group_rules_data_types.sql new file mode 100644 index 000000000..368f1da7a --- /dev/null +++ b/backend/src/main/resources/config/liquibase/data/20260401/windows/utm_group_rules_data_types.sql @@ -0,0 +1,108 @@ +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1356, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1357, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1358, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1359, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1360, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1361, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1362, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1363, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1364, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1365, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1366, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1367, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1368, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1369, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1370, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1371, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1372, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1373, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1374, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1375, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1376, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1377, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1378, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1379, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1380, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1381, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1382, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1383, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1384, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1385, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1386, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1387, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1388, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1389, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1390, 1); +INSERT INTO public.utm_group_rules_data_type +(rule_id, data_type_id) +VALUES(1391, 1); diff --git a/backend/src/main/resources/config/liquibase/master.xml b/backend/src/main/resources/config/liquibase/master.xml index 86c16ca8f..eebe85f8c 100644 --- a/backend/src/main/resources/config/liquibase/master.xml +++ b/backend/src/main/resources/config/liquibase/master.xml @@ -301,6 +301,10 @@ + + + + @@ -537,6 +541,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/filters/antivirus/checkpoint.yml b/filters/antivirus/checkpoint.yml deleted file mode 100644 index f6a5c1a4a..000000000 --- a/filters/antivirus/checkpoint.yml +++ /dev/null @@ -1,49 +0,0 @@ -pipeline: - - dataTypes: - - antivirus-checkpoint - steps: - # 1. Parse header to extract the payload inside brackets - - grok: - source: raw - patterns: - - fieldName: log.header - pattern: '{{.data}} - \[' - - fieldName: log.payload - pattern: '{{.data}}' - - fieldName: log.footer - pattern: '; \]' - - # 2. Parse the payload as Key-Value pairs - - kv: - source: log.payload - fieldSplit: " " - valueSplit: ":" - - # 3. Clean up quotes from values (since we don't have trim_value in kv) - # We would need a trim step for every field, but since we don't know all dynamic fields, - # we assume the KV parser handles basic quotes or we accept them. - # However, Logstash config suggests fields might be quoted like field:"value". - # The CEL-based KV step usually handles standard formats. - - # 4. Standard Reference Mapping - - rename: - from: [log.src] - to: origin.ip - - rename: - from: [log.dst] - to: target.ip - - rename: - from: [log.s_port] - to: origin.port - - rename: - from: [log.service] - to: target.port - - # 5. Type Casting - - cast: - fields: [origin.port, target.port] - to: int - - # 6. Clean up - - delete: - fields: [log.header, log.footer] diff --git a/filters/deceptivebytes/deceptive-bytes.yml b/filters/antivirus/deceptive-bytes.yml similarity index 100% rename from filters/deceptivebytes/deceptive-bytes.yml rename to filters/antivirus/deceptive-bytes.yml diff --git a/filters/filebeat/apache_module.yml b/filters/filebeat/apache_module.yml deleted file mode 100644 index 9ec5ad46f..000000000 --- a/filters/filebeat/apache_module.yml +++ /dev/null @@ -1,230 +0,0 @@ -# Apache filter, version 3.0.3 -# Compatible with Common Apache Log and Combined Apache Log. See: https://httpd.apache.org/docs/2.2/logs.html -#Filter Input requirements -> fileset: datatype -# access: plain text -# 1. Parsing the json from beats -# 2. Parsing the message field containing the apache log -pipeline: - - dataTypes: - - apache - steps: - - json: - source: raw - - rename: - from: - - log.url - to: origin.url - - rename: - from: - - log.log.file.path - to: origin.file - - rename: - from: - - log.host.ip - to: log.local.ips - - rename: - from: - - log.host.mac - to: log.local.macs - - rename: - from: - - log.host.hostname - to: origin.host - - rename: - from: - - log.event.dataset - to: action - - rename: - from: - - log.agent.version - to: log.agentVersion - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - rename: - from: - - log.host.os.type - to: log.osType - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - cast: - to: '[]string' - fields: - - log.local.ips - - cast: - to: '[]string' - fields: - - log.local.macs - # Common apache log parsing - - grok: - patterns: - - fieldName: origin.ip - pattern: '{{.ipv4}}|{{.ipv6}}' - - fieldName: log.userIdent - pattern: '{{.word}}|(-)' - - fieldName: origin.user - pattern: '{{.word}}|(-)' - - fieldName: deviceTime - pattern: '\[{{.data}}\]' - - fieldName: log.request - pattern: '\"{{.data}}\"' - - fieldName: log.statusCode - pattern: '{{.integer}}' - - fieldName: log.rest - pattern: '{{.greedy}}' - source: log.message - # Parsing Common and Combined end of apache log - # Common - - grok: - patterns: - - fieldName: origin.bytesReceived - pattern: '{{.integer}}|(-)' - source: log.rest - # Combined - - grok: - patterns: - - fieldName: origin.bytesReceived - pattern: '{{.integer}}|(-)' - - fieldName: log.referer - pattern: '\"{{.data}}\"' - - fieldName: log.userAgent - pattern: '\"(.*)\"' - source: log.rest - - trim: - function: prefix - substring: '[' - fields: - - deviceTime - - trim: - function: suffix - substring: ']' - fields: - - deviceTime - - trim: - function: prefix - substring: '"' - fields: - - log.request - - log.referer - - log.userAgent - - trim: - function: suffix - substring: '"' - fields: - - log.request - - log.referer - - log.userAgent - # Extracting request parts - - grok: - patterns: - - fieldName: log.method - pattern: '{{.word}}' - - fieldName: "origin.path" - pattern: '(.*)\s+' - - fieldName: protocol - pattern: '{{.greedy}}' - source: log.request - # Extracting protocol version - - grok: - patterns: - - fieldName: protocol - pattern: '{{.data}}/' - - fieldName: log.protoVersion - pattern: '{{.greedy}}' - source: protocol - where: exists("protocol") - - trim: - function: suffix - substring: '/' - fields: - - protocol - where: exists("protocol") - # Adding geolocation - - dynamic: - plugin: com.utmstack.geolocation - params: - source: origin.ip - destination: origin.geolocation - where: exists("origin.ip") - # Normalizing request method and renaming to action - - add: - function: 'string' - params: - key: action - value: 'get' - where: equals("log.method", "GET") - - add: - function: 'string' - params: - key: action - value: 'post' - where: equals("log.method", "POST") - - add: - function: 'string' - params: - key: action - value: 'put' - where: equals("log.method", "PUT") - - add: - function: 'string' - params: - key: action - value: 'delete' - where: equals("log.method", "DELETE") - - add: - function: 'string' - params: - key: action - value: 'patch' - where: equals("log.method", "PATCH") - - add: - function: 'string' - params: - key: action - value: 'request' - where: equals("log.method", "REQUEST") - # Removing log.method if action was set - - delete: - fields: - - log.method - where: exists("action") - # Reformat and field conversions - - cast: - fields: - - log.statusCode - - origin.bytesReceived - to: float - - reformat: - fields: - - deviceTime - function: time - fromFormat: '14/Feb/2022:15:40:53 -0500' - toFormat: '2024-09-23T15:57:40.338364445Z' - # Adding actionResult - # denied by default - - add: - function: 'string' - params: - key: actionResult - value: 'denied' - - add: - function: 'string' - params: - key: actionResult - value: 'accepted' - where: (greaterOrEqual("log.statusCode", 200) && lessOrEqual("log.statusCode", 299)) || (greaterOrEqual("log.statusCode", 300) && lessOrEqual("log.statusCode", 399) && greaterThan("origin.bytesReceived", 0)) - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.rest - - log.fileset \ No newline at end of file diff --git a/filters/filebeat/auditd_module.yml b/filters/filebeat/auditd_module.yml deleted file mode 100644 index 2030c52ef..000000000 --- a/filters/filebeat/auditd_module.yml +++ /dev/null @@ -1,73 +0,0 @@ -# Auditd filter, version 3.0.0 -# Fields based on https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-auditd.html -# https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sec-understanding_audit_log_files -# https://linux.die.net/man/5/auditd.conf -# and filebeat fields.yml version 7.13.4 oss -# As the docs says this module work with one event per line, filebeat must ensure to send one event per line. - -# Filter Input requirements -> fileset: datatype -# log: plain text -pipeline: - - dataTypes: - - auditd - steps: - - json: - source: raw - - rename: - from: - - log.url - to: origin.url - - rename: - from: - - log.log.file.path - to: origin.file - - rename: - from: - - log.host.ip - to: log.local.ips - - rename: - from: - - log.host.mac - to: log.local.macs - - rename: - from: - - log.host.hostname - to: origin.host - - rename: - from: - - log.event.dataset - to: action - - rename: - from: - - log.agent.version - to: log.agentVersion - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - rename: - from: - - log.host.os.type - to: log.osType - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - cast: - to: '[]string' - fields: - - log.local.ips - - cast: - to: '[]string' - fields: - - log.local.macs - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.fileset \ No newline at end of file diff --git a/filters/filebeat/elasticsearch_module.yml b/filters/filebeat/elasticsearch_module.yml deleted file mode 100644 index af0a0f499..000000000 --- a/filters/filebeat/elasticsearch_module.yml +++ /dev/null @@ -1,423 +0,0 @@ -# Elasticsearch filter, version 3.0.3 -# Fields based on https://www.elastic.co/guide/en/elasticsearch/reference/8.17/audit-event-types.html, -# https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-elasticsearch.html -# and filebeat fields.yml version 7.13.4 oss -# Support only server and audit logs from elasticsearch 7++ -# Filter Input requirements -> fileset: datatype -# server: plain text, json -# audit: plain text, json -# 1. Parsing the json from beats -# 2. Parsing the message field containing the elasticsearch log -pipeline: - - dataTypes: - - elasticsearch - steps: - - json: - source: raw - - rename: - from: - - log.url - to: origin.url - - rename: - from: - - log.log.file.path - to: origin.file - - rename: - from: - - log.host.ip - to: log.local.ips - - rename: - from: - - log.host.mac - to: log.local.macs - - rename: - from: - - log.host.hostname - to: origin.host - - rename: - from: - - log.event.dataset - to: log.eventDataset - - rename: - from: - - log.agent.version - to: log.agentVersion - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - rename: - from: - - log.host.os.type - to: log.osType - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - cast: - to: '[]string' - fields: - - log.local.ips - - cast: - to: '[]string' - fields: - - log.local.macs - - grok: - patterns: - - fieldName: deviceTime - pattern: '\[{{.data}}\]' - - fieldName: log.level - pattern: '\[{{.data}}\]' - - fieldName: log.component - pattern: '\[{{.data}}\]' - - fieldName: log.nodeName - pattern: '\[{{.data}}\]' - - fieldName: log.msg - pattern: '{{.greedy}}' - source: log.message - - trim: - function: prefix - substring: '[' - fields: - - deviceTime - - log.level - - log.component - - log.nodeName - where: exists("log.msg") - - trim: - function: suffix - substring: ']' - fields: - - deviceTime - - log.level - - log.component - - log.nodeName - where: exists("log.msg") - - reformat: - fields: - - deviceTime - function: time - fromFormat: '2022-01-20T22:52:07,431' - toFormat: '2024-09-23T15:57:40.338364445Z' - where: exists("deviceTime") - # Begin parsing when message comes in json format - - json: - source: log.message - where: exists("log.msg") - # Performing json step over the remaining message field (Cases when log.message has a message field inside) - - json: - source: log.message - where: exists("log.message") - # Rename audit fields from json - - rename: - from: - - log.audit_format_version - to: log.auditFormatVersion - where: exists("log.audit_format_version") - - rename: - from: - - log.audit_category - to: action - where: exists("log.audit_category") - - rename: - from: - - log.audit_node_host_address - to: log.auditNodeHostAddress - where: exists("log.audit_node_host_address") - - rename: - from: - - log.audit_node_host_name - to: log.auditNodeHostName - where: exists("log.audit_node_host_name") - - rename: - from: - - log.audit_request_layer - to: log.auditRequestLayer - where: exists("log.audit_request_layer") - - rename: - from: - - log.audit_request_origin - to: log.auditRequestOrigin - where: exists("log.audit_request_origin") - - rename: - from: - - log.audit_request_effective_user_is_admin - to: log.auditRequestEffectiveUserIsAdmin - where: exists("log.audit_request_effective_user_is_admin") - - rename: - from: - - log.audit_request_effective_user - to: log.auditRequestEffectiveUser - where: exists("log.audit_request_effective_user") - - rename: - from: - - log.audit_rest_request_path - to: log.auditRestRequestPath - where: exists("log.audit_rest_request_path") - - rename: - from: - - log.audit_rest_request_params - to: log.auditRestRequestParams - where: exists("log.audit_rest_request_params") - - rename: - from: - - log.audit_rest_request_headers - to: log.auditRestRequestHeaders - where: exists("log.audit_rest_request_headers") - - rename: - from: - - log.audit_request_initiating_user - to: log.auditRequestInitiatingUser - where: exists("log.audit_request_initiating_user") - - rename: - from: - - log.audit_request_body - to: log.auditRequestBody - where: exists("log.audit_request_body") - - rename: - from: - - log.audit_rest_request_method - to: log.auditRestRequestMethod - where: exists("log.audit_rest_request_method") - - rename: - from: - - log.audit_request_exception_stacktrace - to: log.auditRequestExceptionStacktrace - where: exists("log.audit_request_exception_stacktrace") - - rename: - from: - - log.audit_trace_task_id - to: log.auditTraceTaskId - where: exists("log.audit_trace_task_id") - - rename: - from: - - log.audit_transport_headers - to: log.auditTransportHeaders - where: exists("log.audit_transport_headers") - - rename: - from: - - log.audit_transport_request_type - to: log.auditTransportRequestType - where: exists("log.audit_transport_request_type") - - rename: - from: - - log.audit_trace_indices - to: log.auditTraceIndices - where: exists("log.audit_trace_indices") - - rename: - from: - - log.audit_trace_resolved_indices - to: log.auditTraceResolvedIndices - where: exists("log.audit_trace_resolved_indices") - - rename: - from: - - log.audit_trace_doc_types - to: log.auditTraceDocTypes - where: exists("log.audit_trace_doc_types") - - rename: - from: - - log.audit_trace_task_parent_id - to: log.auditTraceTaskParentId - where: exists("log.audit_trace_task_parent_id") - - rename: - from: - - log.audit_request_privilege - to: log.auditRequestPrivilege - where: exists("log.audit_request_privilege") - - rename: - from: - - log.audit_compliance_operation - to: log.auditComplianceOperation - where: exists("log.audit_compliance_operation") - - rename: - from: - - log.node.id - - log.audit_node_id - to: log.nodeId - where: exists("log.node.id") || exists("log.audit_node_id") - - rename: - from: - - log.node.name - - log.audit_node_name - to: log.nodeName - where: exists("log.node.name") || exists("log.node.name") - - rename: - from: - - log.cluster.name - - log.audit_cluster_name - to: log.clusterName - where: exists("log.cluster.name") || exists("log.audit_cluster_name") - - rename: - from: - - log.cluster.uuid - to: log.clusterUuid - where: exists("log.cluster.uuid") - # Adding fields from elastic audit json file - - rename: - from: - - log.event.type - to: log.eventType - where: exists("log.event.type") - - rename: - from: - - log.event.action - to: action - where: exists("log.event.action") - - rename: - from: - - log.request.id - to: log.requestId - where: exists("log.request.id") - # Extracting ip and port from address - - grok: - patterns: - - fieldName: log.origin.address - pattern: '(.*)\:' - - fieldName: origin.port - pattern: '{{.greedy}}' - source: log.origin.address - where: exists("log.origin.address") - # Cleaning ip address if has port - - trim: - function: suffix - substring: ':' - fields: - - log.origin.address - where: exists("log.origin.address") - - rename: - from: - - log.origin.address - to: origin.ip - where: exists("log.origin.address") - # Adding geolocation - - dynamic: - plugin: com.utmstack.geolocation - params: - source: origin.ip - destination: origin.geolocation - where: exists("origin.ip") - # Port field conversion - - cast: - fields: - - origin.port - to: int - where: exists("origin.port") - - rename: - from: - - log.origin.type - to: log.originType - where: exists("log.origin.type") - - rename: - from: - - log.url.path - to: origin.url - where: exists("log.url.path") - - rename: - from: - - log.url.query - to: log.urlQuery - where: exists("log.url.query") - - rename: - from: - - log.request.method - to: log.method - where: exists("log.request.method") - - rename: - from: - - log.transport_profile - to: log.transportProfile - where: exists("log.transport_profile") - - rename: - from: - - log.user.name - to: origin.user - where: exists("log.user.name") - - rename: - from: - - log.user.realm - to: log.userRealm - where: exists("log.user.realm") - - rename: - from: - - log.user.run_by.name - to: log.userRunByName - where: exists("log.user.run_by.name") - - rename: - from: - - log.authentication.type - to: log.authenticationType - where: exists("log.authentication.type") - - rename: - from: - - log.apikey.name - to: log.apikeyName - where: exists("log.apikey.name") - - rename: - from: - - log.user.roles - to: log.userRoles - where: exists("log.user.roles") - - rename: - from: - - log.user.run_as.name - to: log.userRunAsName - where: exists("log.user.run_as.name") - - rename: - from: - - log.user.run_as.name - to: log.userRunAsName - where: exists("log.user.run_as.name") - # Casting new fields after json parsing - - cast: - to: '[]string' - fields: - - log.auditTraceIndices - - log.auditTraceResolvedIndices - - log.indices - - log.userRoles - # Adding severity based on log.level - - add: - function: 'string' - params: - key: severity - value: 'high' - where: oneOf("log.level", ["ERROR", "Error", "FATAL", "CRITICAL", "Critical"]) - - add: - function: 'string' - params: - key: severity - value: 'medium' - where: oneOf("log.level", ["WARN", "Warning"]) - - add: - function: 'string' - params: - key: severity - value: 'low' - where: oneOf("log.level", ["Information", "Informational", "INFO", "DEBUG", "TRACE"]) - - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.fileset - - log.cluster - - log.node - - log.opaque_id - - log.trace_id - - log.x_forwarded_for - - log.request - - log.url - - log.user - - log.apikey - - log.authentication - - log.origin - - # Droping unwanted logs - - drop: - where: exists("log.eventDataset") && exists("log.component") && ( (!equals("log.eventDataset", "elasticsearch.server") && !equals("log.eventDataset", "elasticsearch.audit")) || (equals("log.eventDataset", "elasticsearch.server") && (!equalsIgnoreCase("log.component", "audit") && !equalsIgnoreCase("log.component", "ssl") && !equalsIgnoreCase("log.component", "security") ) ) ) \ No newline at end of file diff --git a/filters/filebeat/haproxy_module.yml b/filters/filebeat/haproxy_module.yml deleted file mode 100644 index 7b896b0f9..000000000 --- a/filters/filebeat/haproxy_module.yml +++ /dev/null @@ -1,66 +0,0 @@ -# HAPROXY filter, version 2.0.0 -# Fields based on https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-haproxy.html -pipeline: - - dataTypes: - - haproxy - steps: - - json: - source: raw - - rename: - from: - - log.url - to: origin.url - - rename: - from: - - log.log.file.path - to: origin.file - - rename: - from: - - log.host.ip - to: log.local.ips - - rename: - from: - - log.host.mac - to: log.local.macs - - rename: - from: - - log.host.hostname - to: origin.host - - rename: - from: - - log.event.dataset - to: action - - rename: - from: - - log.agent.version - to: log.agentVersion - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - rename: - from: - - log.host.os.type - to: log.osType - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - cast: - to: '[]string' - fields: - - log.local.ips - - cast: - to: '[]string' - fields: - - log.local.macs - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.fileset \ No newline at end of file diff --git a/filters/filebeat/iis_module.yml b/filters/filebeat/iis_module.yml deleted file mode 100644 index cc2ad55f5..000000000 --- a/filters/filebeat/iis_module.yml +++ /dev/null @@ -1,186 +0,0 @@ -# Internet Information Services Filter, version 3.0.3 -# Supports IIS 7 and later versions. See: https://learn.microsoft.com/es-es/iis/configuration/system.applicationhost/log/ -# and https://learn.microsoft.com/es-es/iis/configuration/system.applicationhost/sites/site/logfile/ -# 1. Parsing the json from beats -# 2. Parsing the message field containing the iis log -pipeline: - - dataTypes: - - iis - steps: - - json: - source: raw - - - rename: - from: - - log.log.file.path - to: origin.file - - - rename: - from: - - log.host.ip - to: log.origin.ips - - - rename: - from: - - log.host.mac - to: log.origin.macs - - - rename: - from: - - log.host.hostname - to: origin.host - - - rename: - from: - - log.event.dataset - to: action - - - rename: - from: - - log.agent.version - to: log.agentVersion - - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - - rename: - from: - - log.host.os.type - to: log.osType - - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - - cast: - to: "[]string" - fields: - - log.origin.ips - - - cast: - to: "[]string" - fields: - - log.origin.macs - - # Parsing the message field - - grok: - patterns: - - fieldName: log.deviceTime - pattern: '{{.year}}\-{{.monthNumber}}\-{{.monthDay}}{{.space}}{{.time}}' - - fieldName: log.localIpv6 - pattern: '{{.ipv6}}' - - fieldName: log.method - pattern: '{{.word}}' - - fieldName: target.path - pattern: '\/[^ ]*|(-)' - - fieldName: log.userIdent - pattern: '{{.integer}}|(-)' - - fieldName: target.port - pattern: '\b([0-9]{1,5})\b' - - fieldName: target.user - pattern: '{{.word}}|(-)' - - fieldName: target.ip - pattern: '{{.ipv4}}' - - fieldName: log.userAgent - pattern: 'Mozilla(.*?)\s' - - fieldName: log.referrer - pattern: 'https?:\/\/[^\s]+|(-)' - - fieldName: log.statusCode - pattern: '{{.integer}}' - - fieldName: log.subStatusCode - pattern: '{{.integer}}' - - fieldName: log.win32Status - pattern: '{{.integer}}' - - fieldName: log.responseTime - pattern: '{{.greedy}}' - source: log.message - - # Adding geolocation to target ip - - dynamic: - plugin: com.utmstack.geolocation - params: - source: target.ip - destination: target.geolocation - where: exists("target.ip") - - - cast: - fields: - - target.port - - log.subStatusCode - - log.win32Status - - log.timeTaken - - log.responseTime - to: int - - - cast: - fields: - - log.statusCode - to: float - - # Renaming "log.statusCode" to "statusCode" to add it to the event structure - - rename: - from: - - log.statusCode - to: statusCode - - # Normalizing request method and renaming to action - - add: - function: 'string' - params: - key: action - value: 'get' - where: equals("log.method", "GET") - - - add: - function: 'string' - params: - key: action - value: 'post' - where: equals("log.method", "POST") - - - add: - function: 'string' - params: - key: action - value: 'put' - where: equals("log.method", "PUT") - - - add: - function: 'string' - params: - key: action - value: 'delete' - where: equals("log.method", "DELETE") - - - add: - function: 'string' - params: - key: action - value: 'request' - where: equals("log.method", "REQUEST") - - # Removing log.method if action was set - - delete: - fields: - - log.method - where: exists("action") - - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.log.offset - - log.log - - log.input.type - - log.input - - log.fileset.name - - log.fileset - - log.agent - - log.host - - log.event - - log.ecs - - log.log.file \ No newline at end of file diff --git a/filters/filebeat/kafka_module.yml b/filters/filebeat/kafka_module.yml deleted file mode 100644 index 5ab966008..000000000 --- a/filters/filebeat/kafka_module.yml +++ /dev/null @@ -1,173 +0,0 @@ -# Kafka module filter, version 3.0.3 -# Filter Input requirements -> fileset: datatype -# log: plain text -# -# Compatible any of Kafka logs -# like: Server, Controller, Log-cleaner and so on -# -# Documentations -# 1- https://kafka.apache.org/documentation/ -# 2- https://www.elastic.co/guide/en/beats/filebeat/7.13/exported-fields-kafka.html -# -# Implementation -# 1. Parsing the json from beats -# 2. Parsing the message field containing the apache log -pipeline: - - dataTypes: - - kafka - steps: - - json: - source: raw - - # Parse beats field - - rename: - from: - - log.url - to: origin.url - - - rename: - from: - - log.log.file.path - to: origin.file - - - rename: - from: - - log.host.ip - to: log.origin.ips - - - rename: - from: - - log.host.mac - to: log.origin.macs - - - rename: - from: - - log.host.hostname - to: origin.host - - - rename: - from: - - log.event.dataset - to: action - - - rename: - from: - - log.agent.version - to: log.agentVersion - - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - - rename: - from: - - log.host.os.type - to: log.osType - - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - # Fields conversions - - cast: - to: '[]string' - fields: - - log.origin.ips - - cast: - to: '[]string' - fields: - - log.origin.macs - - #Parse message field in plain text format - # Logs Kafka parsing - - grok: - patterns: - - fieldName: log.deviceTime - pattern: '\[{{.data}}\]' - - fieldName: log.severity - pattern: '{{.word}}' - - fieldName: log.restData - pattern: '{{.greedy}}' - source: log.message - - # Logs Server Kafka parsing - - grok: - patterns: - - fieldName: log.msg - pattern: '{{.greedy}}{{.space}}' - - fieldName: log.class - pattern: '\({{.greedy}}\)' - source: log.restData - - # Logs Controller Kafka parsing - - grok: - patterns: - - fieldName: log.component - pattern: '\[{{.data}}\](\:|\,)?' - - fieldName: log.msg - pattern: '{{.greedy}}{{.space}}' - - fieldName: log.class - pattern: '\({{.greedy}}\)' - source: log.restData - - # Removing unused caracters - - trim: - function: prefix - substring: '[' - fields: - - log.deviceTime - - log.component - - trim: - function: suffix - substring: ']' - fields: - - log.deviceTime - - log.component - - trim: - function: prefix - substring: '(' - fields: - - log.class - - trim: - function: suffix - substring: ')' - fields: - - log.class - - # Adding severity field based on log.severity - - add: - function: 'string' - params: - key: severity - value: 'low' - where: oneOf("log.severity", ["INFO", "TRACE", "DEBUG"]) - - - add: - function: 'string' - params: - key: severity - value: 'medium' - where: oneOf("log.severity", ["WARNING", "WARN"]) - - - add: - function: 'string' - params: - key: severity - value: 'high' - where: equals("log.severity", "ERROR") - - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.log.offset - - log.agent - - log.host - - log.event - - log.ecs - - log.log.file - - log.log - - log.restData \ No newline at end of file diff --git a/filters/filebeat/kibana_module.yml b/filters/filebeat/kibana_module.yml deleted file mode 100644 index 18a34b6d1..000000000 --- a/filters/filebeat/kibana_module.yml +++ /dev/null @@ -1,181 +0,0 @@ -# Kibana filter, version 3.0.3 -# Supports Kibana Log and Kibana Audit version 7.17 or later. -# See: https://www.elastic.co/guide/en/kibana/7.17/xpack-security-audit-logging.html -# and https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-kibana.html#_fields_27 -# 1. Parsing the json from beats -# 2. Parsing the message field containing the kibana log -pipeline: - - dataTypes: - - kibana - steps: - - json: - source: raw - - - rename: - from: - - log.log.file.path - to: origin.file - - - rename: - from: - - log.host.ip - to: log.origin.ips - - - rename: - from: - - log.host.mac - to: log.origin.macs - - - rename: - from: - - log.host.hostname - to: origin.host - - - rename: - from: - - log.event.dataset - to: action - - - rename: - from: - - log.agent.version - to: log.agentVersion - - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - - rename: - from: - - log.host.os.name - to: log.osType - - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - # Parsing the message field for the log "audit" - - rename: - from: - - log.kibana._audit_temp.event.action - to: log.action - - - rename: - from: - - log.kibana._audit_temp.event.category - to: log.eventCategory - - - rename: - from: - - log.kibana._audit_temp.timestamp - to: log.deviceTime - - - rename: - from: - - log.kibana._audit_temp.@timestamp - to: log.deviceTime - - - rename: - from: - - log.kibana._audit_temp.user.name - to: origin.user - - - rename: - from: - - log.kibana._audit_temp.type - to: log.severityLabel - - - rename: - from: - - log.kibana._audit_temp.event.outcome - to: actionResult - - - rename: - from: - - log.kibana._audit_temp.message - to: log.message - - - cast: - to: "[]string" - fields: - - log.origin.ips - - - cast: - to: "[]string" - fields: - - log.origin.macs - - # Parsing the message field - - grok: - patterns: - - fieldName: log.deviceTime - pattern: '\[{{.data}}\]' - - fieldName: log.severityLabel - pattern: '\[{{.data}}\]' - - fieldName: log.component - pattern: '\[{{.data}}\]' - - fieldName: log.actionMessage - pattern: '{{.greedy}}' - source: log.message - - - trim: - function: prefix - substring: '[' - fields: - - log.deviceTime - - log.severityLabel - - log.component - - - trim: - function: suffix - substring: ']' - fields: - - log.deviceTime - - log.severityLabel - - log.component - - # Reformatting timestamps Kibana Log field - - reformat: - fields: - - log.deviceTime - function: time - fromFormat: '2022-01-01T00:05:07.292-05:00' - toFormat: '2024-09-23T15:57:40.338364445Z' - - # Adding severity based on log.severityLabel - - add: - function: 'string' - params: - key: log.severity - value: 'high' - where: oneOf("log.severityLabel", ["critical", "alert", "error"]) - - - add: - function: 'string' - params: - key: log.severity - value: 'medium' - where: equals("log.severityLabel", "warning") - - - add: - function: 'string' - params: - key: log.severity - value: 'low' - where: oneOf("log.severityLabel", ["debug", "verbose", "notice", "information", "trace"]) - - # Removing unused fields - - delete: - fields: - - log.metadata - - log.agent - - log.ecs - - log.event - - log.host - - log.input - - log.log - - log.service - - log.fileset - - log.kibana \ No newline at end of file diff --git a/filters/filebeat/logstash_module.yml b/filters/filebeat/logstash_module.yml deleted file mode 100644 index 309288b35..000000000 --- a/filters/filebeat/logstash_module.yml +++ /dev/null @@ -1,140 +0,0 @@ -# Logstash filter, version 4.0.3 -# Fields based on https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-logstash.html -# and filebeat fields.yml version 7.13.4 oss -# Support logs from logstash 7.14.1 ++ -# Filter Input requirements -> fileset: datatype -# log: plain text -# 1. Parsing the json from beats -# 2. Parsing the message field containing the logstash log -pipeline: - - dataTypes: - - logstash - steps: - - json: - source: raw - - rename: - from: - - log.url - to: origin.url - - rename: - from: - - log.log.file.path - to: origin.file - - rename: - from: - - log.host.ip - to: log.local.ips - - rename: - from: - - log.host.mac - to: log.local.macs - - rename: - from: - - log.host.hostname - to: origin.host - - rename: - from: - - log.event.dataset - to: action - - rename: - from: - - log.agent.version - to: log.agentVersion - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - rename: - from: - - log.host.os.type - to: log.osType - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - cast: - to: '[]string' - fields: - - log.local.ips - - cast: - to: '[]string' - fields: - - log.local.macs - # Parsing common log parts - - grok: - patterns: - - fieldName: deviceTime - pattern: '\[{{.data}}\]' - - fieldName: log.level - pattern: '\[{{.data}}\]' - - fieldName: log.component - pattern: '\[{{.data}}\]' - - fieldName: log.pipelineName - pattern: '^(\[{{.data}}\])' - - fieldName: log.msg - pattern: '{{.greedy}}' - source: log.message - # Parsing when pipeline is not present - - grok: - patterns: - - fieldName: deviceTime - pattern: '\[{{.data}}\]' - - fieldName: log.level - pattern: '\[{{.data}}\]' - - fieldName: log.component - pattern: '\[{{.data}}\]' - - fieldName: log.msg - pattern: '{{.greedy}}' - source: log.message - - trim: - function: prefix - substring: '[' - fields: - - deviceTime - - log.level - - log.component - - log.pipelineName - - trim: - function: suffix - substring: ']' - fields: - - deviceTime - - log.level - - log.component - - log.pipelineName - - reformat: - fields: - - deviceTime - function: time - fromFormat: '2024-07-31T17:02:07,154' - toFormat: '2024-09-23T15:57:40.338364445Z' - # Adding severity based on log.level - - add: - function: 'string' - params: - key: severity - value: 'high' - where: oneOf("log.level", ["ERROR", "Error", "FATAL", "CRITICAL", "Critical"]) - - add: - function: 'string' - params: - key: severity - value: 'medium' - where: oneOf("log.level", ["WARN", "Warning"]) - - add: - function: 'string' - params: - key: severity - value: 'low' - where: oneOf("log.level", ["Information", "Informational", "INFO", "DEBUG", "TRACE"]) - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.fileset \ No newline at end of file diff --git a/filters/filebeat/mongodb_module.yml b/filters/filebeat/mongodb_module.yml deleted file mode 100644 index 0553ef584..000000000 --- a/filters/filebeat/mongodb_module.yml +++ /dev/null @@ -1,136 +0,0 @@ -# MongoDb filter, version 3.0.1 -# Fields based on https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-mongodb.html -# https://docs.mongodb.com/manual/reference/log-messages/ -# and filebeat fields.yml version 7.13.4 oss -# Support logs from MongoDb 4.4 ++ -# Filter Input requirements -> fileset: datatype -# log: json -# 1. Parsing the json from beats -# 2. Parsing the message field containing the MongoDb log -pipeline: - - dataTypes: - - mongodb - steps: - - json: - source: raw - - rename: - from: - - log.url - to: origin.url - - rename: - from: - - log.log.file.path - to: origin.file - - rename: - from: - - log.host.ip - to: log.local.ips - - rename: - from: - - log.host.mac - to: log.local.macs - - rename: - from: - - log.host.hostname - to: log.agentHostName - - rename: - from: - - log.event.dataset - to: action - - rename: - from: - - log.agent.version - to: log.agentVersion - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - rename: - from: - - log.host.os.type - to: log.osType - - rename: - from: - - log.host.architecture - to: log.cpuAgentArchitecture - - cast: - to: '[]string' - fields: - - log.local.ips - - cast: - to: '[]string' - fields: - - log.local.macs - # Parsing json log - - json: - source: log.message - # Renaming fields of mongodb log - - rename: - from: - - log.t.$date - to: log.time - - rename: - from: - - log.c - to: log.component - - rename: - from: - - log.attr.host - to: origin.host - - rename: - from: - - log.attr.port - to: origin.port - - rename: - from: - - log.attr.pid - to: log.pid - - rename: - from: - - log.attr.architecture - to: log.cpuArchitecture - - rename: - from: - - log.attr.dbPath - to: origin.path - - reformat: - fields: - - log.time - function: time - fromFormat: '2020-05-18T20:18:12.814+00:00' - toFormat: '2024-09-23T15:57:40.338364445Z' - # Decoding severity - - add: - function: 'string' - params: - key: severity - value: 'high' - where: log.s=="F" || log.s=="E" - - add: - function: 'string' - params: - key: severity - value: 'medium' - where: log.s=="W" - - add: - function: 'string' - params: - key: severity - value: 'low' - where: log.s!="F" && log.s!="E" && log.s!="W" - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.fileset - - log.t - - log.agentHostName - - log.attr - - log.input - - log.s \ No newline at end of file diff --git a/filters/filebeat/mysql_module.yml b/filters/filebeat/mysql_module.yml deleted file mode 100644 index 84c9d3325..000000000 --- a/filters/filebeat/mysql_module.yml +++ /dev/null @@ -1,131 +0,0 @@ -# MySQL filter, version 3.0.3 -# Fields based on https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-mysql.html -# https://dev.mysql.com/doc/refman/8.0/en/error-log-format.html -# https://docs.oracle.com/en-us/iaas/Content/Logging/Reference/top_level_logging_format.htm -# https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-application-log.html#mysql-shell-log-levels -# and filebeat fields.yml version 7.13.4 oss -# Support logs from MySQL 8.0 ++ -# Filter Input requirements -> fileset: datatype -# error: plain text -# 1. Parsing the json from beats -# 2. Parsing the message field containing the mysql log -pipeline: - - dataTypes: - - mysql - steps: - - json: - source: raw - - rename: - from: - - log.url - to: origin.url - - rename: - from: - - log.log.file.path - to: origin.file - - rename: - from: - - log.host.ip - to: log.local.ips - - rename: - from: - - log.host.mac - to: log.local.macs - - rename: - from: - - log.host.hostname - to: origin.host - - rename: - from: - - log.event.dataset - to: action - - rename: - from: - - log.agent.version - to: log.agentVersion - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - rename: - from: - - log.host.os.type - to: log.osType - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - cast: - to: '[]string' - fields: - - log.local.ips - - cast: - to: '[]string' - fields: - - log.local.macs - # Parsing common log parts - - grok: - patterns: - - fieldName: deviceTime - pattern: '{{.data}}\s' - - fieldName: log.thread - pattern: '{{.integer}}' - - fieldName: log.level - pattern: '\[{{.data}}\]' - - fieldName: log.errorCode - pattern: '\[{{.data}}\]' - - fieldName: log.subsystem - pattern: '\[{{.data}}\]' - - fieldName: log.msg - pattern: '{{.greedy}}' - source: log.message - - trim: - function: prefix - substring: '[' - fields: - - log.level - - log.errorCode - - log.subsystem - - trim: - function: suffix - substring: ']' - fields: - - log.level - - log.errorCode - - log.subsystem - - reformat: - fields: - - deviceTime - function: time - fromFormat: '2020-08-06T14:25:03.109022Z' - toFormat: '2024-09-23T15:57:40.338364445Z' - # Adding severity based on log.level - - add: - function: 'string' - params: - key: severity - value: 'high' - where: oneOf("log.level", ["Internal", "internal", "INTERNAL", "Error", "error", "ERROR"]) - - add: - function: 'string' - params: - key: severity - value: 'medium' - where: exists("log.level") && oneOf("log.level", ["Warning", "warning", "WARNING"]) - - add: - function: 'string' - params: - key: severity - value: 'low' - where: exists("log.level") && !oneOf("log.level", ["Internal", "internal", "INTERNAL", "Error", "error", "ERROR", "Warning", "warning", "WARNING"]) - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.fileset \ No newline at end of file diff --git a/filters/filebeat/nats_module.yml b/filters/filebeat/nats_module.yml deleted file mode 100644 index e97d20f33..000000000 --- a/filters/filebeat/nats_module.yml +++ /dev/null @@ -1,66 +0,0 @@ -# Nats filter, version 2.0.0 -# Fields based on https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-nats.html -pipeline: - - dataTypes: - - nats - steps: - - json: - source: raw - - rename: - from: - - log.url - to: origin.url - - rename: - from: - - log.log.file.path - to: origin.file - - rename: - from: - - log.host.ip - to: log.local.ips - - rename: - from: - - log.host.mac - to: log.local.macs - - rename: - from: - - log.host.hostname - to: origin.host - - rename: - from: - - log.event.dataset - to: action - - rename: - from: - - log.agent.version - to: log.agentVersion - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - rename: - from: - - log.host.os.type - to: log.osType - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - cast: - to: '[]string' - fields: - - log.local.ips - - cast: - to: '[]string' - fields: - - log.local.macs - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.fileset \ No newline at end of file diff --git a/filters/filebeat/nginx_module.yml b/filters/filebeat/nginx_module.yml deleted file mode 100644 index 8b7743564..000000000 --- a/filters/filebeat/nginx_module.yml +++ /dev/null @@ -1,398 +0,0 @@ -# Nginx filter, version 3.0.3 -# Supports Nginx access, error, emergency and notice log -# See: https://github.com/nginx/nginx -# and https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-nginx.html for more documentation -# 1. Parsing the json from beats -# 2. Parsing the message field containing the Nginx log -pipeline: - - dataTypes: - - nginx - steps: - - json: - source: raw - - - rename: - from: - - log.log.file.path - to: origin.file - - - rename: - from: - - log.host.ip - to: log.origin.ips - - - rename: - from: - - log.host.mac - to: log.origin.macs - - - rename: - from: - - log.host.hostname - to: origin.host - - - rename: - from: - - log.event.dataset - to: action - - - rename: - from: - - log.agent.version - to: log.agentVersion - - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - - rename: - from: - - log.host.os.type - to: log.osType - - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - - cast: - to: "[]string" - fields: - - log.origin.ips - - - cast: - to: "[]string" - fields: - - log.origin.macs - - # Parsing the message field for the log "access" type - - grok: - patterns: - - fieldName: origin.ip - pattern: '{{.ipv4}}|{{.ipv6}}' - - fieldName: log.userIdent - pattern: '{{.word}}|(-)' - - fieldName: origin.user - pattern: '{{.word}}\.{{.word}}|(-)' - - fieldName: log.deviceTime - pattern: '\[(.*?)\]' - - fieldName: log.request - pattern: '\"{{.data}}\"' - - fieldName: log.statusCode - pattern: '{{.integer}}' - - fieldName: origin.bytesReceived - pattern: '{{.integer}}|(-)' - - fieldName: log.referrer - pattern: '\"{{.data}}\"' - - fieldName: log.userAgent - pattern: '{{.greedy}}' - source: log.message - - # Removing unnecessary characters - - trim: - function: prefix - substring: '[' - fields: - - log.deviceTime - - - trim: - function: suffix - substring: ']' - fields: - - log.deviceTime - - - trim: - function: prefix - substring: '"' - fields: - - log.request - - log.referrer - - log.userAgent - - - trim: - function: suffix - substring: '"' - fields: - - log.request - - log.referrer - - log.userAgent - - # Parsing the request for the log "access" type - - grok: - patterns: - - fieldName: log.method - pattern: '{{.word}}' - - fieldName: origin.path - pattern: '\/[^ ]*' - - fieldName: protocol - pattern: '{{.greedy}}' - source: log.request - - # Parsing the message field for the log "error" type - - grok: - patterns: - - fieldName: log.deviceTime - pattern: '{{.year}}\/{{.monthNumber}}\/{{.monthDay}}{{.space}}{{.time}}' - - fieldName: log.severityLabel - pattern: '\[{{.data}}\]' - - fieldName: log.processPidThreadId - pattern: '{{.integer}}\#{{.integer}}' - - fieldName: log.requestId - pattern: '(\:\s\*{{.integer}}\s)|(\:{{.space}})' - - fieldName: log.message - pattern: '{{.data}}\,' - - fieldName: origin.ip - pattern: '{{.data}}\,' - - fieldName: target.ip - pattern: '{{.data}}\,' - - fieldName: log.quest - pattern: '{{.word}}\:' - - fieldName: log.request - pattern: '\"{{.data}}\"' - - fieldName: log.restdata - pattern: '{{.greedy}}' - source: log.message - - # Removing unnecessary characters - - trim: - function: prefix - substring: '"' - fields: - - log.request - - - trim: - function: suffix - substring: '"' - fields: - - log.request - - - trim: - function: prefix - substring: '[' - fields: - - log.severityLabel - - - trim: - function: suffix - substring: ']' - fields: - - log.severityLabel - - - trim: - function: prefix - substring: ',' - fields: - - log.restdata - - - trim: - function: suffix - substring: ',' - fields: - - log.message - - origin.ip - - target.ip - - # Parsing the request for the log "error" type - - grok: - patterns: - - fieldName: log.method - pattern: '{{.word}}' - - fieldName: origin.path - pattern: '\/[^ ]*' - - fieldName: protocol - pattern: '{{.greedy}}' - source: log.request - - # Parsing the message field for the log "emergency" type - - grok: - patterns: - - fieldName: log.deviceTime - pattern: '{{.year}}\/{{.monthNumber}}\/{{.monthDay}}{{.space}}{{.time}}' - - fieldName: log.severityLabel - pattern: '\[{{.data}}\]' - - fieldName: log.processPidThreadId - pattern: '{{.integer}}\#{{.integer}}' - - fieldName: log.requestId - pattern: '(\:\s\*{{.integer}}\s)|(\:{{.space}})' - - fieldName: log.message - pattern: '{{.greedy}}' - source: log.message - - # Removing unnecessary characters - - trim: - function: prefix - substring: '[' - fields: - - log.severityLabel - - - trim: - function: suffix - substring: ']' - fields: - - log.severityLabel - - # Parsing the message field for the log "notice" type - - grok: - patterns: - - fieldName: log.deviceTime - pattern: '{{.year}}\/{{.monthNumber}}\/{{.monthDay}}{{.space}}{{.time}}' - - fieldName: log.severityLabel - pattern: '\[{{.data}}\]' - - fieldName: log.processPidThreadId - pattern: '{{.integer}}\#{{.integer}}' - - fieldName: log.requestId - pattern: '(\:\s\*{{.integer}}\s)|(\:{{.space}})' - - fieldName: log.message - pattern: '{{.greedy}}' - source: log.message - - # Removing unnecessary characters - - trim: - function: prefix - substring: '[' - fields: - - log.severityLabel - - - trim: - function: suffix - substring: ']' - fields: - - log.severityLabel - - # Adding geolocation to target ip - - dynamic: - plugin: com.utmstack.geolocation - params: - source: target.ip - destination: target.geolocation - where: exists("target.ip") - - # Adding geolocation to origin ip - - dynamic: - plugin: com.utmstack.geolocation - params: - source: origin.ip - destination: origin.geolocation - where: exists("origin.ip") - - # Reformat and field conversions - - cast: - fields: - - log.statusCode - to: float - - - cast: - fields: - - origin.bytesReceived - to: float - - - reformat: - fields: - - log.deviceTime - function: time - fromFormat: '01/Feb/2022:08:01:18 -0500' - toFormat: '2024-09-23T15:57:40.338364445Z' - - # Renaming "log.statusCode" to "statusCode" to add it to the event structure - - rename: - from: - - log.statusCode - to: statusCode - - # Normalizing request method and renaming to action - - add: - function: 'string' - params: - key: action - value: 'get' - where: equals("log.method", "GET") - - - add: - function: 'string' - params: - key: action - value: 'post' - where: equals("log.method", "POST") - - - add: - function: 'string' - params: - key: action - value: 'put' - where: equals("log.method", "PUT") - - - add: - function: 'string' - params: - key: action - value: 'delete' - where: equals("log.method", "DELETE") - - - add: - function: 'string' - params: - key: action - value: 'request' - where: equals("log.method", "REQUEST") - - # Adding actionResult - # denied by default - - add: - function: 'string' - params: - key: actionResult - value: 'denied' - - - add: - function: 'string' - params: - key: actionResult - value: 'accepted' - where: (greaterOrEqual("statusCode", 200) && lessOrEqual("statusCode", 299)) || (greaterOrEqual("statusCode", 300) && lessOrEqual("statusCode", 399) && greaterThan("origin.bytesReceived", 0)) - - # Adding severity based on log.severityLabel - - add: - function: 'string' - params: - key: log.severity - value: 'high' - where: oneOf("log.severityLabel", ["critical", "alert", "error"]) - - - add: - function: 'string' - params: - key: log.severity - value: 'medium' - where: equals("log.severityLabel", "warning") - - - add: - function: 'string' - params: - key: log.severity - value: 'low' - where: oneOf("log.severityLabel", ["debug", "verbose", "notice", "information", "trace"]) - - # Removing log.method if action was set - - delete: - fields: - - log.method - where: exists("action") - - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.log.offset - - log.log - - log.quest - - log.input.type - - log.input - - log.fileset.name - - log.fileset - - log.agent - - log.host - - log.event - - log.ecs - - log.log.file \ No newline at end of file diff --git a/filters/filebeat/osquery_module.yml b/filters/filebeat/osquery_module.yml deleted file mode 100644 index 9207796b3..000000000 --- a/filters/filebeat/osquery_module.yml +++ /dev/null @@ -1,142 +0,0 @@ -# Osquery filter -# Supports other_info, system_info and other log -# See: https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-osquery.html -# and https://www.elastic.co/guide/en/beats/filebeat/7.13/exported-fields-osquery.html for more documentation -# 1. Parsing the json from beats -# 2. Parsing the message field containing the other_info, system_info and other log -pipeline: - - dataTypes: - - osquery - steps: - - json: - source: raw - - - rename: - from: - - log.log.file.path - to: origin.file - - - rename: - from: - - log.host.ip - to: log.origin.ips - - - rename: - from: - - log.host.mac - to: log.origin.macs - - - rename: - from: - - log.host.hostname - to: origin.host - - - rename: - from: - - log.event.dataset - to: action - - - rename: - from: - - log.agent.version - to: log.agentVersion - - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - - rename: - from: - - log.host.os.name - to: log.osType - - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - # Parsing the message field for the other_info, system_info and other log - - rename: - from: - - log.json.action - to: actionResult - - - rename: - from: - - log.json.columns.description - to: log.message - - - rename: - from: - - log.json.columns.cpu_brand - to: log.cpuBrand - - - rename: - from: - - log.json.columns.hostname - to: origin.host - - - rename: - from: - - log.json.model - to: log.deviceModel - - - rename: - from: - - log.json.vendor - to: log.deviceVendor - - - rename: - from: - - log.json.calendarTime - to: log.deviceTime - - - rename: - from: - - log.json.hostIdentifier - to: origin.host - - - rename: - from: - - log.json.name - to: log.eventName - - - rename: - from: - - log.json.columns.username - to: origin.user - - - rename: - from: - - log.json.columns.directory - to: origin.path - - - rename: - from: - - log.json.columns.uuid - to: log.localUserUuid - - - cast: - to: "[]string" - fields: - - log.origin.ips - - - cast: - to: "[]string" - fields: - - log.origin.macs - - # Removing unused fields - - delete: - fields: - - log.metadata - - log.agent - - log.ecs - - log.event - - log.host - - log.input - - log.log - - log.service - - log.fileset - - log.json \ No newline at end of file diff --git a/filters/filebeat/postgresql_module.yml b/filters/filebeat/postgresql_module.yml deleted file mode 100644 index a35b24cb8..000000000 --- a/filters/filebeat/postgresql_module.yml +++ /dev/null @@ -1,153 +0,0 @@ -# Postgres module filter, version 3.0.0 -# Filter Input requirements -> fileset: datatype -# log : plain text -# -# Documentations -# 1- https://www.postgresql.org/docs/ -# 2- https://www.postgresql.org/docs/current/runtime-config-logging.html -# 3- https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-postgresql.html -# -# Implementation -# 1. Parsing the json from beats -# 2. Parsing the message field containing the postgres log -pipeline: - - dataTypes: - - postgresql - steps: - - json: - source: raw - - # Parse beats field - - rename: - from: - - log.url - to: origin.url - - - rename: - from: - - log.log.file.path - to: origin.file - - - rename: - from: - - log.host.ip - to: log.origin.ips - - - rename: - from: - - log.host.mac - to: log.origin.macs - - - rename: - from: - - log.host.hostname - to: origin.host - - - rename: - from: - - log.event.dataset - to: action - - - rename: - from: - - log.agent.version - to: log.agentVersion - - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - - rename: - from: - - log.host.os.type - to: log.osType - - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - # Fields conversions - - cast: - to: '[]string' - fields: - - log.origin.ips - - cast: - to: '[]string' - fields: - - log.origin.macs - - # Common postgresql log parsing - # Example Log - # Mar 24 14:58:08 webappsecure postgres[7694]: [10-2] 42701 530b5e00.1e0e STATEMENT: ALTER TABLE sessiongroup ADD COLUMN requests bigint - - grok: - patterns: - - fieldName: log.deviceTime - pattern: '{{.monthName}}{{.space}}{{.monthDay}}{{.space}}{{.time}} | - {{.year}}(-){{.monthNumber}}(-){{.monthDay}}{{.space}}{{.time}}{{.space}}((UTC)?)' - - fieldName: target.host - pattern: '{{.hostname}}' - - fieldName: log.irrelevant - pattern: '{{.word}}' - - fieldName: log.processId - pattern: '\[{{.data}}\](\:)?' - - fieldName: log.groupId - pattern: '\[{{.data}}\]' - - fieldName: log.errorCode - pattern: '{{.integer}}' - - fieldName: log.sessionId - pattern: '([0-9a-f]{8}\.[0-9a-f]{4})' - - fieldName: log.messageType - pattern: '{{.word}}(\:)?' - - fieldName: log.msg - pattern: '{{.greedy}}' - source: log.message - - # Common postgresql log parsing - # Example Log - # 2022-02-15 19:43:52.364 UTC [25] LOG: database system was shut down at 2022-02-11 20:01:30 UTC - - grok: - patterns: - - fieldName: log.deviceTime - pattern: '{{.year}}(-){{.monthNumber}}(-){{.monthDay}}{{.space}}{{.time}}{{.space}}((UTC)?) | - {{.monthName}}{{.space}}{{.monthDay}}{{.space}}{{.time}}' - - fieldName: log.groupId - pattern: '\[{{.data}}\]' - - fieldName: log.messageType - pattern: '{{.word}}(\:)?' - - fieldName: log.msg - pattern: '{{.greedy}}' - source: log.message - - # Removing unused caracters - - trim: - function: prefix - substring: '[' - fields: - - log.processId - - log.groupId - - trim: - function: suffix - substring: ':' - fields: - - log.processId - - log.messageType - - trim: - function: suffix - substring: ']' - fields: - - log.processId - - log.groupId - - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.irrelevant \ No newline at end of file diff --git a/filters/filebeat/redis_module.yml b/filters/filebeat/redis_module.yml deleted file mode 100644 index ad4a05ed3..000000000 --- a/filters/filebeat/redis_module.yml +++ /dev/null @@ -1,241 +0,0 @@ -# Redis module filter, version 3.0.3 -# Filter Input requirements -> fileset: datatype -# log: plain text -# -# Documentations -# 1- https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-redis.html -# 2- https://www.elastic.co/guide/en/beats/filebeat/7.13/exported-fields-redis.html -# 3- https://redis.io/docs/latest/operate/rs/clusters/logging/redis-slow-log/ -# 4- https://build47.com/redis-log-format-levels/ -# -# Implementation -# 1. Parsing the json from beats -# 2. Parsing the message field containing the redis log -pipeline: - - dataTypes: - - redis - steps: - - json: - source: raw - - # Parse message field in plain text format - - grok: - patterns: - - fieldName: log.pid - pattern: '{{.data}}\:' - - fieldName: log.roleEnc - pattern: '{{.word}}' - - fieldName: log.deviceTime - pattern: '{{.monthDay}}{{.space}}{{.monthName}}{{.space}}{{.year}}{{.space}}{{.time}}' - - fieldName: log.levelEnc - pattern: '(\.)|(-)|(\*)|(#)' - - fieldName: log.msg - pattern: '{{.greedy}}' - source: log.message - - # Removing unwanted prefixes - - trim: - function: suffix - substring: ':' - fields: - - log.pid - - # Fields variants from module - # Example: [4018] 14 Nov 07:01:22.119 - - grok: - patterns: - - fieldName: log.pid - pattern: '\[{{.data}}\]' - - fieldName: log.deviceTime - pattern: '{{.monthDay}}{{.space}}{{.monthName}}{{.space}}{{.time}}' - - fieldName: log.levelEnc - pattern: '(\.)|(-)|(\*)|(#)' - - fieldName: log.msg - pattern: '{{.greedy}}' - source: log.message - - # Removing unwanted prefixes - - trim: - function: prefix - substring: '[' - fields: - - log.pid - - trim: - function: suffix - substring: ']' - fields: - - log.pid - - # ................................................................................# - # Implementing the Record-RoleEnc Field Based on Redis Documentation - # https://build47.com/redis-log-format-levels/ - # - # The possible values for roleEnc are as follows: - # (X) sentinel - # (M) master - # (S) slave - # (C) RDB/AOF writing child - # ................................................................................# - - add: - function: 'string' - params: - key: log.role - value: 'sentinel' - where: log.roleEnc=="X" || log.roleEnc=="x" - - - add: - function: 'string' - params: - key: log.role - value: 'master' - where: log.roleEnc=="M" || log.roleEnc=="m" - - - add: - function: 'string' - params: - key: log.role - value: 'slave' - where: log.roleEnc=="S" || log.roleEnc=="s" - - - add: - function: 'string' - params: - key: log.role - value: 'rdb/aof' - where: log.roleEnc=="C" || log.roleEnc=="c" - - # ................................................................................# - # Implementing the Record-severity Field Based on Redis Documentation - # https://build47.com/redis-log-format-levels/ - # - # The log severity is a single character, which is one of the following: - # debug (.) - # verbose (-) - # notice (*) - # warning (#) - # ................................................................................# - - add: - function: 'string' - params: - key: log.severity - value: 'debug' - where: log.levelEnc=="." - - - add: - function: 'string' - params: - key: log.severity - value: 'verbose' - where: log.levelEnc=="-" - - - add: - function: 'string' - params: - key: log.severity - value: 'notice' - where: log.levelEnc=="*" - - - add: - function: 'string' - params: - key: log.severity - value: 'warning' - where: log.levelEnc=="#" - - # Adding severity field based on log.severity - - add: - function: 'string' - params: - key: severity - value: 'low' - where: oneOf("log.severity", ["debug", "verbose"]) - - - add: - function: 'string' - params: - key: severity - value: 'medium' - where: oneOf("log.severity", ["notice", "warning"]) - - - add: - function: 'string' - params: - key: severity - value: 'high' - where: oneOf("log.severity", ["error"]) - - # Parse beats field - - rename: - from: - - log.url - to: origin.url - - - rename: - from: - - log.log.file.path - to: origin.file - - - rename: - from: - - log.host.ip - to: log.origin.ips - - - rename: - from: - - log.host.mac - to: log.origin.macs - - - rename: - from: - - log.host.hostname - to: origin.host - - - rename: - from: - - log.event.dataset - to: action - - - rename: - from: - - log.agent.version - to: log.agentVersion - - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - - rename: - from: - - log.host.os.type - to: log.osType - - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - # Fields conversions - - cast: - to: '[]string' - fields: - - log.origin.ips - - cast: - to: '[]string' - fields: - - log.origin.macs - - # Removing unused fields - - delete: - fields: - - log.service - - log.metadata - - log.log.offset - - log.agent - - log.host - - log.event - - log.ecs - - log.log.file - - log.roleEnc - - log.levelEnc - - log.log \ No newline at end of file diff --git a/filters/filebeat/traefik_module.yml b/filters/filebeat/traefik_module.yml deleted file mode 100644 index d82857f7e..000000000 --- a/filters/filebeat/traefik_module.yml +++ /dev/null @@ -1,69 +0,0 @@ -# Traefik filter, version 2.0.0 -# Fields based on https://www.elastic.co/guide/en/beats/filebeat/7.13/filebeat-module-traefik.html - -#Filter Input requirements -> fileset: datatype -# access: plain text -pipeline: - - dataTypes: - - traefik - steps: - - json: - source: raw - - rename: - from: - - log.url - to: origin.url - - rename: - from: - - log.log.file.path - to: origin.file - - rename: - from: - - log.host.ip - to: log.local.ips - - rename: - from: - - log.host.mac - to: log.local.macs - - rename: - from: - - log.host.hostname - to: origin.host - - rename: - from: - - log.event.dataset - to: action - - rename: - from: - - log.agent.version - to: log.agentVersion - - rename: - from: - - log.host.os.kernel - to: log.osVersion - - rename: - from: - - log.host.os.type - to: log.osType - - rename: - from: - - log.host.architecture - to: log.cpuArchitecture - - cast: - to: '[]string' - fields: - - log.local.ips - - cast: - to: '[]string' - fields: - - log.local.macs - - delete: - fields: - - log.service - - log.metadata - - log.agent - - log.host - - log.event - - log.ecs - - log.log - - log.fileset \ No newline at end of file diff --git a/filters/hids/hids-wazuh.yml b/filters/hids/hids-wazuh.yml deleted file mode 100644 index 4bbc2cc6d..000000000 --- a/filters/hids/hids-wazuh.yml +++ /dev/null @@ -1,59 +0,0 @@ -pipeline: - - dataTypes: - - hids - steps: - # 1. Parse JSON - - json: - source: raw - - # 2. Rename Agent Fields - - rename: - from: [log.agent.id] - to: log.agent_id - - rename: - from: [log.agent.ip] - to: log.agent_ip - - rename: - from: [log.agent.name] - to: log.agent_name - - rename: - from: [log.manager.name] - to: log.manager - - # 3. Handle Special "000" Agent Case (from conf) - # In the new system, we might just keep the values as is, - # or if we need to enforce dataSource changes, we relies on pipeline logic. - # The old conf set "dataSource" => "hids" if agent.id == "000". - # This is likely handled by defining the dataType as "hids" for this pipeline. - - # 4. Rename Other Fields - - rename: - from: [log.decoder.name] - to: log.decoder_name - - rename: - from: [log.rule] - to: log.rule - - rename: - from: [log.location] - to: log.location - - rename: - from: [log.data] - to: log.data - - # 5. Severity Mapping based on Rule Level - - add: - function: string - params: { key: severity, value: high } - where: 'exists("log.rule.level") && greaterThan("log.rule.level", 11)' - - add: - function: string - params: { key: severity, value: medium } - where: 'exists("log.rule.level") && lessOrEqual("log.rule.level", 11) && greaterOrEqual("log.rule.level", 7)' - - add: - function: string - params: { key: severity, value: low } - where: 'exists("log.rule.level") && lessThan("log.rule.level", 7)' - - # 6. Standard UTMStack Fields - # If these exist in log.data or elsewhere, they should be mapped. - # The conf didn't map to origin.ip/target.ip explicitly unless they were in "data". diff --git a/filters/linux/linux-ufw.yml b/filters/linux/linux-ufw.yml deleted file mode 100644 index f5840f837..000000000 --- a/filters/linux/linux-ufw.yml +++ /dev/null @@ -1,84 +0,0 @@ -pipeline: - - dataTypes: - - firewall-ufw - steps: - # 1. Handle Agent Wrapper (Optional) - - grok: - 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 # Fallback if no wrapper, match everything - pattern: '{{.greedy}}' - - # 2. Parse UFW Log - - grok: - source: log.inner_msg - patterns: - - fieldName: log.timestamp - pattern: '{{.monthName}}(\s+){{.monthDay}}(\s+){{.time}}' - - fieldName: log.separator - pattern: '{{.space}}' - - fieldName: log.ufw_host - pattern: '{{.hostname}}' - - fieldName: log.separator - pattern: '{{.space}}' - - fieldName: log.process - pattern: '{{.data}}' - - fieldName: log.separator - pattern: '\[UFW ' - - fieldName: log.action - pattern: '{{.word}}' - - fieldName: log.separator - pattern: '\] ' - - fieldName: log.ufw_data - pattern: '{{.greedy}}' - - # 2b. Parse the Key-Value part of UFW - - kv: - source: log.ufw_data - fieldSplit: " " - valueSplit: "=" - - # 3. Standardize Fields from KV - - rename: - from: [SRC] - to: origin.ip - - rename: - from: [DST] - to: target.ip - - rename: - from: [SPT] - to: origin.port - - rename: - from: [DPT] - to: target.port - - rename: - from: [PROTO] - to: protocol - - rename: - from: [MAC] - to: log.mac - - rename: - from: [IN] - to: log.interface - - # 4. Standardize Action - - rename: - from: [log.action] - to: action - - # 5. Cast Types - - cast: - fields: [origin.port, target.port] - to: int - - # 6. Cleanup - - delete: - fields: [log.wrapper_open, log.wrapper_close, log.inner_msg, log.ufw_data, log.separator] diff --git a/filters/linux/linux.yml b/filters/linux/linux.yml index 7dad671a1..554eae9c8 100644 --- a/filters/linux/linux.yml +++ b/filters/linux/linux.yml @@ -1,55 +1,470 @@ +# 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")' \ No newline at end of file diff --git a/filters/paloalto/pa_cortex_xdr.yml b/filters/paloalto/pa_cortex_xdr.yml deleted file mode 100644 index 81a664a47..000000000 --- a/filters/paloalto/pa_cortex_xdr.yml +++ /dev/null @@ -1,295 +0,0 @@ -pipeline: - - dataTypes: - - paloalto-cortex-xdr - steps: - # ================================================================================== - # 1. CEF / LEEF Handling - # ================================================================================== - - grok: - source: raw - where: 'contains(raw, "CEF:") || contains(raw, "LEEF:")' - patterns: - - fieldName: log.format_type - pattern: '{{.word}}' # Extracts CEF or LEEF - - fieldName: log.ignore - pattern: ':' - - fieldName: log.format_version - pattern: '{{.data}}' # Extracts version until next | - - fieldName: log.ignore - pattern: '\|' - - fieldName: log.vendor - pattern: '{{.data}}' - - fieldName: log.ignore - pattern: '\|' - - fieldName: log.product - pattern: '{{.data}}' - - fieldName: log.ignore - pattern: '\|' - - fieldName: log.device_version - pattern: '{{.data}}' - - fieldName: log.ignore - pattern: '\|' - - fieldName: log.event_class - pattern: '{{.data}}' - - fieldName: log.ignore - pattern: '\|' - - fieldName: log.name - pattern: '{{.data}}' - - fieldName: log.ignore - pattern: '\|' - - fieldName: log.severity - pattern: '{{.data}}' - - fieldName: log.ignore - pattern: '\|' - - fieldName: log.extension - pattern: '{{.greedy}}' - - - kv: - source: log.extension - where: 'exists("log.extension")' - fieldSplit: " " - valueSplit: "=" - - # Cleanup CEF fields - - delete: - fields: [log.ignore] - - # ================================================================================== - # 2. CSV Handling - Threat Logs - # ================================================================================== - # Regex: (threat)(\s)?,... - - csv: - source: raw - where: 'regexMatch(raw, "^(threat)(\\s)?,.*")' - separator: "," - headers: - - log.recordType - - log.class - - log.FUTURE_USE - - log.eventType - - log.generatedTime - - log.serverTime - - log.agentTime - - log.tzOffset - - log.FUTURE_USE_2 - - log.facility - - log.customerId - - log.trapsId - - log.serverHost - - log.serverComponentVersion - - log.regionId - - log.isEndpoint - - log.agentId - - log.osType - - log.isVdi - - log.osVersion - - log.is64 - - log.agentIp - - log.deviceName - - log.deviceDomain - - log.severity - - log.trapsSeverity - - log.agentVersion - - log.contentVersion - - log.protectionStatus - - log.preventionKey - - log.moduleId - - log.profile - - log.moduleStatusId - - log.verdict - - log.preventionMode - - log.terminate - - log.terminateTarget - - log.quarantine - - log.block - - log.postDetected - - log.eventParameters - - log.sourceProcessIdx - - log.targetProcessIdx - - log.fileIdx - - log.processes - - log.files - - log.users - - log.urls - - log.description - - # ================================================================================== - # 3. CSV Handling - Config / Policy / System Management - # ================================================================================== - # Regex: ^(config|system),.* - # Note: The conf groups these together for Config Logs + System Logs separate. - # Config Logs column mapping: - - csv: - source: raw - where: 'regexMatch(raw, "^config,.*")' - separator: "," - headers: - - log.recordType - - log.class - - log.FUTURE_USE - - log.subClassId - - log.eventType - - log.eventCategory - - log.generatedTime - - log.serverTime - - log.FUTURE_USE_2 - - log.facility - - log.customerId - - log.trapsId - - log.serverHost - - log.serverComponentVersion - - log.regionId - - log.isEndpoint - - log.severity - - log.trapsSeverity - - log.messageCode - - log.friendlyName - - log.FUTURE_USE_3 - - log.msgTextEn - - log.userFullName - - log.userName - - log.userRole - - log.userDomain - - log.additionalData - - log.messageCode2 - - log.errorText - - log.errorData - - log.resultData - - # ================================================================================== - # 4. CSV Handling - Analytics Logs - # ================================================================================== - - csv: - source: raw - where: 'regexMatch(raw, "^analytics,.*")' - separator: "," - headers: - - log.recordType - - log.class - - log.FUTURE_USE - - log.eventType - - log.eventCategory - - log.generatedTime - - log.serverTime - - log.agentTime - - log.tzOffset - - log.FUTURE_USE_2 - - log.facility - - log.customerId - - log.trapsId - - log.serverHost - - log.serverComponentVersion - - log.regionId - - log.isEndpoint - - log.agentId - - log.osType - - log.isVdi - - log.osVersion - - log.is64 - - log.agentIp - - log.deviceName - - log.deviceDomain - - log.severity - - log.agentVersion - - log.contentVersion - - log.protectionStatus - - log.sha256 - - log.type - - log.parentSha256 - - log.lastSeen - - log.fileName - - log.filePath - - log.fileSize - - log.localAnalysisResult - - log.reported - - log.blocked - - log.executionCount - - # ================================================================================== - # 5. CSV Handling - System Logs - # ================================================================================== - - csv: - source: raw - where: 'regexMatch(raw, "^system,.*")' - separator: "," - headers: - - log.recordType - - log.class - - log.FUTURE_USE - - log.subClassId - - log.eventType - - log.eventCategory - - log.generatedTime - - log.serverTime - - log.FUTURE_USE_2 - - log.facility - - log.customerId - - log.trapsId - - log.serverHost - - log.serverComponentVersion - - log.regionId - - log.isEndpoint - - log.agentId - - log.severity - - log.trapsSeverity - - log.messageCode - - log.friendlyName - - log.FUTURE_USE_3 - - log.msgTextEn - - log.userFullName - - log.userName - - log.userRole - - log.userDomain - - log.agentTime - - log.tzOffset - - log.osType - - log.isVdi - - log.osVersion - - log.is64 - - log.agentIp - - log.deviceName - - log.deviceDomain - - log.agentVersion - - log.contentVersion - - log.protectionStatus - - log.userFullName2 - - log.username2 - - log.userRole2 - - log.userDomain2 - - log.messageName - - log.messageId - - log.processStatus - - log.errorText - - log.errorData - - log.resultData - - log.parameters - - log.additionalData - - # ================================================================================== - # 6. Standard Mappings - # ================================================================================== - # Map fields extracted from CEF/CSV to standard UTMStack schema (origin.ip, target.ip, etc) - # Assuming KV filter extracted typical CEF keys like src, dst, spt, dpt - - - rename: - from: [log.src, log.u_srcIp] # u_srcIp might be from CSV if named differently? No, CSV columns are named above. - to: origin.ip - where: 'exists("log.src")' - - rename: - from: [log.agentIp] # From CSV - to: origin.ip - where: 'exists("log.agentIp") && !exists("origin.ip")' - - - rename: - from: [log.dst] - to: target.ip - - rename: - from: [log.spt, log.srcPort] - to: origin.port - - rename: - from: [log.dpt, log.dstPort] - to: target.port - - # Clean up FUTURE_USE fields - - delete: - fields: [log.FUTURE_USE, log.FUTURE_USE_2, log.FUTURE_USE_3] diff --git a/filters/windows/windows-events.yml b/filters/windows/windows-events.yml index 9f5f109f5..0b277730c 100644 --- a/filters/windows/windows-events.yml +++ b/filters/windows/windows-events.yml @@ -296,7 +296,7 @@ pipeline: - rename: from: - - log.log.level + - log.level to: log.severityLabel - rename: @@ -304,11 +304,6 @@ pipeline: - log.api to: log.api - - rename: - from: - - log.channel - to: log.channel - - rename: from: - log.ecs.version @@ -334,6 +329,56 @@ pipeline: - log.data.ObjectType to: log.eventDataObjectType + - rename: + from: + - log.data.OperationType + to: log.eventDataOperationType + + - rename: + from: + - log.data.TicketEncryptionType + to: log.eventDataTicketEncryptionType + + - rename: + from: + - log.data.PreAuthType + to: log.eventDataPreAuthType + + - rename: + from: + - log.data.TicketOptions + to: log.eventDataTicketOptions + + - rename: + from: + - log.data.ProcessPath + to: log.eventDataProcessPath + + - rename: + from: + - log.data.ImagePath + to: log.eventDataImagePath + + - rename: + from: + - log.data.ServiceType + to: log.eventDataServiceType + + - rename: + from: + - log.data.StartType + to: log.eventDataStartType + + - rename: + from: + - log.data.FileName + to: log.eventDataFileName + + - rename: + from: + - log.data.LinkName + to: log.eventDataLinkName + - rename: from: - log.data.AccessList @@ -374,6 +419,26 @@ pipeline: - log.data.TransactionId to: log.eventDataTransactionId + - rename: + from: + - log.data.ScriptBlockText + to: log.eventDataScriptBlockText + + - rename: + from: + - log.data.MessageNumber + to: log.eventDataMessageNumber + + - rename: + from: + - log.data.MessageTotal + to: log.eventDataMessageTotal + + - rename: + from: + - log.data.ScriptBlockId + to: log.eventDataScriptBlockId + - cast: to: "int" fields: @@ -403,7 +468,7 @@ pipeline: # Drop unnecessary events - drop: - where: "oneOf('log.eventCode', [0, 1, 43, 44, 1040, 1042, 1105, 1500, 1501, 4608, 4609, 4614, 4615, 4616, 4626, 4627, 4650, 4651, 4652, 4653, 4654, 4655, 4659, 4665, 4666, 4667, 4668, 4688, 4689, 4696, 4709, 4710, 4711, 4712, 4778, 4779, 4826, 4864, 4866, 4898, 4899, 4902, 4904, 4905, 4906, 4909, 4910, 4911, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4944, 4945, 4951, 4952, 4953, 4957, 4958, 4965, 4979, 4980, 4981, 4982, 4983, 4984, 4985, 5024, 5027, 5028, 5029, 5033, 5034, 5035, 5038, 5039, 5051, 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5120, 5121, 5122, 5123, 5125, 5126, 5127, 5137, 5138, 5139, 5141, 5145, 5168, 5169, 5170, 5376, 5377, 5378, 5379, 5380, 5381, 5440, 5441, 5442, 5443, 5444, 5446, 5450, 5451, 5452, 5456, 5457, 5458, 5459, 5460, 5461, 5462, 5463, 5464, 5465, 5466, 5467, 5468, 5471, 5472, 5473, 5474, 5477, 5478, 5712, 5888, 5889, 5890, 6145, 6274, 6275, 6281, 6400, 6401, 6402, 6403, 6405, 6406, 6407, 6408, 6409, 6410, 6417, 6418, 6423, 6424, 7040, 8191, 10000, 10010, 16384, 16394, 24578, 24579, 24581, 24582, 24583, 24584, 24586, 24588, 24592, 24593, 24594, 24595, 24621])" + where: "oneOf('log.eventCode', [0, 1, 43, 44, 1040, 1042, 1105, 1500, 1501, 4608, 4609, 4614, 4615, 4616, 4626, 4627, 4650, 4651, 4652, 4653, 4654, 4655, 4659, 4665, 4666, 4667, 4668, 4689, 4696, 4709, 4710, 4711, 4712, 4778, 4779, 4826, 4864, 4866, 4898, 4899, 4902, 4904, 4905, 4906, 4909, 4910, 4911, 4928, 4929, 4930, 4931, 4932, 4933, 4934, 4935, 4936, 4937, 4944, 4945, 4951, 4952, 4953, 4957, 4958, 4965, 4979, 4980, 4981, 4982, 4983, 4984, 4985, 5024, 5027, 5028, 5029, 5033, 5034, 5035, 5038, 5039, 5051, 5056, 5057, 5058, 5059, 5060, 5061, 5062, 5063, 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, 5120, 5121, 5122, 5123, 5125, 5126, 5127, 5137, 5138, 5139, 5141, 5145, 5168, 5169, 5170, 5376, 5377, 5378, 5379, 5380, 5381, 5440, 5441, 5442, 5443, 5444, 5446, 5450, 5451, 5452, 5456, 5457, 5458, 5459, 5460, 5461, 5462, 5463, 5464, 5465, 5466, 5467, 5468, 5471, 5472, 5473, 5474, 5477, 5478, 5712, 5888, 5889, 5890, 6145, 6274, 6275, 6281, 6400, 6401, 6402, 6403, 6405, 6406, 6407, 6408, 6409, 6410, 6417, 6418, 6423, 6424, 7040, 8191, 10000, 10010, 16384, 16394, 24578, 24579, 24581, 24582, 24583, 24584, 24586, 24588, 24592, 24593, 24594, 24595, 24621])" # Decoding event code - add: @@ -2949,7 +3014,6 @@ pipeline: - log.agent - log.host - log.computer_name - - log.data - log.process - log.metadata - log.event diff --git a/frontend/package.json b/frontend/package.json index aba386502..9abddd4c4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -32,7 +32,7 @@ "angular2-uuid": "^1.1.1", "animate.css": "^3.7.0", "bootstrap": "^4.3.1", - "core-js": "^2.5.4", + "core-js": "^2.6.12", "echarts": "^4.4.0", "echarts-gl": "^1.1.1", "echarts-leaflet": "^1.1.0", @@ -45,7 +45,7 @@ "highlight.js": "9.12.0", "html2canvas": "^1.0.0-rc.1", "interactjs": "^1.4.0-rc.13", - "jquery": "^3.6.0", + "jquery": "^3.7.1", "jquery-ui": "^1.13.2", "js-yaml": "^4.1.0", "jspdf": "^2.3.1", @@ -53,7 +53,7 @@ "leaflet.heat": "^0.2.0", "lodash": "^4.17.21", "magic-check": "^1.0.3", - "moment": "^2.29.4", + "moment": "^2.30.1", "moment-timezone": "^0.5.21", "monaco-editor": "^0.20.0", "net": "^1.0.2", @@ -81,7 +81,7 @@ "stompjs": "^2.3.3", "table-dragger": "^1.0.3", "tether": "^1.4.6", - "tslib": "^1.9.0", + "tslib": "^1.14.1", "webstomp-client": "^1.2.6", "zone.js": "~0.8.26" }, diff --git a/frontend/src/app/app-module/conf/int-generic-group-config/int-generic-group-config.component.html b/frontend/src/app/app-module/conf/int-generic-group-config/int-generic-group-config.component.html index 5dfb2f720..1fc83061e 100644 --- a/frontend/src/app/app-module/conf/int-generic-group-config/int-generic-group-config.component.html +++ b/frontend/src/app/app-module/conf/int-generic-group-config/int-generic-group-config.component.html @@ -119,11 +119,14 @@ && integrationConfig.confDataType !== 'select' && integrationConfig.confDataType !== 'file'" (input)="addChange(integrationConfig)" + (focus)="onPasswordFocus(integrationConfig)" + (blur)="onPasswordBlur(integrationConfig)" [(ngModel)]="integrationConfig.confValue" [attr.autocomplete]="'disabled'" [id]="'sectionParam'+integrationConfig.id" [name]="integrationConfig.confName" [type]="integrationConfig.confDataType" + [placeholder]="integrationConfig.confDataType === 'password' ? 'Enter new value to change' : ''" (ngModelChange)="integrationConfig.confOptions === 'unique' ? inputChange$.next({id: integrationConfig.groupId, value: $event}) : null" class="form-control" [required]="integrationConfig.confRequired"> diff --git a/frontend/src/app/app-module/conf/int-generic-group-config/int-generic-group-config.component.ts b/frontend/src/app/app-module/conf/int-generic-group-config/int-generic-group-config.component.ts index 03424208e..1ba7bb77a 100644 --- a/frontend/src/app/app-module/conf/int-generic-group-config/int-generic-group-config.component.ts +++ b/frontend/src/app/app-module/conf/int-generic-group-config/int-generic-group-config.component.ts @@ -23,13 +23,14 @@ import {IntegrationConfigFactory} from './int-config-types/IntegrationConfigFact templateUrl: './int-generic-group-config.component.html', styleUrls: ['./int-generic-group-config.component.css'] }) -export class IntGenericGroupConfigComponent implements OnInit, OnDestroy { +export class IntGenericGroupConfigComponent implements OnInit, OnChanges, OnDestroy { @Input() serverId: number; @Input() moduleId: number; @Input() groupType = GroupTypeEnum.TENANT; @Input() allowAdd = true; @Input() editable = true; @Input() disablePreAction = false; + @Input() hiddenValues: {[confKey: string]: string} = {}; @Output() configValidChange = new EventEmitter(); @Output() runDisablePreAction = new EventEmitter(); loading = true; @@ -57,6 +58,12 @@ export class IntGenericGroupConfigComponent implements OnInit, OnDestroy { private cdr: ChangeDetectorRef) { } + ngOnChanges(changes: SimpleChanges) { + if (changes.hiddenValues && !changes.hiddenValues.firstChange && this.groups.length > 0) { + this.applyHiddenValues(); + } + } + ngOnInit() { this.config = this.configFactory.getConfiguration(this.groupType); this.getGroups().subscribe(); @@ -98,11 +105,29 @@ export class IntGenericGroupConfigComponent implements OnInit, OnDestroy { return this.config.getIntegrationConfigs(this.moduleId) .pipe( tap(() => { + this.applyHiddenValues(); this.configValidChange.emit(this.tenantGroupConfigValid()); this.loading = false; })); } + applyHiddenValues() { + if (!this.hiddenValues || Object.keys(this.hiddenValues).length === 0) { + return; + } + for (const group of this.groups) { + for (const conf of group.moduleGroupConfigurations) { + if (this.hiddenValues[conf.confKey] !== undefined) { + const newValue = this.hiddenValues[conf.confKey]; + if (conf.confValue !== newValue) { + conf.confValue = newValue; + this.addChange(conf); + } + } + } + } + } + createGroup() { this.getGroups().subscribe(res => { const modal = this.modalService.open(IntCreateGroupComponent, {centered: true}); @@ -173,15 +198,16 @@ export class IntGenericGroupConfigComponent implements OnInit, OnDestroy { }) ).subscribe({ next: () => { - this.pendingChanges = false; - this.changes = { keys: [], moduleId: this.moduleId }; + // Remove only the saved group's changes, keep other groups' changes + this.changes.keys = this.changes.keys.filter(k => k.groupId !== group.id); + this.pendingChanges = this.changes.keys.length > 0; this.configValidChange.emit(this.tenantGroupConfigValid()); this.toast.showSuccessBottom('Configuration saved successfully'); }, error: err => { if (err.status === 400) { - this.toast.showError('Invalid Configuration', - 'The configuration data is invalid. Please check your inputs and try again.'); + const message = this.extractValidationError(err); + this.toast.showError('Invalid Configuration', message); } else { this.toast.showError('Error saving configuration', 'Error while trying to save tenant configuration, please try again.'); @@ -397,6 +423,10 @@ export class IntGenericGroupConfigComponent implements OnInit, OnDestroy { } isVisible(integrationConfig: UtmModuleGroupConfType): boolean { + // Hide fields that are set via hiddenValues + if (this.hiddenValues && this.hiddenValues[integrationConfig.confKey] !== undefined) { + return false; + } if (!integrationConfig.confVisibility) { return true; @@ -423,6 +453,43 @@ export class IntGenericGroupConfigComponent implements OnInit, OnDestroy { } + extractValidationError(err: any): string { + const defaultMsg = 'The configuration data is invalid. Please check your inputs and try again.'; + try { + const body = err.error; + // Spring fieldErrors format + if (body && body.fieldErrors && body.fieldErrors.length > 0) { + return body.fieldErrors.map(e => e.message).join('. '); + } + // Spring message format + if (body && body.message) { + return body.message; + } + // X-UtmStack-error header + const headerError = err.headers ? err.headers.get('X-UtmStack-error') : null; + if (headerError) { + return headerError; + } + // Plain string body + if (typeof body === 'string' && body.length > 0) { + return body; + } + } catch (e) {} + return defaultMsg; + } + + onPasswordFocus(config: UtmModuleGroupConfType) { + if (config.confDataType === 'password' && config.confValue === '*****') { + config.confValue = ''; + } + } + + onPasswordBlur(config: UtmModuleGroupConfType) { + if (config.confDataType === 'password' && (config.confValue === '' || config.confValue === null)) { + config.confValue = '*****'; + } + } + ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); diff --git a/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.css b/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.css index e69de29bb..ca8b5a424 100644 --- a/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.css +++ b/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.css @@ -0,0 +1,23 @@ +.provider-logo { + width: 20px; + height: 20px; + object-fit: contain; +} + +.nav-tabs .nav-link { + display: flex; + align-items: center; + padding: 8px 14px; + font-size: 13px; +} + +:host ::ng-deep .step-guide a, +:host ::ng-deep p a { + color: #2563eb; + text-decoration: underline; +} + +:host ::ng-deep .step-guide a:hover, +:host ::ng-deep p a:hover { + color: #1d4ed8; +} diff --git a/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.html b/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.html index 2d40711cb..35ae48c9e 100644 --- a/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.html +++ b/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.html @@ -1,52 +1,171 @@
-

- SOC AI -

+

SOC AI

-
    -
  1. -

    - 1 Access the API key by logging in to your OpenAI account and navigating to - the - API section - IAM configuration -

  2. -
  3. -

    - 2 Create a new API key, and copy the value -

    - IAM configuration -
  4. -
  5. -

    - 3 Paste the API Key in the form below: -

    -
    -
    - -
    -
    - -
  6. -
  7. -

    - 4 - Click on the button shown below, to activate the UTMStack features related to this integration -

    - - -
  8. -
+ +

+ SOC AI enhances your security operations by integrating advanced language models directly into your alert investigation workflow. + It automatically analyzes alerts, identifies patterns, prioritizes threats, and provides actionable insights to accelerate incident response. + Connect any of the supported AI providers below to get started. + If your provider is not listed, you can use the Custom tab to configure any service that supports the OpenAI-compatible chat completions format. +

+ +
+ +
+ + + + + + + + {{ provider.name }} + + +
+ +

+ + +
+ + +
+ + + + {{ field.label }} is required + +
+ + +
+ + + +
+ +
+ +
+
+ + {{ field.label }} is required + +
+ + +
+ + + + + + + + + + + + + + + + + + + +
Header NameHeader Value
+ + + + + +
+ No headers configured. Click "Add Header" to add one. +
+ +
+ + +
+ + +
+
+
+ + +
+ + + +
+
+
+
+
+
+
diff --git a/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.ts b/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.ts index 958c842b0..7d6e28aea 100644 --- a/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.ts +++ b/frontend/src/app/app-module/guides/guide-soc-ai/guide-soc-ai.component.ts @@ -1,5 +1,28 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core'; import {UtmModulesEnum} from '../../shared/enum/utm-module.enum'; +import {UtmModuleGroupService} from '../../shared/services/utm-module-group.service'; +import {UtmModuleGroupConfService} from '../../shared/services/utm-module-group-conf.service'; +import {UtmModuleGroupConfType} from '../../shared/type/utm-module-group-conf.type'; +import {UtmToastService} from '../../../shared/alert/utm-toast.service'; +import {ModuleChangeStatusBehavior} from '../../shared/behavior/module-change-status.behavior'; + +interface ProviderConfig { + id: string; + name: string; + logo: string; + description: string; + fields: ProviderField[]; +} + +interface ProviderField { + key: string; + label: string; + type: 'text' | 'password' | 'select' | 'number' | 'toggle' | 'headers'; + required?: boolean; + placeholder?: string; + options?: {value: string, label: string}[]; + tooltip?: string; +} @Component({ selector: 'app-guide-soc-ai', @@ -8,18 +31,527 @@ import {UtmModulesEnum} from '../../shared/enum/utm-module.enum'; }) export class GuideSocAiComponent implements OnInit { @Input() integrationId: number; - module = UtmModulesEnum; @Input() serverId: number; - configValidity = false; + module = UtmModulesEnum; - constructor() { - } + activeProvider = 'openai'; + saving = false; + loading = true; + + // Form values - what the user sees/edits + formValues: {[key: string]: string} = {}; + customModelValue = ''; + + // Editable headers table for custom provider + headerRows: {key: string, value: string}[] = []; + + // Cache form values per provider so switching tabs preserves edits + private providerFormCache: {[providerId: string]: {values: {[key: string]: string}, customModel: string, headers: {key: string, value: string}[]}} = {}; + + // Raw configs from DB (to get IDs for saving) + private rawConfigs: UtmModuleGroupConfType[] = []; + private groupId: number; + + providers: ProviderConfig[] = [ + { + id: 'openai', + name: 'OpenAI', + logo: 'assets/img/guides/soc-ai/providers/openai.svg', + description: 'Obtain an API key from your OpenAI account. If you need help, see Where do I find my API key?', + fields: [ + {key: 'apiKey', label: 'API Key', type: 'password', required: true, placeholder: 'sk-...'}, + {key: 'model', label: 'Model', type: 'select', required: true, options: [ + {value: 'gpt-5.4', label: 'gpt-5.4'}, + {value: 'gpt-5.4-mini', label: 'gpt-5.4-mini'}, + {value: 'gpt-5.4-nano', label: 'gpt-5.4-nano'}, + {value: 'gpt-4.1', label: 'gpt-4.1'}, + {value: 'gpt-4.1-mini', label: 'gpt-4.1-mini'}, + {value: 'gpt-4.1-nano', label: 'gpt-4.1-nano'}, + {value: 'gpt-4o', label: 'gpt-4o'}, + {value: 'gpt-4o-mini', label: 'gpt-4o-mini'}, + {value: 'o3-mini', label: 'o3-mini'}, + {value: '__custom__', label: 'Custom model...'}, + ]}, + {key: 'autoAnalyze', label: 'Auto-analyze alerts', type: 'toggle', tooltip: 'Automatically send new alerts for AI analysis'}, + {key: 'incidentCreation', label: 'Auto-create incidents', type: 'toggle', tooltip: 'Automatically create incidents based on AI analysis'}, + {key: 'changeAlertStatus', label: 'Change alert status after analysis', type: 'toggle', tooltip: 'Allow SOC AI to update alert status after analysis'}, + ] + }, + { + id: 'anthropic', + name: 'Anthropic', + logo: 'assets/img/guides/soc-ai/providers/anthropic.svg', + description: 'Obtain an API key from Anthropic Console.', + fields: [ + {key: 'apiKey', label: 'API Key', type: 'password', required: true, placeholder: 'sk-ant-...'}, + {key: 'model', label: 'Model', type: 'select', required: true, options: [ + {value: 'claude-sonnet-4-20250514', label: 'claude-sonnet-4-20250514'}, + {value: 'claude-haiku-4-20250414', label: 'claude-haiku-4-20250414'}, + {value: 'claude-opus-4-20250514', label: 'claude-opus-4-20250514'}, + {value: '__custom__', label: 'Custom model...'}, + ]}, + {key: 'maxTokens', label: 'Max Tokens', type: 'number', required: true, placeholder: '4096', tooltip: 'Required for Anthropic'}, + {key: 'autoAnalyze', label: 'Auto-analyze alerts', type: 'toggle'}, + {key: 'incidentCreation', label: 'Auto-create incidents', type: 'toggle'}, + {key: 'changeAlertStatus', label: 'Change alert status after analysis', type: 'toggle'}, + ] + }, + { + id: 'azure', + name: 'Azure OpenAI', + logo: 'assets/img/guides/soc-ai/providers/azure.svg', + description: 'Create an Azure OpenAI resource in the Azure Portal, deploy a model, and copy your API key from Keys and Endpoint.', + fields: [ + {key: 'apiKey', label: 'API Key', type: 'password', required: true}, + {key: 'url', label: 'Endpoint URL', type: 'text', required: true, placeholder: 'https://YOUR-RESOURCE.openai.azure.com/openai/deployments/YOUR-DEPLOYMENT/chat/completions?api-version=2024-02-01'}, + {key: 'model', label: 'Model', type: 'text', required: true, placeholder: 'gpt-4o'}, + {key: 'autoAnalyze', label: 'Auto-analyze alerts', type: 'toggle'}, + {key: 'incidentCreation', label: 'Auto-create incidents', type: 'toggle'}, + {key: 'changeAlertStatus', label: 'Change alert status after analysis', type: 'toggle'}, + ] + }, + { + id: 'gemini', + name: 'Google Gemini', + logo: 'assets/img/guides/soc-ai/providers/gemini.svg', + description: 'Obtain an API key from Google AI Studio.', + fields: [ + {key: 'apiKey', label: 'API Key', type: 'password', required: true}, + {key: 'model', label: 'Model', type: 'select', required: true, options: [ + {value: 'gemini-2.5-flash', label: 'gemini-2.5-flash'}, + {value: 'gemini-2.5-pro', label: 'gemini-2.5-pro'}, + {value: 'gemini-2.0-flash', label: 'gemini-2.0-flash'}, + {value: '__custom__', label: 'Custom model...'}, + ]}, + {key: 'autoAnalyze', label: 'Auto-analyze alerts', type: 'toggle'}, + {key: 'incidentCreation', label: 'Auto-create incidents', type: 'toggle'}, + {key: 'changeAlertStatus', label: 'Change alert status after analysis', type: 'toggle'}, + ] + }, + { + id: 'ollama', + name: 'Ollama', + logo: 'assets/img/guides/soc-ai/providers/ollama.svg', + description: 'Install Ollama from ollama.ai and pull a model (ollama pull llama3). No API key required.', + fields: [ + {key: 'url', label: 'Ollama Server URL', type: 'text', required: true, placeholder: 'http://YOUR-SERVER:11434/v1/chat/completions'}, + {key: 'model', label: 'Model', type: 'text', required: true, placeholder: 'llama3'}, + {key: 'autoAnalyze', label: 'Auto-analyze alerts', type: 'toggle'}, + {key: 'incidentCreation', label: 'Auto-create incidents', type: 'toggle'}, + {key: 'changeAlertStatus', label: 'Change alert status after analysis', type: 'toggle'}, + ] + }, + { + id: 'mistral', + name: 'Mistral AI', + logo: 'assets/img/guides/soc-ai/providers/mistral.svg', + description: 'Obtain an API key from Mistral Console.', + fields: [ + {key: 'apiKey', label: 'API Key', type: 'password', required: true}, + {key: 'model', label: 'Model', type: 'select', required: true, options: [ + {value: 'mistral-large-latest', label: 'mistral-large-latest'}, + {value: 'mistral-small-latest', label: 'mistral-small-latest'}, + {value: 'mistral-medium-latest', label: 'mistral-medium-latest'}, + {value: '__custom__', label: 'Custom model...'}, + ]}, + {key: 'autoAnalyze', label: 'Auto-analyze alerts', type: 'toggle'}, + {key: 'incidentCreation', label: 'Auto-create incidents', type: 'toggle'}, + {key: 'changeAlertStatus', label: 'Change alert status after analysis', type: 'toggle'}, + ] + }, + { + id: 'deepseek', + name: 'DeepSeek', + logo: 'assets/img/guides/soc-ai/providers/deepseek.svg', + description: 'Obtain an API key from DeepSeek Platform.', + fields: [ + {key: 'apiKey', label: 'API Key', type: 'password', required: true}, + {key: 'model', label: 'Model', type: 'select', required: true, options: [ + {value: 'deepseek-chat', label: 'deepseek-chat'}, + {value: 'deepseek-reasoner', label: 'deepseek-reasoner'}, + {value: '__custom__', label: 'Custom model...'}, + ]}, + {key: 'autoAnalyze', label: 'Auto-analyze alerts', type: 'toggle'}, + {key: 'incidentCreation', label: 'Auto-create incidents', type: 'toggle'}, + {key: 'changeAlertStatus', label: 'Change alert status after analysis', type: 'toggle'}, + ] + }, + { + id: 'groq', + name: 'Groq', + logo: 'assets/img/guides/soc-ai/providers/groq.svg', + description: 'Obtain an API key from Groq Console.', + fields: [ + {key: 'apiKey', label: 'API Key', type: 'password', required: true}, + {key: 'model', label: 'Model', type: 'select', required: true, options: [ + {value: 'llama-3.3-70b-versatile', label: 'llama-3.3-70b-versatile'}, + {value: 'llama-3.1-8b-instant', label: 'llama-3.1-8b-instant'}, + {value: 'mixtral-8x7b-32768', label: 'mixtral-8x7b-32768'}, + {value: '__custom__', label: 'Custom model...'}, + ]}, + {key: 'autoAnalyze', label: 'Auto-analyze alerts', type: 'toggle'}, + {key: 'incidentCreation', label: 'Auto-create incidents', type: 'toggle'}, + {key: 'changeAlertStatus', label: 'Change alert status after analysis', type: 'toggle'}, + ] + }, + { + id: 'custom', + name: 'Custom', + logo: 'assets/img/guides/soc-ai/providers/custom.svg', + description: 'Configure any provider that supports the OpenAI-compatible /chat/completions format.', + fields: [ + {key: 'url', label: 'API URL', type: 'text', required: true, placeholder: 'https://your-provider.com/v1/chat/completions'}, + {key: 'model', label: 'Model', type: 'text', required: true, placeholder: 'model-name'}, + {key: 'authType', label: 'Auth Type', type: 'select', options: [ + {value: 'custom-headers', label: 'Custom Headers'}, + {value: 'none', label: 'None'}, + ]}, + {key: 'customHeaders', label: 'Custom Headers', type: 'headers'}, + {key: 'maxTokens', label: 'Max Tokens', type: 'number', placeholder: '4096'}, + {key: 'autoAnalyze', label: 'Auto-analyze alerts', type: 'toggle'}, + {key: 'incidentCreation', label: 'Auto-create incidents', type: 'toggle'}, + {key: 'changeAlertStatus', label: 'Change alert status after analysis', type: 'toggle'}, + ] + }, + ]; + + // Map provider to their auth header format + private providerAuthHeaders: {[providerId: string]: {headerName: string, headerValuePrefix: string}} = { + 'openai': {headerName: 'Authorization', headerValuePrefix: 'Bearer '}, + 'anthropic': {headerName: 'x-api-key', headerValuePrefix: ''}, + 'azure': {headerName: 'api-key', headerValuePrefix: ''}, + 'gemini': {headerName: 'Authorization', headerValuePrefix: 'Bearer '}, + 'mistral': {headerName: 'Authorization', headerValuePrefix: 'Bearer '}, + 'deepseek': {headerName: 'Authorization', headerValuePrefix: 'Bearer '}, + 'groq': {headerName: 'Authorization', headerValuePrefix: 'Bearer '}, + }; + + // Map from our form keys to backend confKeys + private keyMap = { + 'model': 'utmstack.socai.model', + 'url': 'utmstack.socai.url', + 'maxTokens': 'utmstack.socai.maxTokens', + 'authType': 'utmstack.socai.authType', + 'customHeaders': 'utmstack.socai.customHeaders', + 'autoAnalyze': 'utmstack.socai.autoAnalyze', + 'incidentCreation': 'utmstack.socai.incidentCreation', + 'changeAlertStatus': 'utmstack.socai.changeAlertStatus', + }; + + constructor( + private moduleGroupService: UtmModuleGroupService, + private moduleGroupConfService: UtmModuleGroupConfService, + private toast: UtmToastService, + private moduleChangeStatusBehavior: ModuleChangeStatusBehavior, + private cdr: ChangeDetectorRef + ) {} ngOnInit() { + this.loadConfig(); + } + + get currentProvider(): ProviderConfig { + return this.providers.find(p => p.id === this.activeProvider); + } + + onTabChange(event: any) { + // Save current form state + this.providerFormCache[this.activeProvider] = { + values: {...this.formValues}, + customModel: this.customModelValue, + headers: (this.headerRows||[]).map(r => ({...r})) + }; + + this.activeProvider = event.nextId; + + // Restore from cache or init fresh + const cached = this.providerFormCache[this.activeProvider]; + if (cached) { + this.formValues = {...cached.values}; + this.customModelValue = cached.customModel; + this.headerRows = cached.headers.map(r => ({...r})); + } else { + this.initFormValues(); + } + } + + getModelValue(): string { + if (this.formValues['model'] === '__custom__') { + return this.customModelValue; + } + return this.formValues['model'] || ''; + } + + isFormValid(): boolean { + const provider = this.currentProvider; + return provider.fields + .filter(f => f.required) + .every(f => { + if (f.key === 'model') { + return !!this.getModelValue(); + } + const val = this.formValues[f.key]; + return val !== undefined && val !== null && val !== ''; + }); + } + + private loadConfig() { + this.loading = true; + this.moduleGroupService.query({moduleId: this.integrationId}).subscribe(response => { + const groups = response.body || []; + if (groups.length > 0) { + this.groupId = groups[0].id; + this.rawConfigs = groups[0].moduleGroupConfigurations || []; + this.loadCurrentProvider(); + this.initFormValues(); + // Cache the initial loaded values for the saved provider + this.providerFormCache[this.activeProvider] = { + values: {...this.formValues}, + customModel: this.customModelValue, + headers: [...this.headerRows.map(r => ({...r}))] + }; + } + this.loading = false; + this.cdr.detectChanges(); + }, () => { + this.loading = false; + this.cdr.detectChanges(); + }); } - configValidChange($event: boolean) { - this.configValidity = !$event; + private loadCurrentProvider() { + const providerConf = this.rawConfigs.find(c => c.confKey === 'utmstack.socai.provider'); + if (providerConf && providerConf.confValue) { + this.activeProvider = providerConf.confValue; + } + this.savedProvider = this.activeProvider; } + private savedProvider: string; + + private initFormValues() { + const isCurrentSavedProvider = this.activeProvider === this.savedProvider; + + // Always load behavior toggles from DB + const autoAnalyze = this.getConf('utmstack.socai.autoAnalyze'); + const incidentCreation = this.getConf('utmstack.socai.incidentCreation'); + const changeStatus = this.getConf('utmstack.socai.changeAlertStatus'); + + // Start clean + this.formValues = { + 'autoAnalyze': autoAnalyze ? autoAnalyze.confValue : 'false', + 'incidentCreation': incidentCreation ? incidentCreation.confValue : 'false', + 'changeAlertStatus': changeStatus ? changeStatus.confValue : 'false', + }; + this.customModelValue = ''; + + // Only load provider-specific values if viewing the saved provider + if (isCurrentSavedProvider) { + const modelConf = this.getConf('utmstack.socai.model'); + if (modelConf && modelConf.confValue) { + // Check if the model value matches any option in the current provider + const provider = this.currentProvider; + const modelField = provider.fields.find(f => f.key === 'model'); + if (modelField && modelField.options) { + const match = modelField.options.find(o => o.value === modelConf.confValue); + if (match) { + this.formValues['model'] = modelConf.confValue; + } else { + this.formValues['model'] = '__custom__'; + this.customModelValue = modelConf.confValue; + } + } else { + this.formValues['model'] = modelConf.confValue; + } + } + + const urlConf = this.getConf('utmstack.socai.url'); + if (urlConf) { + this.formValues['url'] = urlConf.confValue || ''; + } + + // Check if API key exists in custom headers — show masked if so + const customHeaders = this.getConf('utmstack.socai.customHeaders'); + if (customHeaders && customHeaders.confValue && customHeaders.confValue !== '{}') { + try { + const headers = JSON.parse(customHeaders.confValue); + const authConfig = this.providerAuthHeaders[this.activeProvider]; + if (authConfig && headers[authConfig.headerName]) { + // API key exists — show masked, don't expose the real value + this.formValues['apiKey'] = '*****'; + } + } catch (e) {} + this.formValues['customHeaders'] = customHeaders.confValue; + this.parseHeadersFromJson(customHeaders.confValue); + } + + const maxTokensConf = this.getConf('utmstack.socai.maxTokens'); + if (maxTokensConf) { + this.formValues['maxTokens'] = maxTokensConf.confValue || ''; + } + + const authType = this.getConf('utmstack.socai.authType'); + if (authType) { + this.formValues['authType'] = authType.confValue || 'custom-headers'; + } + } else { + this.headerRows = []; + // Set defaults for the new provider + this.setFieldDefaults(); + } + } + + private setFieldDefaults() { + const provider = this.currentProvider; + for (const field of provider.fields) { + if (field.type === 'select' && field.options && field.options.length > 0 && !this.formValues[field.key]) { + this.formValues[field.key] = field.options[0].value; + } + if (field.key === 'maxTokens' && !this.formValues['maxTokens']) { + this.formValues['maxTokens'] = '4096'; + } + } + } + + private getConf(confKey: string): UtmModuleGroupConfType { + return this.rawConfigs.find(c => c.confKey === confKey); + } + + save() { + this.saving = true; + const changes: UtmModuleGroupConfType[] = []; + + // Set provider + this.pushChange(changes, 'utmstack.socai.provider', this.activeProvider); + + // Set model + this.pushChange(changes, 'utmstack.socai.model', this.getModelValue()); + + // Set URL for providers that need it (azure, ollama, custom) + if (this.formValues['url']) { + this.pushChange(changes, 'utmstack.socai.url', this.formValues['url']); + } + + // Set maxTokens + if (this.formValues['maxTokens']) { + this.pushChange(changes, 'utmstack.socai.maxTokens', this.formValues['maxTokens']); + } + + // Set behavior toggles + this.pushChange(changes, 'utmstack.socai.autoAnalyze', this.formValues['autoAnalyze'] || 'false'); + this.pushChange(changes, 'utmstack.socai.incidentCreation', this.formValues['incidentCreation'] || 'false'); + this.pushChange(changes, 'utmstack.socai.changeAlertStatus', this.formValues['changeAlertStatus'] || 'false'); + + // Build auth headers + if (this.activeProvider === 'custom') { + // Custom provider: user manages auth type and headers directly + this.pushChange(changes, 'utmstack.socai.authType', this.formValues['authType'] || 'custom-headers'); + this.pushChange(changes, 'utmstack.socai.customHeaders', this.formValues['customHeaders'] || '{}'); + } else if (this.activeProvider === 'ollama') { + // Ollama: no auth needed + this.pushChange(changes, 'utmstack.socai.authType', 'none'); + this.pushChange(changes, 'utmstack.socai.customHeaders', '{}'); + } else { + // Known providers: build auth header from API key + const authConfig = this.providerAuthHeaders[this.activeProvider]; + if (authConfig && this.formValues['apiKey'] && this.formValues['apiKey'] !== '*****') { + // User entered a new API key — build auth headers + const headers: {[k: string]: string} = {}; + headers[authConfig.headerName] = authConfig.headerValuePrefix + this.formValues['apiKey']; + this.pushChange(changes, 'utmstack.socai.authType', 'custom-headers'); + this.pushChange(changes, 'utmstack.socai.customHeaders', JSON.stringify(headers)); + } + // If apiKey is '*****', don't touch customHeaders — keep existing value in DB + } + + this.moduleGroupConfService.update({ + keys: changes, + moduleId: this.integrationId + }).subscribe( + () => { + this.saving = false; + this.cdr.markForCheck() + this.toast.showSuccessBottom('SOC AI configuration saved successfully'); + }, + (err) => { + this.saving = false; + this.cdr.markForCheck() + if (err.status === 400) { + const message = this.extractValidationError(err); + this.toast.showError('Invalid Configuration', message); + } else { + this.toast.showError('Error', 'Failed to save configuration. Please try again.'); + } + } + ); + } + + private pushChange(changes: UtmModuleGroupConfType[], confKey: string, value: string) { + const existing = this.getConf(confKey); + if (existing) { + changes.push({ + ...existing, + confValue: value, + confOptions: existing.confOptions ? JSON.stringify(existing.confOptions) : existing.confOptions, + confVisibility: existing.confVisibility ? JSON.stringify(existing.confVisibility) : existing.confVisibility, + }); + } + } + + private extractValidationError(err: any): string { + const defaultMsg = 'The configuration data is invalid. Please check your inputs and try again.'; + try { + const body = err.error; + if (body && body.fieldErrors && body.fieldErrors.length > 0) { + return body.fieldErrors.map((e: any) => e.message).join('. '); + } + if (body && body.message) { + return body.message; + } + const headerError = err.headers ? err.headers.get('X-UtmStack-error') : null; + if (headerError) { + return headerError; + } + if (typeof body === 'string' && body.length > 0) { + return body; + } + } catch (e) {} + return defaultMsg; + } + + onToggle(key: string, value: boolean) { + this.formValues[key] = value.toString(); + } + + addHeaderRow() { + this.headerRows.push({key: '', value: ''}); + this.syncHeadersToForm(); + } + + removeHeaderRow(index: number) { + this.headerRows.splice(index, 1); + this.syncHeadersToForm(); + } + + syncHeadersToForm() { + const obj: {[k: string]: string} = {}; + for (const row of this.headerRows) { + if (row.key.trim()) { + obj[row.key.trim()] = row.value; + } + } + this.formValues['customHeaders'] = JSON.stringify(obj); + } + + private parseHeadersFromJson(json: string) { + this.headerRows = []; + try { + const obj = JSON.parse(json || '{}'); + for (const key of Object.keys(obj)) { + this.headerRows.push({key, value: obj[key]}); + } + } catch (e) { + // Invalid JSON, start empty + } + } } diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index ee57b55fd..b2020ec51 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -4,7 +4,7 @@ import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {BrowserModule} from '@angular/platform-browser'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {RouterModule} from '@angular/router'; -import {NgbDatepickerConfig, NgbModalConfig} from '@ng-bootstrap/ng-bootstrap'; +import {NgbDatepickerConfig, NgbModalConfig, NgbTooltipConfig} from '@ng-bootstrap/ng-bootstrap'; import {TranslateLoader, TranslateModule} from '@ngx-translate/core'; import {TranslateHttpLoader} from '@ngx-translate/http-loader'; import * as moment from 'moment'; @@ -151,8 +151,9 @@ export function initTimezoneFormat(apiChecker: ApiServiceCheckerService, schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class AppModule { - constructor(private dpConfig: NgbDatepickerConfig, private config: NgbModalConfig) { + constructor(private dpConfig: NgbDatepickerConfig, private config: NgbModalConfig, private tooltipConfig: NgbTooltipConfig) { this.dpConfig.minDate = {year: moment().year() - 100, month: 1, day: 1}; config.backdrop = 'static'; + this.tooltipConfig.container = 'body'; } } diff --git a/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.html b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.html new file mode 100644 index 000000000..c02750549 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.html @@ -0,0 +1,77 @@ +
+
+
+ shield +
+ {{ currentEvaluation.controlName }} +
+
+ + +
+ +
+ + + +
+ +
+
+ + +
+

+ {{ currentEvaluation.controlSolution }} +

+
+ +
+
+ + +
+

+ {{ currentEvaluation.controlRemediation }} +

+
+ + + + {{ currentEvaluation.controlStrategy }} + + + + + +
+ +
+ + +
+ + + + +
+
+
+
+ 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..de9881ccd --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-evaluation-history-view.component.ts @@ -0,0 +1,71 @@ +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-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 new file mode 100644 index 000000000..3a933288b --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-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 #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 new file mode 100644 index 000000000..54f7c21ed --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluation-detail/compliance-query-evaluation-detail.component.html @@ -0,0 +1,71 @@ +
+
+
+
+ Status: + + {{ query.status | complianceStatusLabel }} + +
+ +
+ Evaluation rule: + + {{ ComplianceEvaluationRuleLabels[query.evaluationRule] }} + +
+
+
+
+
+
+ Rule value: + + {{ query.ruleValue }} + +
+ +
+ Result count: + + {{ query.hits }} + +
+
+
+ +
+
+ Query description: +
+
+

{{ query.queryDescription }}

+
+
+ +
+ + Evidence: + +
+ + {{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/compliance-evaluation-history-view/compliance-query-evaluations-view/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 new file mode 100644 index 000000000..6a226940c --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/compliance-query-evaluations-view/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-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 new file mode 100644 index 000000000..aa6aa22b2 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/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-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 new file mode 100644 index 000000000..ef0fff977 --- /dev/null +++ b/frontend/src/app/compliance/compliance-evaluation-history-view/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 #6C757D !important; +} 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-latest-evaluations-view/compliance-latest-evaluations-view.component.css b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css new file mode 100644 index 000000000..4af543688 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.css @@ -0,0 +1,33 @@ + +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 #6C757D !important; +} diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.html b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.html new file mode 100644 index 000000000..aa150eb72 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.html @@ -0,0 +1,134 @@ +
+
+
+
+
+
+
+ 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-latest-evaluations-view/compliance-latest-evaluations-view.component.ts b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.ts new file mode 100644 index 000000000..66062f91e --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/compliance-latest-evaluations-view.component.ts @@ -0,0 +1,156 @@ +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 {ComplianceStatusExtendedEnum} from '../shared/enums/compliance-status.enum'; +import {CpControlConfigService} from '../shared/services/cp-control-config.service'; +import {ComplianceControlLatestEvaluationType} from '../shared/type/compliance-control-latest-evaluation.type'; +import {ComplianceStandardSectionType} from '../shared/type/compliance-standard-section.type'; + +@Component({ + 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 ComplianceLatestEvaluationsViewComponent implements OnInit, OnChanges, OnDestroy { + @Input() section: ComplianceStandardSectionType; + @Output() pageChange = new EventEmitter<{}>(); + + controls$: Observable; + selected: number; + controlDetail: ComplianceControlLatestEvaluationType; + loading = true; + noData = false; + itemsPerPage = 15; + page = 0; + totalItems = 0; + sortEvent: SortEvent = { + column: 'controlName', + direction: 'asc' + }; + destroy$: Subject = new Subject(); + sort = 'controlName,asc'; + 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) => { + 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) => { + 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-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component.css b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component.css new file mode 100644 index 000000000..df3312a15 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component.css @@ -0,0 +1,33 @@ + +@media print { + .report-loading { + display: none; + } + + .compliance { + padding: 15px; + margin: 10px 0; + border: 1px solid #ccc; + background-color: #fff; + box-shadow: none; + } + + .compliance-header { + font-size: 1.1rem; + } + + .compliance-status, .compliance-time { + font-size: 1rem; + margin-bottom: 8px; + } + + .standard-prev { + font-size: 1.4rem; + text-align: center; + font-weight: bold; + } + + .font-weight-bold { + font-weight: bold; + } +} diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component.html b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component.html new file mode 100644 index 000000000..3197e7073 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component.html @@ -0,0 +1,28 @@ +

+ Compliance Assessment +

+ +
+
+
+

{{ control.controlName}}

+
+ +
+

Status:

+ {{ control.lastEvaluationStatus | complianceStatusLabel }} +
+ +
+

Last Evaluation:

+ + {{ control.lastEvaluationTimestamp | date:dateFormat.dateFormat:dateFormat.timezone }} + +
+ +
+

Description:

+ {{ control.controlSolution }} +
+
+
diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component.ts b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component.ts new file mode 100644 index 000000000..8427be714 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component.ts @@ -0,0 +1,57 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit, Output} from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import {EMPTY, Observable} from 'rxjs'; +import {catchError, concatMap, filter, map, tap} from 'rxjs/operators'; +import { UtmToastService } from 'src/app/shared/alert/utm-toast.service'; +import {TimezoneFormatService} from '../../../../shared/services/utm-timezone.service'; +import {DatePipeDefaultOptions} from '../../../../shared/types/date-pipe-default-options'; +import {CpControlConfigService} from '../../../shared/services/cp-control-config.service'; +import {ComplianceControlLatestEvaluationType} from '../../../shared/type/compliance-control-latest-evaluation.type'; + + +@Component({ + selector: 'app-compliance-latest-eval-print-view', + templateUrl: './compliance-latest-eval-print-view.component.html', + styleUrls: ['./compliance-latest-eval-print-view.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ComplianceLatestEvalPrintViewComponent implements OnInit, OnDestroy { + controls$: Observable; + dateFormat$: Observable; + + constructor(private controlsService: CpControlConfigService, + private toastService: UtmToastService, + private route: ActivatedRoute, + private timezoneFormatService: TimezoneFormatService) { } + + ngOnInit() { + this.dateFormat$ = this.timezoneFormatService.getDateFormatSubject(); + this.controls$ = this.route.queryParams + .pipe( + filter((params) => !!params.section), + map((params) => JSON.parse(decodeURIComponent(params.section))), + concatMap((params) => this.controlsService.fetchData({ + page: params.page, + size: params.size, + sectionId: params.id, + sort: params.sort, + })), + map((res) => { + return res.body.map((r, index) => { + return { + ...r, + }; + }); + }), + catchError((err: HttpErrorResponse) => { + this.toastService.showError('Error', + 'Unable to retrieve the list of reports. Please try again or contact support.'); + return EMPTY; + })); + } + + ngOnDestroy(): void { + throw new Error('Method not implemented.'); + } +} diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component.html b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component.html new file mode 100644 index 000000000..a59b70e54 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component.html @@ -0,0 +1,43 @@ +
+

+ Compliance report: {{ control.controlName }} +

+ +
+
+
+ Status: + {{ control.lastEvaluationStatus | complianceStatusLabel }} +
+ +
+ Last Evaluation: + + {{ control.lastEvaluationTimestamp | date:dateFormat.dateFormat:dateFormat.timezone }} + +
+ +
+ Compliance report scope: +

{{ control.section.standard.standardName }}

+

{{ control.section.standard.standardDescription }}

+
+ +
+ Compliance section: +

{{ control.section.standardSectionName }}

+

{{ control.section.standardSectionDescription }}

+
+ +
+ Solution: +

{{ control.controlSolution }}

+
+ +
+ Remediation: +

{{ control.controlRemediation }}

+
+
+
+
diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component.scss b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component.scss new file mode 100644 index 000000000..278123d77 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component.scss @@ -0,0 +1,32 @@ +@media print { + .report-loading { + display: none; + } + + .compliance { + padding: 15px; + margin: 10px 0; + border: 1px solid #ccc; + background-color: #fff; + box-shadow: none; + } + + .compliance-header { + font-size: 1.1rem; + } + + .compliance-status, .compliance-time { + font-size: 1rem; + margin-bottom: 8px; + } + + .standard-prev { + font-size: 1.4rem; + text-align: center; + font-weight: bold; + } + + .font-weight-bold { + font-weight: bold; + } +} diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component.ts b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component.ts new file mode 100644 index 000000000..7bda47569 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component.ts @@ -0,0 +1,55 @@ +import {HttpErrorResponse} from '@angular/common/http'; +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {EMPTY, Observable} from 'rxjs'; +import {catchError} from 'rxjs/operators'; +import {UtmToastService} from '../../../../../shared/alert/utm-toast.service'; +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 {CpControlConfigService} from '../../../../shared/services/cp-control-config.service'; +import {ComplianceControlLatestEvaluationType} from '../../../../shared/type/compliance-control-latest-evaluation.type'; + +@Component({ + selector: 'app-compliance-detail-print-view', + templateUrl: './compliance-latest-eval-detail-print-view.component.html', + styleUrls: ['./compliance-latest-eval-detail-print-view.component.scss'] +}) +export class ComplianceLatestEvalDetailPrintViewComponent implements OnInit { + reportId: number; + control: ComplianceControlLatestEvaluationType; + dateFormat$: Observable; + + protected readonly ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; + + constructor(private activatedRoute: ActivatedRoute, + private cpControlConfigService: CpControlConfigService, + private timezoneFormatService: TimezoneFormatService, + private toastService: UtmToastService) { + } + + ngOnInit() { + this.dateFormat$ = this.timezoneFormatService.getDateFormatSubject(); + this.activatedRoute.params.subscribe(params => { + this.reportId = params.id; + this.getTemplate(); + }); + } + + getTemplate() { + this.cpControlConfigService.find(this.reportId) + .pipe( + catchError((err: HttpErrorResponse) => { + this.toastService.showError( + 'Error', + 'Unable to retrieve the report template. Please try again or contact support.' + ); + return EMPTY; + }) + ) + .subscribe(response => { + this.control = response.body; + }); + } + +} diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.css b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.css new file mode 100644 index 000000000..2dcc588c1 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-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 #6C757D !important; +} + +button { + white-space: nowrap; +} + + diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.html b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.html new file mode 100644 index 000000000..4eeca19aa --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.html @@ -0,0 +1,80 @@ +
+
+
+
+ Status: + + {{ control.lastEvaluationStatus | complianceStatusLabel }} + +
+ +
+ Last Evaluation: + + + {{ control.lastEvaluationTimestamp | date:dateFormat.dateFormat:dateFormat.timezone }} + + + + {{ control.lastEvaluationStatus | complianceStatusLabel }} + + + +
+
+
+
+
+
+ Compliance report scope: +
+ +
+
+

{{ control.section.standard.standardName }}

+
+
+ +
+ +
+ Compliance section: +
+
+

{{ control.section.standardSectionName }}

+
+
+ +
+ +
+ Compliance report: +
+
+ +
+ + +
+ Compliance remediation: +
+
+ +
+
+
+
diff --git a/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.ts b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.ts new file mode 100644 index 000000000..e28591950 --- /dev/null +++ b/frontend/src/app/compliance/compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component.ts @@ -0,0 +1,42 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {NgxSpinnerService} from 'ngx-spinner'; +import {Observable} from 'rxjs'; +import {UtmToastService} from '../../../../shared/alert/utm-toast.service'; +import {ExportPdfService} from '../../../../shared/services/util/export-pdf.service'; +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 {ComplianceControlLatestEvaluationType} from '../../../shared/type/compliance-control-latest-evaluation.type'; + +@Component({ + 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 ComplianceLatestEvaluationViewDetailComponent implements OnInit { + @Input() control: ComplianceControlLatestEvaluationType; + dateFormat$: Observable; + ComplianceStatusExtendedEnum = ComplianceStatusExtendedEnum; + + constructor(private timezoneFormatService: TimezoneFormatService, + private spinner: NgxSpinnerService, + private exportPdfService: ExportPdfService, + private toastService: UtmToastService) { } + + ngOnInit() { + this.dateFormat$ = this.timezoneFormatService.getDateFormatSubject(); + } + + exportToPdf() { + this.spinner.show('buildPrintPDF'); + const url = '/compliance/evaluation-detail-print-view/' + this.control.id; + const fileName = this.control.controlName.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.toastService.showError('Error', 'An error occurred while creating a PDF.')); + }); + } +} 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..a1c69fa10 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'; @@ -29,13 +33,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..c6696a047 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,8 @@
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 8e7aba5de..c9059afba 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 { + 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'; 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(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.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..71af11a89 --- /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 {ComplianceControlType} from '../../../shared/type/compliance-control.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: ComplianceControlType; + @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..4feaaa729 --- /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 { + UtmComplianceControlCreateComponent +} from '../../shared/components/utm-compliance-control-create/utm-compliance-control-create.component'; +import {CpControlConfigService} from '../../shared/services/cp-control-config.service'; +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'; + +@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: ComplianceControlType[] = []; + 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, + 'controlSolution.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: ComplianceControlType) { + const modal = this.modalService.open(UtmCpControlConfigDeleteComponent, {centered: true}); + modal.componentInstance.control = control; + modal.componentInstance.controlDelete.subscribe(() => { + this.getControls(); + }); + } + + editControl(control: ComplianceControlType) { + const controlModal = this.modalService.open(UtmComplianceControlCreateComponent, {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/compliance-report-viewer/compliance-report-viewer.component.html b/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.html index cdc74e88f..aa3a5f744 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 @@ -11,7 +11,7 @@
- + {{ pdfExport ? 'Generating...' : 'Save to PDF' }} @@ -48,13 +48,21 @@
- - + --> + + +
@@ -62,10 +70,12 @@
-
+
- - + + +
diff --git a/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.ts b/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.ts index c7e24357c..6a09e01a0 100644 --- a/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.ts +++ b/frontend/src/app/compliance/compliance-report-viewer/compliance-report-viewer.component.ts @@ -176,7 +176,8 @@ export class ComplianceReportViewerComponent implements OnInit, AfterViewInit, O return '/dashboard/export-compliance/' + this.report.id; } else { const section = this.getActiveSectionParams(); - return encodeURIComponent('/compliance/print-view?section=' + section); + // return encodeURIComponent('/compliance/print-view?section=' + section); + return encodeURIComponent('/compliance/evaluations-print-view=' + section); } } 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/compliance-routing.module.ts b/frontend/src/app/compliance/compliance-routing.module.ts index 879e5c581..626f1e72e 100644 --- a/frontend/src/app/compliance/compliance-routing.module.ts +++ b/frontend/src/app/compliance/compliance-routing.module.ts @@ -3,12 +3,20 @@ import {RouterModule, Routes} from '@angular/router'; 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 { + ComplianceLatestEvalPrintViewComponent +// tslint:disable-next-line:max-line-length +} from './compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component'; +import { + ComplianceLatestEvalDetailPrintViewComponent +// tslint:disable-next-line:max-line-length +} from './compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-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'}, @@ -50,6 +58,16 @@ const routes: Routes = [ component: CompliancePrintViewComponent, data: {authorities: [USER_ROLE, ADMIN_ROLE]} }, + { + path: 'evaluations-print-view', + component: ComplianceLatestEvalPrintViewComponent, + data: {authorities: [USER_ROLE, ADMIN_ROLE]} + }, + { + path: 'evaluation-detail-print-view/:id', + component: ComplianceLatestEvalDetailPrintViewComponent, + data: {authorities: [USER_ROLE, ADMIN_ROLE]} + }, ]; @NgModule({ diff --git a/frontend/src/app/compliance/shared/compliance-shared.module.ts b/frontend/src/app/compliance/shared/compliance-shared.module.ts index b134a5a00..b30130a65 100644 --- a/frontend/src/app/compliance/shared/compliance-shared.module.ts +++ b/frontend/src/app/compliance/shared/compliance-shared.module.ts @@ -3,9 +3,36 @@ 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 {ComplianceEvaluationHistoryViewComponent} from '../compliance-evaluation-history-view/compliance-evaluation-history-view.component'; +import { + 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-evaluation-history-view/compliance-query-evaluations-view/compliance-query-evaluations-view.component'; + +import {ComplianceLatestEvaluationsViewComponent} from '../compliance-latest-evaluations-view/compliance-latest-evaluations-view.component'; +import { + ComplianceLatestEvalPrintViewComponent +// tslint:disable-next-line:max-line-length +} from '../compliance-latest-evaluations-view/components/compliance-latest-eval-print-view/compliance-latest-eval-print-view.component'; +import { + ComplianceLatestEvalDetailPrintViewComponent +// tslint:disable-next-line:max-line-length +} from '../compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-eval-detail-print-view/compliance-latest-eval-detail-print-view.component'; +import { + ComplianceLatestEvaluationViewDetailComponent +// tslint:disable-next-line:max-line-length +} from '../compliance-latest-evaluations-view/components/compliance-latest-evaluation-view-detail/compliance-latest-evaluation-view-detail.component'; import {ComplianceReportsViewComponent} from '../compliance-reports-view/compliance-reports-view.component'; import { CompliancePrintViewComponent @@ -20,6 +47,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 { + UtmComplianceCreateQueryComponent +} from './components/utm-compliance-control-create/query-config/utm-compliance-create-query.component'; +import { + UtmComplianceQueryListComponent +} from './components/utm-compliance-control-create/query-config/utm-compliance-query-list.component'; +import { + 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 @@ -28,6 +64,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'; @@ -35,7 +73,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 {ComplianceStatusLabelPipe} from './pipes/compliance-status-label.pipe'; @NgModule({ declarations: [ @@ -54,8 +92,21 @@ import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/ ComplianceStatusComponent, ComplianceReportsViewComponent, ComplianceReportDetailComponent, + ComplianceQueryEvaluationDetailComponent, ComplianceTimeWindowsComponent, - CompliancePrintViewComponent + CompliancePrintViewComponent, + UtmComplianceControlCreateComponent, + UtmComplianceCreateQueryComponent, + UtmComplianceQueryListComponent, + ComplianceLatestEvaluationsViewComponent, + ComplianceEvaluationHistoryViewComponent, + UtmCpSectionConfigComponent, + ComplianceTimelineComponent, + ComplianceQueryEvaluationsViewComponent, + ComplianceLatestEvaluationViewDetailComponent, + ComplianceStatusLabelPipe, + ComplianceLatestEvalPrintViewComponent, + ComplianceLatestEvalDetailPrintViewComponent ], imports: [ CommonModule, @@ -65,7 +116,10 @@ import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/ ReactiveFormsModule, NgbModule, UtmDashboardSharedModule, - NgxJsonViewerModule + NgxJsonViewerModule, + GraphicBuilderSharedModule, + NgxEchartsModule, + AlertManagementSharedModule ], schemas: [NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA], entryComponents: [ @@ -76,7 +130,8 @@ import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/ UtmCpStandardSectionCreateComponent, UtmComplianceCreateComponent, UtmComplianceScheduleCreateComponent, - UtmComplianceScheduleDeleteComponent + UtmComplianceScheduleDeleteComponent, + UtmComplianceControlCreateComponent ], exports: [ UtmSaveAsComplianceComponent, @@ -92,8 +147,15 @@ import {UtmSaveAsComplianceComponent} from './components/utm-save-as-compliance/ ComplianceStatusComponent, ComplianceReportsViewComponent, ComplianceReportDetailComponent, + ComplianceQueryEvaluationDetailComponent, ComplianceTimeWindowsComponent, - CompliancePrintViewComponent + CompliancePrintViewComponent, + ComplianceLatestEvaluationsViewComponent, + ComplianceEvaluationHistoryViewComponent, + UtmCpSectionConfigComponent, + ComplianceStatusLabelPipe, + ComplianceLatestEvalPrintViewComponent, + ComplianceLatestEvalDetailPrintViewComponent ] }) export class ComplianceSharedModule { diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.css b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.css new file mode 100644 index 000000000..f37095e5c --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.css @@ -0,0 +1,3 @@ +.editor-container { + height: 80px; +} diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.html new file mode 100644 index 000000000..0763e93c2 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-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-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 new file mode 100644 index 000000000..8eac1b47e --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-create-query.component.ts @@ -0,0 +1,121 @@ +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, + ComplianceEvaluationRuleLabels +} from '../../../enums/compliance-evaluation-rule.enum'; +import {ComplianceQueryType} from '../../../type/compliance-query.type'; + +@Component({ + selector: 'app-utm-compliance-create-query', + templateUrl: './utm-compliance-create-query.component.html', + styleUrls: ['./utm-compliance-create-query.component.css'] +}) +export class UtmComplianceCreateQueryComponent implements OnInit { + + @Input() query: ComplianceQueryType = null; + @Input() indexPatterns: UtmIndexPattern[] = []; + @Input() indexPatternNames: string[] = []; + @Output() add = new EventEmitter(); + @Output() cancel = new EventEmitter(); + + form: FormGroup; + evaluationRules = Object.values(ComplianceEvaluationRuleEnum).map(rule => ({ + id: rule, + evaluationRule: ComplianceEvaluationRuleLabels[rule] + })); + + codeEditorOptions: ConsoleOptions = {lineNumbers: 'off'}; + errorMessage = ''; + + constructor(private fb: FormBuilder, + private sqlValidationService: SqlValidationService, + private localFieldService: LocalFieldService) {} + + ngOnInit() { + const q = this.query || {}; + + this.form = this.fb.group({ + id: [q.id || null], + queryName: [q.queryName || '', [Validators.required, Validators.minLength(10), Validators.maxLength(200)]], + queryDescription: [q.queryDescription || '', [Validators.required, Validators.maxLength(2000)]], + sqlQuery: [q.sqlQuery || '', [Validators.required, Validators.maxLength(2000)]], + evaluationRule: [q.evaluationRule || null, [Validators.required]], + ruleValue: [q.ruleValue || '', ], + indexPatternId: [q.indexPatternId || null, [Validators.required]], + controlConfigId: [q.controlConfigId || null] + }); + + this.form.get('evaluationRule').valueChanges.subscribe(rule => { + const ruleValueControl = this.form.get('ruleValue'); + + if (rule !== null && rule !== 'NO_HITS_ALLOWED') { + ruleValueControl.setValidators([ + Validators.required, + Validators.min(1), + Validators.pattern(/^[1-9]\d*$/) + ]); + } else { + ruleValueControl.clearValidators(); + ruleValueControl.setValue(null); + } + + ruleValueControl.updateValueAndValidity(); + }); + } + + submit() { + if (this.form.invalid) { + return; + } + + const sql = this.form.get('sqlQuery').value; + this.errorMessage = this.sqlValidationService.validateSqlQuery(sql); + if (this.errorMessage) { + 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(); + } + + cancelEdit() { + this.cancel.emit(); + } + + loadFieldNames() { + return [ + ...this.localFieldService.getPatternStoredFields(ALERT_INDEX_PATTERN).map(f => f.name), + ...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/compliance/shared/components/utm-compliance-control-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 new file mode 100644 index 000000000..8e2519abd --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.html @@ -0,0 +1,67 @@ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
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) }} + +
+ + + +
+
+ +
+
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-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 new file mode 100644 index 000000000..e5b34a5bc --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/query-config/utm-compliance-query-list.component.ts @@ -0,0 +1,104 @@ +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 {ComplianceQueryType} from '../../../type/compliance-query.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 implements OnInit { + // tslint:disable-next-line:variable-name + private _queries: ComplianceQueryType[] = []; + + @Input() set queries(value: ComplianceQueryType[]) { + this._queries = value || []; + } + + get queries() { + return this._queries; + } + + @Output() add = new EventEmitter<{ + query: ComplianceQueryType; + index: number | null; + }>(); + + @Output() remove = new EventEmitter(); + + patterns: UtmIndexPattern[]; + indexPatternNames = []; + editingIndex: number = null; + + constructor(private indexPatternService: IndexPatternService) { + + } + + ngOnInit() { + this.getIndexPatterns(); + } + + startEdit(index: number) { + this.editingIndex = index; + } + + cancelEdit() { + this.editingIndex = null; + } + + onQueryAdd(query: ComplianceQueryType): void { + this.add.emit({ + query, + index: this.editingIndex + }); + + this.editingIndex = null; + } + + onRemove(index: number) { + this.remove.emit(index); + } + + 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); + } + + 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-create/utm-compliance-control-create.component.html b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.html new file mode 100644 index 000000000..6753343ac --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.html @@ -0,0 +1,123 @@ + +
+
+
+
+ + Report Configuration + +
+ +
+
+ +
+ + Queries Configuration + +
+ +
+
+
+
+
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + +
+ + Report name is required. + + + Report name must be at least 10 characters long. + + + Report name must not exceed 200 characters. + +
+
+
+ + + +
+ + Strategy is required. + +
+
+
+ +
+ + +
+ +
+ + +
+
+
+
+ + +
+
+ + + + +
+
diff --git a/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.scss b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.scss new file mode 100644 index 000000000..38365f459 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-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-create/utm-compliance-control-create.component.ts b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.ts new file mode 100644 index 000000000..0a577fd8f --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-control-create/utm-compliance-control-create.component.ts @@ -0,0 +1,137 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {FormArray, FormBuilder, FormGroup, Validators} from '@angular/forms'; +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 {ComplianceControlType} from '../../type/compliance-control.type'; +import {ComplianceQueryType} from '../../type/compliance-query.type'; + +@Component({ + selector: 'app-utm-compliance-control-create', + templateUrl: './utm-compliance-control-create.component.html', + styleUrls: ['./utm-compliance-control-create.component.scss'] +}) +export class UtmComplianceControlCreateComponent implements OnInit { + @Input() control: ComplianceControlType; + @Output() controlCreated = new EventEmitter(); + + loading = true; + step = 1; + stepCompleted: number[] = []; + creating = false; + viewSection = false; + + complianceForm: FormGroup; + standardSectionId: number; + strategies = []; + + constructor(private cpControlConfigService: CpControlConfigService, + public activeModal: NgbActiveModal, + private cpReportBehavior: CpReportBehavior, + private utmToastService: UtmToastService, + private fb: FormBuilder) { + } + + ngOnInit() { + this.complianceForm = this.fb.group({ + controlName: [this.control ? this.control.controlName : '' , + [Validators.required, Validators.minLength(10), Validators.maxLength(200)]], + 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(this.control ? this.control.queriesConfigs : [], [Validators.minLength(1)]) + }); + + this.strategies = Object.keys(ComplianceStrategyEnum).map( + key => ({ + id: key as ComplianceStrategyEnum, + strategy: ComplianceStrategyEnum[key as keyof typeof ComplianceStrategyEnum] + }) + ); + + if (this.control) { + this.viewSection = true; + this.standardSectionId = this.control.standardSectionId; + } + this.loading = false; + } + + 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; + } + + createCompliance() { + this.creating = true; + const controlConfigCompliance: ComplianceControlType = { + standardSectionId: this.standardSectionId, + 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 + }; + + if (this.control) { + controlConfigCompliance.id = this.control.id; + this.cpControlConfigService.update(controlConfigCompliance).subscribe(() => { + this.utmToastService.showSuccessBottom('Compliance report edited successfully'); + this.activeModal.close(); + this.controlCreated.emit('edited'); + }, error1 => { + this.creating = false; + this.utmToastService.showError('Error', 'Error editing compliance report'); + }); + } else { + this.cpControlConfigService.create(controlConfigCompliance).subscribe(() => { + this.utmToastService.showSuccessBottom('Compliance report created successfully'); + this.activeModal.close(); + this.cpReportBehavior.$reportUpdate.next('update'); + this.controlCreated.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); + } + + onQueryAdd(event: { query: ComplianceQueryType ; index: number | null }) { + const { query, index } = event; + if (index === null) { + this.queriesConfigs.push(this.fb.control(query)); + } else { + this.queriesConfigs.at(index).setValue(query); + } + } + + onQueryRemove(index: number) { + this.queriesConfigs.removeAt(index); + } +} 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..2bc96e847 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.html @@ -0,0 +1,10 @@ +
+
+ Control Status Timeline +
+
+
+
+
+
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..cfcbc1b72 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.scss @@ -0,0 +1,18 @@ +.chart-container { + width: 100%; + height: 250px; + overflow-x: hidden; + overflow-y: hidden; + display: block; + white-space: nowrap; +} + +.chart { + height: 300px; + width: max-content; + min-width: 100%; +} + +.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 new file mode 100644 index 000000000..f4e74c1b6 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-compliance-timeline/compliance-timeline.component.ts @@ -0,0 +1,225 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {ComplianceStatusExtendedEnum, getComplianceStatusLabel} from '../../enums/compliance-status.enum'; +import {ComplianceControlEvaluationHistoryType} from '../../type/compliance-control-evaluation-history.type'; + +@Component({ + selector: 'app-compliance-timeline', + templateUrl: './compliance-timeline.component.html', + styleUrls: ['./compliance-timeline.component.scss'] +}) +export class ComplianceTimelineComponent implements OnInit { + @Input() evaluations: ComplianceControlEvaluationHistoryType[]; + @Output() evaluationSelected = new EventEmitter(); + private originalData: ComplianceControlEvaluationHistoryType[] = []; + + options: any; + complianceValue = [ + '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[]; + private monthDays: string[] = []; + + constructor() { + } + + ngOnInit(): void { + this.options = null; + + if (this.evaluations && this.evaluations.length > 0) { + this.transformResponse(this.evaluations); + if (this.rawData.length > 0) { + this.initChartOptions(); + } + } + } + + private transformResponse(data: ComplianceControlEvaluationHistoryType[]): 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 === 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]); + }); + } + + 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} (${getComplianceStatusLabel(value)})` + : ''; + }, + }, + grid: { + height: '50%', + top: '10%', + left: '10%', + right: '3%', + bottom: '0', + width: this.evaluations.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, + formatter: (value: string) => getComplianceStatusLabel(value)} + }, + 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 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: 4, + }; + 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]); + } + } +} 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..fb255a124 --- /dev/null +++ b/frontend/src/app/compliance/shared/components/utm-cp-section-config/utm-cp-section-config.component.ts @@ -0,0 +1,108 @@ +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 {ComplianceControlType} from '../../type/compliance-control.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: ComplianceControlType, controls: ComplianceControlType[]) { + if (this.section.isActive && control) { + controls.forEach(r => r.selected = false); + control.selected = true; + this.loadReport(control); + } + } + + loadReport(report: ComplianceControlType) { + this.cpControlConfigService.loadReport({ + template: report, + sectionId: this.section.id, + standardId: this.section.standardId + }); + } +} 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, 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..3174b5ad8 --- /dev/null +++ b/frontend/src/app/compliance/shared/enums/compliance-evaluation-rule.enum.ts @@ -0,0 +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' +} + +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..53a435071 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,27 @@ export enum ComplianceStatusEnum { COMPLIANT = 'COMPLIANT', NON_COMPLIANT = 'NON_COMPLIANT' } + +export enum ComplianceStatusExtendedEnum { + COMPLIANT = 'COMPLIANT', + NON_COMPLIANT = 'NON_COMPLIANT', + NOT_EVALUATED = 'NOT_EVALUATED', + NOT_APPLICABLE = 'NOT_APPLICABLE', + ERROR = 'ERROR' +} + +export const ComplianceStatusLabels: Record = { + [ComplianceStatusExtendedEnum.COMPLIANT]: 'Compliant', + [ComplianceStatusExtendedEnum.NON_COMPLIANT]: 'Non Compliant', + [ComplianceStatusExtendedEnum.NOT_APPLICABLE]: 'Not Applicable', + [ComplianceStatusExtendedEnum.NOT_EVALUATED]: 'Not Evaluated', + [ComplianceStatusExtendedEnum.ERROR]: 'Error', +}; + +export function getComplianceStatusLabel( + status: string | ComplianceStatusExtendedEnum +): string { + return ComplianceStatusLabels[status] + || ComplianceStatusLabels[ComplianceStatusExtendedEnum.NOT_EVALUATED]; +} + 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/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 new file mode 100644 index 000000000..a6cdf68fb --- /dev/null +++ b/frontend/src/app/compliance/shared/services/cp-control-config.service.ts @@ -0,0 +1,91 @@ +import {HttpClient, HttpResponse} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +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 {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'; + +export interface ControlParams { + template: ComplianceControlType; + sectionId: number; + standardId: number; +} + +@Injectable({ + providedIn: 'root' +}) +export class CpControlConfigService extends RefreshDataService<{ sectionId: number, + 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(); + } + + create(control: ComplianceControlType): Observable> { + return this.http.post( + this.resourceUrl, + control, + {observe: 'response'}); + } + + query(req?: any): Observable> { + const options = createRequestOption(req); + return this.http.get(this.resourceUrl, { + params: options, + observe: 'response' + }); + } + + + update(control: ComplianceControlType): Observable> { + return this.http.put( + `${this.resourceUrl}/${control.id}`, + control, + { observe: 'response' } + ); + } + + delete(control: number): Observable> { + return this.http.delete( + `${this.resourceUrl}/${control}`, + {observe: 'response'} + ); + } + + controlsBySection(req?: any): Observable> { + const options = createRequestOption(req); + return this.http.get(this.resourceUrl + '/get-by-section', { + params: options, + observe: 'response' + }); + } + + fetchData(request: any): Observable> { + return this.controlsBySection(request); + } + + evaluationsByControl(controlId: number, req?: any): Observable> { + return this.http.get( + `${this.resourceUrl}/${controlId}/evaluations`, + { observe: 'response' } + ); + } + + loadReport(params: ControlParams) { + this.loadControlSubject.next(params); + } + + find(controlId: number): Observable> { + return this.http.get( + `${this.resourceUrl}/get-by-id/${controlId}`, + { observe: 'response' } + ); + } +} diff --git a/frontend/src/app/compliance/shared/type/compliance-control-base.type.ts b/frontend/src/app/compliance/shared/type/compliance-control-base.type.ts new file mode 100644 index 000000000..c4c533a59 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-control-base.type.ts @@ -0,0 +1,14 @@ +import {ComplianceStrategyEnum} from '../enums/compliance-strategy.enum'; +import {ComplianceQueryType} from './compliance-query.type'; +import {ComplianceStandardSectionType} from './compliance-standard-section.type'; + +export class ComplianceControlBaseType { + id?: number; + section?: ComplianceStandardSectionType; + standardSectionId?: number; + controlName?: string; + controlSolution?: string; + controlRemediation?: string; + controlStrategy?: ComplianceStrategyEnum; + 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-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-base.type.ts b/frontend/src/app/compliance/shared/type/compliance-query-base.type.ts new file mode 100644 index 000000000..198ec02c9 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-query-base.type.ts @@ -0,0 +1,9 @@ +import {ComplianceEvaluationRuleEnum} from '../enums/compliance-evaluation-rule.enum'; + +export class ComplianceQueryBaseType { + id?: number; + queryName?: string; + queryDescription?: string; + evaluationRule?: ComplianceEvaluationRuleEnum; + ruleValue?: number; +} diff --git a/frontend/src/app/compliance/shared/type/compliance-query-evaluation.group.ts b/frontend/src/app/compliance/shared/type/compliance-query-evaluation.group.ts new file mode 100644 index 000000000..10cad8d28 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-query-evaluation.group.ts @@ -0,0 +1,8 @@ +import {ComplianceQueryEvaluationType} from './compliance-query-evaluation.type'; + +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 new file mode 100644 index 000000000..1223a0e4c --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-query-evaluation.type.ts @@ -0,0 +1,9 @@ +import {ComplianceStatusExtendedEnum} from '../enums/compliance-status.enum'; +import {ComplianceQueryBaseType} from './compliance-query-base.type'; + +export class ComplianceQueryEvaluationType extends ComplianceQueryBaseType { + indexPatternName?: string; + hits?: number; + status?: ComplianceStatusExtendedEnum; + evidence?: any[]; +} 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..1fe0fc144 --- /dev/null +++ b/frontend/src/app/compliance/shared/type/compliance-query.type.ts @@ -0,0 +1,7 @@ +import {ComplianceQueryBaseType} from './compliance-query-base.type'; + +export class ComplianceQueryType extends ComplianceQueryBaseType { + controlConfigId?: number; + sqlQuery?: string; + indexPatternId?: number; +} diff --git a/frontend/src/app/data-management/alert-management/alert-view/alert-view.component.ts b/frontend/src/app/data-management/alert-management/alert-view/alert-view.component.ts index d0c67d43f..c813140c8 100644 --- a/frontend/src/app/data-management/alert-management/alert-view/alert-view.component.ts +++ b/frontend/src/app/data-management/alert-management/alert-view/alert-view.component.ts @@ -378,8 +378,7 @@ export class AlertViewComponent implements OnInit, OnDestroy { } addToSelected(alert: any) { - console.log(alert); - const index = this.alertSelected.indexOf(alert); + const index = this.alertSelected.findIndex((a)=>a.id ===alert.id); if (index === -1) { this.alertSelected.push(alert); } else { diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-soc-ai/alert-soc-ai.component.html b/frontend/src/app/data-management/alert-management/shared/components/alert-soc-ai/alert-soc-ai.component.html index 18aba5c0a..bdf003915 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-soc-ai/alert-soc-ai.component.html +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-soc-ai/alert-soc-ai.component.html @@ -52,6 +52,19 @@ Info! The SOC-AI integration did not analyze this alert due to inactivity or a processing error.
+
+ +
+ +
diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-soc-ai/alert-soc-ai.component.ts b/frontend/src/app/data-management/alert-management/shared/components/alert-soc-ai/alert-soc-ai.component.ts index b0ff5d3a8..1d6a6ac29 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-soc-ai/alert-soc-ai.component.ts +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-soc-ai/alert-soc-ai.component.ts @@ -1,10 +1,11 @@ import {HttpResponse} from '@angular/common/http'; -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {Component, Input, OnDestroy, OnInit, ChangeDetectorRef} from '@angular/core'; import {UtmToastService} from '../../../../../shared/alert/utm-toast.service'; import {LOG_INDEX_PATTERN, SOC_AI_INDEX_PATTERN} from '../../../../../shared/constants/main-index-pattern.constant'; import {ElasticOperatorsEnum} from '../../../../../shared/enums/elastic-operators.enum'; import {ElasticDataService} from '../../../../../shared/services/elasticsearch/elastic-data.service'; import {ElasticFilterType} from '../../../../../shared/types/filter/elastic-filter.type'; +import {UtmAlertType} from '../../../../../shared/types/alert/utm-alert.type'; import {AlertSocAiService} from '../../services/alert-soc-ai.service'; import {IndexSocAiStatus, SocAiType} from './soc-ai.type'; @@ -15,6 +16,7 @@ import {IndexSocAiStatus, SocAiType} from './soc-ai.type'; }) export class AlertSocAiComponent implements OnInit, OnDestroy { @Input() alertID: string; + @Input() alert: UtmAlertType; @Input() socAiActive: boolean; socAiResponse: SocAiType; indexSocAiStatus = IndexSocAiStatus; @@ -24,16 +26,18 @@ export class AlertSocAiComponent implements OnInit, OnDestroy { constructor(private elasticDataService: ElasticDataService, private alertSocAiService: AlertSocAiService, + private cdt:ChangeDetectorRef, private utmToastService: UtmToastService) {} ngOnInit() { if (this.socAiActive) { - this.getSocAiResponse(); + this.initialLoad() } } - getSocAiResponse() { + initialLoad(){ this.loading = true; + this.cdt.markForCheck() const filter: ElasticFilterType[] = [{ field: 'activityId', operator: ElasticOperatorsEnum.IS, @@ -42,13 +46,40 @@ export class AlertSocAiComponent implements OnInit, OnDestroy { this.elasticDataService.search(1, 1, 1, SOC_AI_INDEX_PATTERN, filter) .subscribe((res: HttpResponse) => { this.loading = false; + this.cdt.markForCheck() if (!res || res.body.length === 0) { this.socAiResponse = res.body; } else { this.socAiResponse = res.body[0]; } + }, + (_res: HttpResponse) => { + this.loading = false; + this.cdt.markForCheck() + } + ); + } - if (this.socAiResponse.status === IndexSocAiStatus.Processing) { + + getSocAiResponse() { + this.loading = true; + this.cdt.markForCheck() + const filter: ElasticFilterType[] = [{ + field: 'activityId', + operator: ElasticOperatorsEnum.IS, + value: this.alertID + }]; + this.elasticDataService.search(1, 1, 1, SOC_AI_INDEX_PATTERN, filter) + .subscribe((res: HttpResponse) => { + if (!res || res.body.length === 0) { + this.socAiResponse = res.body; + } else { + this.socAiResponse = res.body[0]; + this.loading = false; + this.cdt.markForCheck() + } + + if (res.body.length==0 || this.socAiResponse.status === IndexSocAiStatus.Processing) { if (!this.interval) { this.startInterval(); } @@ -58,8 +89,9 @@ export class AlertSocAiComponent implements OnInit, OnDestroy { } } }, - (res: HttpResponse) => { + (_res: HttpResponse) => { this.loading = false; + this.cdt.markForCheck() } ); } @@ -75,15 +107,23 @@ export class AlertSocAiComponent implements OnInit, OnDestroy { } processAlert() { + if (!this.alert) { + this.utmToastService.showError('Error', 'Alert data is not available.'); + return; + } + this.loadingProcess = true; - this.alertSocAiService.processAlertBySoc([this.alertID]) + this.cdt.markForCheck() + this.alertSocAiService.analyzeAlert(this.alert) .subscribe((res) => { + this.utmToastService.showSuccessBottom('Alert submitted for SOC-AI analysis'); setTimeout(() => { this.loadingProcess = false; + this.cdt.markForCheck() this.getSocAiResponse(); }, 3000); }, - (error) => { + (_error) => { this.utmToastService.showError('Error', 'An error occurred while processing the alert. Please try again later.'); this.loadingProcess = false; }); diff --git a/frontend/src/app/data-management/alert-management/shared/components/alert-view-detail/alert-view-detail.component.html b/frontend/src/app/data-management/alert-management/shared/components/alert-view-detail/alert-view-detail.component.html index 8ce80d2f6..6cc55f213 100644 --- a/frontend/src/app/data-management/alert-management/shared/components/alert-view-detail/alert-view-detail.component.html +++ b/frontend/src/app/data-management/alert-management/shared/components/alert-view-detail/alert-view-detail.component.html @@ -198,7 +198,7 @@
- +
diff --git a/frontend/src/app/data-management/alert-management/shared/services/alert-soc-ai.service.ts b/frontend/src/app/data-management/alert-management/shared/services/alert-soc-ai.service.ts index 97128ba9c..2e1c9cac2 100644 --- a/frontend/src/app/data-management/alert-management/shared/services/alert-soc-ai.service.ts +++ b/frontend/src/app/data-management/alert-management/shared/services/alert-soc-ai.service.ts @@ -2,6 +2,7 @@ import {HttpClient, HttpResponse} from '@angular/common/http'; import {Injectable} from '@angular/core'; import {Observable} from 'rxjs'; import {SERVER_API_URL} from '../../../../app.constants'; +import {UtmAlertType} from '../../../../shared/types/alert/utm-alert.type'; @Injectable({ @@ -14,8 +15,12 @@ export class AlertSocAiService { constructor(private http: HttpClient) { } - processAlertBySoc(alertId: string[]): Observable> { - return this.http.post>(this.resourceUrl + '/alerts', alertId, {observe: 'response'}); + /** + * Submit an alert for SOC-AI analysis + * @param alert The complete alert object to analyze + */ + analyzeAlert(alert: UtmAlertType): Observable> { + return this.http.post(this.resourceUrl + '/analyze', alert, {observe: 'response'}); } } diff --git a/frontend/src/app/incident-response/incident-response-routing.module.ts b/frontend/src/app/incident-response/incident-response-routing.module.ts index a0c638cff..1d2d461ec 100644 --- a/frontend/src/app/incident-response/incident-response-routing.module.ts +++ b/frontend/src/app/incident-response/incident-response-routing.module.ts @@ -2,7 +2,6 @@ import {NgModule} from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; import {UserRouteAccessService} from '../core/auth/user-route-access-service'; import {ADMIN_ROLE} from '../shared/constants/global.constant'; -import {IncidentResponseAutomationComponent} from './incident-response-automation/incident-response-automation.component'; import {IncidentResponseViewComponent} from './incident-response-view/incident-response-view.component'; import {PlaybookBuilderComponent} from './playbook-builder/playbook-builder.component'; import {PlaybooksComponent} from './playbooks/playbooks.component'; @@ -16,12 +15,6 @@ const routes: Routes = [ canActivate: [UserRouteAccessService], data: {authorities: [ADMIN_ROLE]} }, - { - path: 'automation', - component: IncidentResponseAutomationComponent, - canActivate: [UserRouteAccessService], - data: {authorities: [ADMIN_ROLE]} - }, { path: 'create-flow', component: PlaybookBuilderComponent, diff --git a/frontend/src/app/incident-response/incident-response-view/incident-response-view.component.html b/frontend/src/app/incident-response/incident-response-view/incident-response-view.component.html index 2190611a1..1be940bfe 100644 --- a/frontend/src/app/incident-response/incident-response-view/incident-response-view.component.html +++ b/frontend/src/app/incident-response/incident-response-view/incident-response-view.component.html @@ -120,7 +120,7 @@
Incident Response Audit< [ngbTooltip]="'Related '+ command.originType + ' id'" placement="top" tooltipClass="utm-tooltip-top" - [routerLink]="'/soar/automation'" + [routerLink]="'/soar/create-flow'" [queryParams]="{id: command.originId}"> {{command.originId}} diff --git a/frontend/src/app/incident-response/playbook-builder/playbook-builder.component.ts b/frontend/src/app/incident-response/playbook-builder/playbook-builder.component.ts index e2af5c73a..497efbb60 100644 --- a/frontend/src/app/incident-response/playbook-builder/playbook-builder.component.ts +++ b/frontend/src/app/incident-response/playbook-builder/playbook-builder.component.ts @@ -69,7 +69,8 @@ export class PlaybookBuilderComponent implements OnInit, OnDestroy { agentType: [false], excludedAgents: [[]], defaultAgent: [''], - agentPlatform: ['', Validators.required] + agentPlatform: ['', Validators.required], + shell: ['cmd'] }); this.viewportHeight = window.innerHeight; } @@ -108,7 +109,7 @@ export class PlaybookBuilderComponent implements OnInit, OnDestroy { this.rulePrefix = getElementPrefix(this.rule.name); - this.formRule.patchValue(ruleData, { emitEvent: false }); + this.formRule.patchValue(ruleData); const name = this.formRule.get('name').value; this.formRule.get('name').setValue(this.replacePrefixInName(name)); diff --git a/frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.html b/frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.html index 234498252..d76795333 100644 --- a/frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.html +++ b/frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.html @@ -56,7 +56,7 @@

Flow Actions

@@ -95,6 +95,17 @@

Flow Actions

+
+
+ + +
+
+
diff --git a/frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.ts b/frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.ts index db769c6b7..40cdc178c 100644 --- a/frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.ts +++ b/frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.ts @@ -2,7 +2,7 @@ import {Component, Input, OnDestroy, OnInit} from '@angular/core'; import {FormGroup} from '@angular/forms'; import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; import {Observable, of, Subject} from 'rxjs'; -import {catchError, finalize, map, takeUntil, tap} from 'rxjs/operators'; +import {catchError, filter, finalize, map, takeUntil, tap} from 'rxjs/operators'; import {UtmNetScanService} from '../../../../assets-discover/shared/services/utm-net-scan.service'; import {NetScanType} from '../../../../assets-discover/shared/types/net-scan.type'; import {UtmToastService} from '../../../../shared/alert/utm-toast.service'; @@ -50,6 +50,16 @@ export class ActionBuilderComponent implements OnInit, OnDestroy { this.group.get('command').setValue(command); }) ); + + this.group.get('agentPlatform').valueChanges + .pipe( + takeUntil(this.destroy$), + filter(val => !!val) + ) + .subscribe(platform => { + this.loadingAgents = true; + this.agents$ = this.fetchAgents(platform); + }); } getPlatforms() { diff --git a/frontend/src/app/incident-response/shared/component/ir-create-rule/ir-create-rule.component.html b/frontend/src/app/incident-response/shared/component/ir-create-rule/ir-create-rule.component.html index aa3bf902b..b0faa55e3 100644 --- a/frontend/src/app/incident-response/shared/component/ir-create-rule/ir-create-rule.component.html +++ b/frontend/src/app/incident-response/shared/component/ir-create-rule/ir-create-rule.component.html @@ -116,6 +116,7 @@ class="w-30" [loadingText]="'Loading alert fields...'" [loading]="!alertFields" + [disabled]="i === 0" bindLabel="label" bindValue="field" formControlName="field" @@ -139,15 +140,16 @@ formControlName="value" id="values"> - +
- - You must set at least one trigger condition + You must select an alert name and complete all trigger conditions