From 7ee4187d502a56c9f6e52f388df71d446ae740db Mon Sep 17 00:00:00 2001 From: Abhisek Datta Date: Wed, 24 Jun 2026 15:43:20 +0530 Subject: [PATCH] refactor: Event log use audit event as SSOT (#350) --- internal/audit/eventlog_sink.go | 35 +---------------------- internal/audit/eventlog_sink_test.go | 42 ++++++++++++++-------------- internal/eventlog/eventlog.go | 23 ++------------- internal/eventlog/eventlog_test.go | 14 +++++----- 4 files changed, 32 insertions(+), 82 deletions(-) diff --git a/internal/audit/eventlog_sink.go b/internal/audit/eventlog_sink.go index 188ab0c..f639086 100644 --- a/internal/audit/eventlog_sink.go +++ b/internal/audit/eventlog_sink.go @@ -20,7 +20,7 @@ func (s *eventlogSink) Handle(_ context.Context, event AuditEvent) error { elEvent := eventlog.Event{ Timestamp: event.Timestamp, - EventType: mapEventType(event.Type), + EventType: string(event.Type), Message: event.Message, PackageName: pkgName(event.PackageVersion), Version: pkgVersion(event.PackageVersion), @@ -48,36 +48,3 @@ func sessionDataToDetails(sd *SessionData) map[string]interface{} { func (s *eventlogSink) Close() error { return nil } - -func mapEventType(t EventType) eventlog.EventType { - switch t { - case EventTypeMalwareBlocked: - return eventlog.EventTypeMalwareBlocked - case EventTypeMalwareConfirmed: - return eventlog.EventTypeMalwareConfirmed - case EventTypeInstallAllowed: - return eventlog.EventTypeInstallAllowed - case EventTypeInstallTrustedAllowed: - return eventlog.EventTypeInstallTrustedAllowed - case EventTypeInstallStarted: - return eventlog.EventTypeInstallStarted - case EventTypeDependencyResolved: - return eventlog.EventTypeDependencyResolved - case EventTypeInstallInsecureBypass: - return eventlog.EventTypeInstallInsecureBypass - case EventTypeProxyHostObserved: - return eventlog.EventTypeProxyHostObserved - case EventTypeDependencyCooldown: - return eventlog.EventTypeDependencyCooldown - case EventTypeCooldownSkipped: - return eventlog.EventTypeCooldownSkipped - case EventTypeSandboxOverride: - return eventlog.EventTypeSandboxOverride - case EventTypeError: - return eventlog.EventTypeError - case EventTypeSessionComplete: - return eventlog.EventType("session_complete") - default: - return eventlog.EventType(string(t)) - } -} diff --git a/internal/audit/eventlog_sink_test.go b/internal/audit/eventlog_sink_test.go index 4c58a57..f7a73ed 100644 --- a/internal/audit/eventlog_sink_test.go +++ b/internal/audit/eventlog_sink_test.go @@ -3,36 +3,36 @@ package audit import ( "testing" - "github.com/safedep/pmg/internal/eventlog" "github.com/stretchr/testify/assert" ) -func TestEventlogSinkTranslatesAllEventTypes(t *testing.T) { +// TestEventTypeOnDiskValues pins the event_type strings written to the on-disk +// event log. The audit package is the single owner of this vocabulary; the +// eventlog sink writes string(event.Type) verbatim, so these values are the +// file-format contract and must not change without a migration. +func TestEventTypeOnDiskValues(t *testing.T) { tests := []struct { - name string input EventType - expected eventlog.EventType + expected string }{ - {"malware_blocked", EventTypeMalwareBlocked, eventlog.EventTypeMalwareBlocked}, - {"malware_confirmed", EventTypeMalwareConfirmed, eventlog.EventTypeMalwareConfirmed}, - {"install_allowed", EventTypeInstallAllowed, eventlog.EventTypeInstallAllowed}, - {"install_trusted_allowed", EventTypeInstallTrustedAllowed, eventlog.EventTypeInstallTrustedAllowed}, - {"install_started", EventTypeInstallStarted, eventlog.EventTypeInstallStarted}, - {"dependency_resolved", EventTypeDependencyResolved, eventlog.EventTypeDependencyResolved}, - {"install_insecure_bypass", EventTypeInstallInsecureBypass, eventlog.EventTypeInstallInsecureBypass}, - {"proxy_host_observed", EventTypeProxyHostObserved, eventlog.EventTypeProxyHostObserved}, - {"dependency_cooldown", EventTypeDependencyCooldown, eventlog.EventTypeDependencyCooldown}, - {"dependency_cooldown_skipped", EventTypeCooldownSkipped, eventlog.EventTypeCooldownSkipped}, - {"sandbox_override", EventTypeSandboxOverride, eventlog.EventTypeSandboxOverride}, - {"error", EventTypeError, eventlog.EventTypeError}, - {"session_complete", EventTypeSessionComplete, eventlog.EventType("session_complete")}, - {"unknown_type", EventType("custom_event"), eventlog.EventType("custom_event")}, + {EventTypeMalwareBlocked, "malware_blocked"}, + {EventTypeMalwareConfirmed, "malware_confirmed"}, + {EventTypeInstallAllowed, "install_allowed"}, + {EventTypeInstallTrustedAllowed, "install_trusted_allowed"}, + {EventTypeInstallStarted, "install_started"}, + {EventTypeDependencyResolved, "dependency_resolved"}, + {EventTypeInstallInsecureBypass, "install_insecure_bypass"}, + {EventTypeProxyHostObserved, "proxy_host_observed"}, + {EventTypeDependencyCooldown, "dependency_cooldown"}, + {EventTypeCooldownSkipped, "dependency_cooldown_skipped"}, + {EventTypeSandboxOverride, "sandbox_override"}, + {EventTypeError, "error"}, + {EventTypeSessionComplete, "session_complete"}, } for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := mapEventType(tt.input) - assert.Equal(t, tt.expected, result) + t.Run(tt.expected, func(t *testing.T) { + assert.Equal(t, tt.expected, string(tt.input)) }) } } diff --git a/internal/eventlog/eventlog.go b/internal/eventlog/eventlog.go index f980fda..88b2dbe 100644 --- a/internal/eventlog/eventlog.go +++ b/internal/eventlog/eventlog.go @@ -13,28 +13,11 @@ import ( "github.com/safedep/pmg/config" ) -// EventType represents the type of event being logged -type EventType string - -const ( - EventTypeMalwareBlocked EventType = "malware_blocked" - EventTypeMalwareConfirmed EventType = "malware_confirmed" - EventTypeInstallAllowed EventType = "install_allowed" - EventTypeInstallTrustedAllowed EventType = "install_trusted_allowed" - EventTypeInstallStarted EventType = "install_started" - EventTypeDependencyResolved EventType = "dependency_resolved" - EventTypeInstallInsecureBypass EventType = "install_insecure_bypass" - EventTypeProxyHostObserved EventType = "proxy_host_observed" - EventTypeDependencyCooldown EventType = "dependency_cooldown" - EventTypeCooldownSkipped EventType = "dependency_cooldown_skipped" - EventTypeSandboxOverride EventType = "sandbox_override" - EventTypeError EventType = "error" -) - -// Event represents a security event +// Event is the on-disk DTO for a logged security event. The event vocabulary is +// owned by the audit package; here event_type is just a JSON string column. type Event struct { Timestamp time.Time `json:"timestamp"` - EventType EventType `json:"event_type"` + EventType string `json:"event_type"` Message string `json:"message"` PackageName string `json:"package_name,omitempty"` Version string `json:"version,omitempty"` diff --git a/internal/eventlog/eventlog_test.go b/internal/eventlog/eventlog_test.go index 1176238..7cf785a 100644 --- a/internal/eventlog/eventlog_test.go +++ b/internal/eventlog/eventlog_test.go @@ -57,7 +57,7 @@ func TestLogEvent(t *testing.T) { // Log an event event := Event{ - EventType: EventTypeMalwareBlocked, + EventType: "malware_blocked", Message: "Test malware blocked", PackageName: "evil-package", Version: "1.0.0", @@ -81,7 +81,7 @@ func TestLogEvent(t *testing.T) { assert.NoError(t, err, "Failed to parse logged event") // Verify the event - assert.Equal(t, EventTypeMalwareBlocked, loggedEvent.EventType) + assert.Equal(t, "malware_blocked", loggedEvent.EventType) assert.Equal(t, "evil-package", loggedEvent.PackageName) } @@ -97,7 +97,7 @@ func TestLogEventMalwareBlocked(t *testing.T) { }() err = LogEvent(Event{ - EventType: EventTypeMalwareBlocked, + EventType: "malware_blocked", Message: "Blocked installation of malicious package: malicious-pkg@2.0.0", PackageName: "malicious-pkg", Version: "2.0.0", @@ -114,7 +114,7 @@ func TestLogEventMalwareBlocked(t *testing.T) { err = json.Unmarshal(data, &event) assert.NoError(t, err, "Failed to parse event") - assert.Equal(t, EventTypeMalwareBlocked, event.EventType) + assert.Equal(t, "malware_blocked", event.EventType) assert.Equal(t, "malicious-pkg", event.PackageName) assert.Equal(t, "pypi", event.Ecosystem) } @@ -131,7 +131,7 @@ func TestLogEventProxyHostObserved(t *testing.T) { }() err = LogEvent(Event{ - EventType: EventTypeProxyHostObserved, + EventType: "proxy_host_observed", Message: "Proxy observed outbound host: example.com", Details: map[string]interface{}{ "hostname": "example.com", @@ -150,7 +150,7 @@ func TestLogEventProxyHostObserved(t *testing.T) { err = json.Unmarshal(data, &event) assert.NoError(t, err, "Failed to parse event") - assert.Equal(t, EventTypeProxyHostObserved, event.EventType) + assert.Equal(t, "proxy_host_observed", event.EventType) assert.Equal(t, "example.com", event.Details["hostname"]) assert.Equal(t, "CONNECT", event.Details["method"]) assert.Equal(t, "connect_tunnel_no_interceptor", event.Details["reason"]) @@ -179,7 +179,7 @@ func TestInitializeWithFile(t *testing.T) { // Log an event event := Event{ - EventType: EventTypeMalwareBlocked, + EventType: "malware_blocked", Message: "Test custom file logging", PackageName: "test-package", Version: "1.0.0",