feat(go): persist Python-compatible incidents
This commit is contained in:
parent
f85c2e831a
commit
538d1d954a
13 changed files with 555 additions and 46 deletions
|
|
@ -61,6 +61,9 @@ type Config struct {
|
|||
HeartbeatMaxAge int
|
||||
MaxSnapshots int
|
||||
MaxSnapshotAgeDays int
|
||||
IncidentTracking bool
|
||||
IncidentWindow int
|
||||
IncidentLineageDepth int
|
||||
Detectors map[string]bool
|
||||
InputSnooperAllowComms map[string]bool
|
||||
CredentialAccessAllowComms map[string]bool
|
||||
|
|
@ -97,6 +100,9 @@ func Default() Config {
|
|||
HeartbeatMaxAge: 120,
|
||||
MaxSnapshots: 300,
|
||||
MaxSnapshotAgeDays: 60,
|
||||
IncidentTracking: true,
|
||||
IncidentWindow: 1800,
|
||||
IncidentLineageDepth: 8,
|
||||
Detectors: detectors,
|
||||
InputSnooperAllowComms: stringSet(defaultInputSnooperAllowComms),
|
||||
CredentialAccessAllowComms: stringSet(defaultCredentialAccessAllowComms),
|
||||
|
|
@ -204,6 +210,24 @@ func Load(path string) (Config, error) {
|
|||
return Config{}, fmt.Errorf("max_snapshot_age_days must be non-negative: %q", value)
|
||||
}
|
||||
cfg.MaxSnapshotAgeDays = days
|
||||
case "incident_tracking":
|
||||
enabled, err := boolean(value)
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("incident_tracking: %w", err)
|
||||
}
|
||||
cfg.IncidentTracking = enabled
|
||||
case "incident_window":
|
||||
window, err := nonNegativeInt(value)
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("incident_window: %w", err)
|
||||
}
|
||||
cfg.IncidentWindow = window
|
||||
case "incident_lineage_depth":
|
||||
depth, err := nonNegativeInt(value)
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("incident_lineage_depth: %w", err)
|
||||
}
|
||||
cfg.IncidentLineageDepth = depth
|
||||
case "detectors":
|
||||
names, err := stringArray(value)
|
||||
if err != nil {
|
||||
|
|
@ -351,6 +375,14 @@ func nonNegativeSeconds(value string) (time.Duration, error) {
|
|||
return time.Duration(seconds * float64(time.Second)), nil
|
||||
}
|
||||
|
||||
func nonNegativeInt(value string) (int, error) {
|
||||
parsed, err := strconv.Atoi(value)
|
||||
if err != nil || parsed < 0 {
|
||||
return 0, fmt.Errorf("must be non-negative: %q", value)
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func boolean(value string) (bool, error) {
|
||||
switch value {
|
||||
case "true":
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ func TestDefaultsMatchPython(t *testing.T) {
|
|||
cfg.BaselineGrace != 10*time.Second ||
|
||||
cfg.SUIDRefresh != time.Hour || cfg.SUIDScanInterval != time.Minute ||
|
||||
cfg.HeartbeatMaxAge != 120 || cfg.MaxSnapshots != 300 ||
|
||||
cfg.MaxSnapshotAgeDays != 60 || !cfg.FirstSeenEnabled {
|
||||
cfg.MaxSnapshotAgeDays != 60 || !cfg.IncidentTracking ||
|
||||
cfg.IncidentWindow != 1800 || cfg.IncidentLineageDepth != 8 ||
|
||||
!cfg.FirstSeenEnabled {
|
||||
t.Fatalf("unexpected defaults: %+v", cfg)
|
||||
}
|
||||
if !cfg.Enabled("deleted_exe") {
|
||||
|
|
@ -34,6 +36,9 @@ suid_scan_interval = 15
|
|||
heartbeat_max_age = 45
|
||||
max_snapshots = 25
|
||||
max_snapshot_age_days = 7
|
||||
incident_tracking = false
|
||||
incident_window = 90
|
||||
incident_lineage_depth = 3
|
||||
detectors = [
|
||||
"deleted_exe",
|
||||
"egress",
|
||||
|
|
@ -67,7 +72,8 @@ unknown_future_key = true
|
|||
if cfg.SampleInterval != 1500*time.Millisecond || cfg.Cooldown != 30*time.Second ||
|
||||
cfg.BaselineGrace != 2500*time.Millisecond ||
|
||||
cfg.SUIDRefresh != 2*time.Minute || cfg.SUIDScanInterval != 15*time.Second ||
|
||||
cfg.HeartbeatMaxAge != 45 || cfg.MaxSnapshots != 25 || cfg.MaxSnapshotAgeDays != 7 {
|
||||
cfg.HeartbeatMaxAge != 45 || cfg.MaxSnapshots != 25 || cfg.MaxSnapshotAgeDays != 7 ||
|
||||
cfg.IncidentTracking || cfg.IncidentWindow != 90 || cfg.IncidentLineageDepth != 3 {
|
||||
t.Fatalf("unexpected parsed config: %+v", cfg)
|
||||
}
|
||||
if !cfg.Enabled("deleted_exe") || !cfg.Enabled("egress") || cfg.Enabled("reverse_shell") {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue