diff --git a/server/modules/elastalert/elastalert.go b/server/modules/elastalert/elastalert.go index 0c492feb..51f4d998 100644 --- a/server/modules/elastalert/elastalert.go +++ b/server/modules/elastalert/elastalert.go @@ -66,6 +66,7 @@ const ( DEFAULT_AI_REPO_BRANCH = "generated-summaries-published" DEFAULT_AI_REPO_PATH = "/opt/sensoroni/ai_summary_repos" DEFAULT_SHOW_AI_SUMMARIES = true + DEFAULT_AUTO_UPDATE_ENABLED = false ) var ( // treat as constant @@ -120,6 +121,7 @@ type ElastAlertEngine struct { aiRepoBranch string aiRepoPath string customAlerters *map[string]interface{} + autoUpdateEnabled bool detections.SyncSchedulerParams detections.IntegrityCheckerData detections.IOManager @@ -191,6 +193,7 @@ func (e *ElastAlertEngine) Init(config module.ModuleConfig) (err error) { e.highSeverityAlerterParams = module.GetStringDefault(config, "additionalSev4AlertersParams", "") e.criticalSeverityAlerters = module.GetStringArrayDefault(config, "additionalSev5Alerters", []string{}) e.criticalSeverityAlerterParams = module.GetStringDefault(config, "additionalSev5AlertersParams", "") + e.autoUpdateEnabled = module.GetBoolDefault(config, "autoUpdateEnabled", DEFAULT_AUTO_UPDATE_ENABLED) if custom, ok := config["additionalUserDefinedNotifications"]; ok { switch ct := custom.(type) { @@ -527,6 +530,15 @@ func (e *ElastAlertEngine) Sync(logger *log.Entry, forceSync bool) error { e.writeNoRead = nil + if !e.autoUpdateEnabled && !forceSync { + logger.WithFields(log.Fields{ + "autoUpdateEnabled": e.autoUpdateEnabled, + "forceSync": forceSync, + }).Info("skipping sync") + + return nil + } + if e.showAiSummaries { err := detections.RefreshAiSummaries(e, model.SigLangSigma, &e.isRunning, e.aiRepoPath, e.aiRepoUrl, e.aiRepoBranch, logger, e.IOManager) if err != nil { diff --git a/server/modules/elastalert/elastalert_test.go b/server/modules/elastalert/elastalert_test.go index ff31567d..a6f9d9f7 100644 --- a/server/modules/elastalert/elastalert_test.go +++ b/server/modules/elastalert/elastalert_test.go @@ -21,6 +21,7 @@ import ( "testing" "time" + "github.com/security-onion-solutions/securityonion-soc/config" "github.com/security-onion-solutions/securityonion-soc/licensing" "github.com/security-onion-solutions/securityonion-soc/model" "github.com/security-onion-solutions/securityonion-soc/module" @@ -1501,8 +1502,9 @@ func TestSyncIncrementalNoChanges(t *testing.T) { IntegrityCheckerData: detections.IntegrityCheckerData{ IsRunning: true, }, - IOManager: iom, - showAiSummaries: false, + IOManager: iom, + showAiSummaries: false, + autoUpdateEnabled: true, } logger := log.WithField("detectionEngine", "test-elastalert") @@ -1549,6 +1551,37 @@ func TestSyncIncrementalNoChanges(t *testing.T) { assert.False(t, eng.EngineState.SyncFailure) } +func TestSyncDisabled(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + detStore := servermock.NewMockDetectionstore(ctrl) + iom := mock.NewMockIOManager(ctrl) + + eng := &ElastAlertEngine{ + srv: &server.Server{ + Detectionstore: detStore, + Config: &config.ServerConfig{}, + }, + isRunning: true, + IOManager: iom, + showAiSummaries: true, + autoUpdateEnabled: false, + } + + logger := log.WithField("detectionEngine", "test-elastalert") + + err := eng.Sync(logger, false) + assert.NoError(t, err) + + assert.False(t, eng.EngineState.Syncing) + assert.False(t, eng.EngineState.IntegrityFailure) + assert.False(t, eng.EngineState.Migrating) + assert.False(t, eng.EngineState.MigrationFailure) + assert.False(t, eng.EngineState.Importing) + assert.False(t, eng.EngineState.SyncFailure) +} + func TestSyncChanges(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/server/modules/strelka/strelka.go b/server/modules/strelka/strelka.go index 5f02274d..26b54f90 100644 --- a/server/modules/strelka/strelka.go +++ b/server/modules/strelka/strelka.go @@ -54,6 +54,7 @@ const ( DEFAULT_AI_REPO_BRANCH = "generated-summaries-published" DEFAULT_AI_REPO_PATH = "/opt/sensoroni/ai_summary_repos" DEFAULT_SHOW_AI_SUMMARIES = true + DEFAULT_AUTO_UPDATE_ENABLED = false ) var titleUpdater = regexp.MustCompile(`(?im)rule\s+(\w+)(\s+:(\s*[^{]+))?(\s+)(//.*$)?(\n?){`) @@ -76,6 +77,7 @@ type StrelkaEngine struct { aiRepoUrl string aiRepoBranch string aiRepoPath string + autoUpdateEnabled bool detections.SyncSchedulerParams detections.IntegrityCheckerData detections.IOManager @@ -123,6 +125,7 @@ func (e *StrelkaEngine) Init(config module.ModuleConfig) (err error) { e.CommunityRulesImportErrorSeconds = module.GetIntDefault(config, "communityRulesImportErrorSeconds", DEFAULT_COMMUNITY_RULES_IMPORT_ERROR_SECS) e.failAfterConsecutiveErrorCount = module.GetIntDefault(config, "failAfterConsecutiveErrorCount", DEFAULT_FAIL_AFTER_CONSECUTIVE_ERROR_COUNT) e.IntegrityCheckerData.FrequencySeconds = module.GetIntDefault(config, "integrityCheckFrequencySeconds", DEFAULT_INTEGRITY_CHECK_FREQUENCY_SECONDS) + e.autoUpdateEnabled = module.GetBoolDefault(config, "autoUpdateEnabled", DEFAULT_AUTO_UPDATE_ENABLED) e.rulesRepos, err = model.GetReposDefault(config, "rulesRepos", []*model.RuleRepo{ { @@ -307,6 +310,15 @@ func (e *StrelkaEngine) Sync(logger *log.Entry, forceSync bool) error { e.writeNoRead = nil + if !e.autoUpdateEnabled && !forceSync { + logger.WithFields(log.Fields{ + "autoUpdateEnabled": e.autoUpdateEnabled, + "forceSync": forceSync, + }).Info("skipping sync") + + return nil + } + if e.showAiSummaries { err := detections.RefreshAiSummaries(e, model.SigLangYara, &e.isRunning, e.aiRepoPath, e.aiRepoUrl, e.aiRepoBranch, logger, e.IOManager) if err != nil { diff --git a/server/modules/strelka/strelka_test.go b/server/modules/strelka/strelka_test.go index 67412c39..f8276608 100644 --- a/server/modules/strelka/strelka_test.go +++ b/server/modules/strelka/strelka_test.go @@ -18,6 +18,7 @@ import ( "testing" "time" + "github.com/security-onion-solutions/securityonion-soc/config" "github.com/security-onion-solutions/securityonion-soc/model" "github.com/security-onion-solutions/securityonion-soc/module" "github.com/security-onion-solutions/securityonion-soc/server" @@ -1016,8 +1017,9 @@ func TestSyncIncrementalNoChanges(t *testing.T) { IntegrityCheckerData: detections.IntegrityCheckerData{ IsRunning: true, }, - IOManager: iom, - showAiSummaries: false, + IOManager: iom, + showAiSummaries: false, + autoUpdateEnabled: true, } logger := log.WithField("detectionEngine", "test-strelka") @@ -1050,6 +1052,37 @@ func TestSyncIncrementalNoChanges(t *testing.T) { assert.False(t, eng.EngineState.SyncFailure) } +func TestSyncDisabled(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + detStore := servermock.NewMockDetectionstore(ctrl) + iom := mock.NewMockIOManager(ctrl) + + eng := &StrelkaEngine{ + srv: &server.Server{ + Detectionstore: detStore, + Config: &config.ServerConfig{}, + }, + isRunning: true, + IOManager: iom, + showAiSummaries: true, + autoUpdateEnabled: false, + } + + logger := log.WithField("detectionEngine", "test-strelka") + + err := eng.Sync(logger, false) + assert.NoError(t, err) + + assert.False(t, eng.EngineState.Syncing) + assert.False(t, eng.EngineState.IntegrityFailure) + assert.False(t, eng.EngineState.Migrating) + assert.False(t, eng.EngineState.MigrationFailure) + assert.False(t, eng.EngineState.Importing) + assert.False(t, eng.EngineState.SyncFailure) +} + func TestSyncChanges(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() diff --git a/server/modules/suricata/suricata.go b/server/modules/suricata/suricata.go index 7ca4f650..bb994446 100644 --- a/server/modules/suricata/suricata.go +++ b/server/modules/suricata/suricata.go @@ -60,6 +60,7 @@ const ( DEFAULT_AI_REPO_BRANCH = "generated-summaries-published" DEFAULT_AI_REPO_PATH = "/opt/sensoroni/ai_summary_repos" DEFAULT_SHOW_AI_SUMMARIES = true + DEFAULT_AUTO_UPDATE_ENABLED = false CUSTOM_RULE_LOC = "/nsm/rules/detect-suricata/custom_temp" ) @@ -89,6 +90,7 @@ type SuricataEngine struct { aiRepoUrl string aiRepoBranch string aiRepoPath string + autoUpdateEnabled bool detections.SyncSchedulerParams detections.IntegrityCheckerData detections.IOManager @@ -132,6 +134,7 @@ func (e *SuricataEngine) Init(config module.ModuleConfig) (err error) { e.CommunityRulesImportErrorSeconds = module.GetIntDefault(config, "communityRulesImportErrorSeconds", DEFAULT_COMMUNITY_RULES_IMPORT_ERROR_SECS) e.failAfterConsecutiveErrorCount = module.GetIntDefault(config, "failAfterConsecutiveErrorCount", DEFAULT_FAIL_AFTER_CONSECUTIVE_ERROR_COUNT) e.IntegrityCheckerData.FrequencySeconds = module.GetIntDefault(config, "integrityCheckFrequencySeconds", DEFAULT_INTEGRITY_CHECK_FREQUENCY_SECONDS) + e.autoUpdateEnabled = module.GetBoolDefault(config, "autoUpdateEnabled", DEFAULT_AUTO_UPDATE_ENABLED) enable := module.GetStringArrayDefault(config, "enableRegex", DEFAULT_ENABLE_REGEX) disable := module.GetStringArrayDefault(config, "disableRegex", DEFAULT_DISABLE_REGEX) @@ -367,6 +370,15 @@ func (e *SuricataEngine) Sync(logger *log.Entry, forceSync bool) error { e.writeNoRead = nil + if !e.autoUpdateEnabled && !forceSync { + logger.WithFields(log.Fields{ + "autoUpdateEnabled": e.autoUpdateEnabled, + "forceSync": forceSync, + }).Info("skipping sync") + + return nil + } + if e.showAiSummaries { err := detections.RefreshAiSummaries(e, model.SigLangSuricata, &e.isRunning, e.aiRepoPath, e.aiRepoUrl, e.aiRepoBranch, logger, e.IOManager) if err != nil { diff --git a/server/modules/suricata/suricata_test.go b/server/modules/suricata/suricata_test.go index 96f3fb9e..5cbad7ef 100644 --- a/server/modules/suricata/suricata_test.go +++ b/server/modules/suricata/suricata_test.go @@ -17,6 +17,7 @@ import ( "testing" "time" + "github.com/security-onion-solutions/securityonion-soc/config" "github.com/security-onion-solutions/securityonion-soc/model" "github.com/security-onion-solutions/securityonion-soc/module" "github.com/security-onion-solutions/securityonion-soc/server" @@ -2197,8 +2198,9 @@ func TestSyncIncrementalNoChanges(t *testing.T) { IntegrityCheckerData: detections.IntegrityCheckerData{ IsRunning: true, }, - IOManager: iom, - showAiSummaries: false, + IOManager: iom, + showAiSummaries: false, + autoUpdateEnabled: true, } logger := log.WithField("detectionEngine", "test-suricata") @@ -2227,6 +2229,37 @@ func TestSyncIncrementalNoChanges(t *testing.T) { assert.True(t, migrationChecked) } +func TestSyncDisabled(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + detStore := servermock.NewMockDetectionstore(ctrl) + iom := mock.NewMockIOManager(ctrl) + + eng := &SuricataEngine{ + srv: &server.Server{ + Detectionstore: detStore, + Config: &config.ServerConfig{}, + }, + isRunning: true, + IOManager: iom, + showAiSummaries: true, + autoUpdateEnabled: false, + } + + logger := log.WithField("detectionEngine", "test-suricata") + + err := eng.Sync(logger, false) + assert.NoError(t, err) + + assert.False(t, eng.EngineState.Syncing) + assert.False(t, eng.EngineState.IntegrityFailure) + assert.False(t, eng.EngineState.Migrating) + assert.False(t, eng.EngineState.MigrationFailure) + assert.False(t, eng.EngineState.Importing) + assert.False(t, eng.EngineState.SyncFailure) +} + func TestSyncChanges(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish()