Remove pre-1.0 audit and protected request scaffolding
This commit is contained in:
@@ -33,10 +33,8 @@ type StoreSnapshot struct {
|
||||
ClientManagerBuildJobs []domain.ClientManagerBuildJob `json:"clientManagerBuildJobs"`
|
||||
RunUpdateJobs []domain.RunUpdateJob `json:"runUpdateJobs"`
|
||||
LogStreams []domain.LogStream `json:"logStreams"`
|
||||
AuditEvents []domain.AuditEvent `json:"auditEvents"`
|
||||
MetricSamples []domain.MetricSample `json:"metricSamples"`
|
||||
Backups []domain.BackupRecord `json:"backups"`
|
||||
Alerts []domain.AlertRecord `json:"alerts"`
|
||||
PluginLifecycles []domain.PluginLifecycleInstallation `json:"pluginLifecycles"`
|
||||
AIConfigDiffs []domain.AIConfigDiffPreview `json:"aiConfigDiffs"`
|
||||
GameClientBridgeCommands []domain.GameClientBridgeCommand `json:"gameClientBridgeCommands"`
|
||||
@@ -153,10 +151,6 @@ func (store *FileStore) LogStreams() LogStreamRepository {
|
||||
return &persistentRepository[domain.LogStream, domain.LogStreamFilter]{repository: store.MemoryStore.logStreams, persist: store.persist}
|
||||
}
|
||||
|
||||
func (store *FileStore) AuditEvents() AuditEventRepository {
|
||||
return &persistentRepository[domain.AuditEvent, domain.AuditEventFilter]{repository: store.MemoryStore.auditEvents, persist: store.persist}
|
||||
}
|
||||
|
||||
func (store *FileStore) MetricSamples() MetricSampleRepository {
|
||||
return &persistentRepository[domain.MetricSample, domain.MetricSampleFilter]{repository: store.MemoryStore.metricSamples, persist: store.persist}
|
||||
}
|
||||
@@ -165,10 +159,6 @@ func (store *FileStore) Backups() BackupRepository {
|
||||
return &persistentRepository[domain.BackupRecord, domain.BackupFilter]{repository: store.MemoryStore.backups, persist: store.persist}
|
||||
}
|
||||
|
||||
func (store *FileStore) Alerts() AlertRepository {
|
||||
return &persistentRepository[domain.AlertRecord, domain.AlertFilter]{repository: store.MemoryStore.alerts, persist: store.persist}
|
||||
}
|
||||
|
||||
func (store *FileStore) PluginLifecycles() PluginLifecycleRepository {
|
||||
return &persistentRepository[domain.PluginLifecycleInstallation, domain.PluginLifecycleFilter]{repository: store.MemoryStore.pluginLifecycle, persist: store.persist}
|
||||
}
|
||||
@@ -257,10 +247,8 @@ func (store *FileStore) snapshot() StoreSnapshot {
|
||||
ClientManagerBuildJobs: snapshotRepository(store.MemoryStore.buildJobs),
|
||||
RunUpdateJobs: snapshotRepository(store.MemoryStore.updateJobs),
|
||||
LogStreams: snapshotRepository(store.MemoryStore.logStreams),
|
||||
AuditEvents: snapshotRepository(store.MemoryStore.auditEvents),
|
||||
MetricSamples: snapshotRepository(store.MemoryStore.metricSamples),
|
||||
Backups: snapshotRepository(store.MemoryStore.backups),
|
||||
Alerts: snapshotRepository(store.MemoryStore.alerts),
|
||||
PluginLifecycles: snapshotRepository(store.MemoryStore.pluginLifecycle),
|
||||
AIConfigDiffs: snapshotRepository(store.MemoryStore.aiConfigDiffs),
|
||||
GameClientBridgeCommands: snapshotRepository(store.MemoryStore.bridgeCommands.memoryRepository),
|
||||
@@ -291,10 +279,8 @@ func (store *FileStore) loadSnapshot(snapshot StoreSnapshot) {
|
||||
loadRepository(store.MemoryStore.buildJobs, snapshot.ClientManagerBuildJobs)
|
||||
loadRepository(store.MemoryStore.updateJobs, snapshot.RunUpdateJobs)
|
||||
loadRepository(store.MemoryStore.logStreams, snapshot.LogStreams)
|
||||
loadRepository(store.MemoryStore.auditEvents, snapshot.AuditEvents)
|
||||
loadRepository(store.MemoryStore.metricSamples, snapshot.MetricSamples)
|
||||
loadRepository(store.MemoryStore.backups, snapshot.Backups)
|
||||
loadRepository(store.MemoryStore.alerts, snapshot.Alerts)
|
||||
loadRepository(store.MemoryStore.pluginLifecycle, snapshot.PluginLifecycles)
|
||||
loadRepository(store.MemoryStore.aiConfigDiffs, snapshot.AIConfigDiffs)
|
||||
loadRepository(store.MemoryStore.bridgeCommands.memoryRepository, snapshot.GameClientBridgeCommands)
|
||||
|
||||
@@ -12,19 +12,19 @@ import (
|
||||
func TestGameClientBridgeCommandRepositoryIdempotencyAndRetention(t *testing.T) {
|
||||
store := NewMemoryStore()
|
||||
now := time.Now().UTC()
|
||||
command := domain.GameClientBridgeCommand{ID: "command-1", ServerInstanceID: "server-1", PluginID: "game.scum", ProfileKey: "scum-client", CommandType: "announcement.send", IdempotencyKey: "same-key", RequesterID: "user-1", State: domain.GameClientBridgeCommandSucceeded, Payload: map[string]any{"nested": map[string]any{"value": "original"}}, ExpiresAt: now.Add(-time.Minute), CompletedAt: now.Add(-time.Minute)}
|
||||
command := domain.GameClientBridgeCommand{ID: "command-1", ServerInstanceID: "server-1", PluginID: "game.scum", ProfileKey: "scum-client", CommandType: "diagnostic.ping", IdempotencyKey: "same-key", RequesterID: "user-1", State: domain.GameClientBridgeCommandSucceeded, Payload: map[string]any{"nested": map[string]any{"value": "original"}}, ExpiresAt: now.Add(-time.Minute), CompletedAt: now.Add(-time.Minute)}
|
||||
if err := store.GameClientBridgeCommands().Create(command); err != nil {
|
||||
t.Fatalf("create command: %v", err)
|
||||
}
|
||||
command.Payload["nested"].(map[string]any)["value"] = "mutated"
|
||||
loaded, err := store.GameClientBridgeCommands().GetByIdempotency("server-1", "user-1", "announcement.send", "same-key")
|
||||
loaded, err := store.GameClientBridgeCommands().GetByIdempotency("server-1", "user-1", "diagnostic.ping", "same-key")
|
||||
if err != nil {
|
||||
t.Fatalf("get by idempotency: %v", err)
|
||||
}
|
||||
if loaded.Payload["nested"].(map[string]any)["value"] != "original" {
|
||||
t.Fatal("repository did not isolate nested payload")
|
||||
}
|
||||
for _, lookup := range [][4]string{{"server-2", "user-1", "announcement.send", "same-key"}, {"server-1", "user-2", "announcement.send", "same-key"}, {"server-1", "user-1", "diagnostic.safe", "same-key"}} {
|
||||
for _, lookup := range [][4]string{{"server-2", "user-1", "diagnostic.ping", "same-key"}, {"server-1", "user-2", "diagnostic.ping", "same-key"}, {"server-1", "user-1", "diagnostic.safe", "same-key"}} {
|
||||
if _, err := store.GameClientBridgeCommands().GetByIdempotency(lookup[0], lookup[1], lookup[2], lookup[3]); !errors.Is(err, ErrNotFound) {
|
||||
t.Fatalf("idempotency scope leaked for %v: %v", lookup, err)
|
||||
}
|
||||
|
||||
@@ -133,10 +133,6 @@ func (store *MySQLStore) LogStreams() LogStreamRepository {
|
||||
return &persistentRepository[domain.LogStream, domain.LogStreamFilter]{repository: store.MemoryStore.logStreams, persist: store.persist}
|
||||
}
|
||||
|
||||
func (store *MySQLStore) AuditEvents() AuditEventRepository {
|
||||
return &persistentRepository[domain.AuditEvent, domain.AuditEventFilter]{repository: store.MemoryStore.auditEvents, persist: store.persist}
|
||||
}
|
||||
|
||||
func (store *MySQLStore) MetricSamples() MetricSampleRepository {
|
||||
return &persistentRepository[domain.MetricSample, domain.MetricSampleFilter]{repository: store.MemoryStore.metricSamples, persist: store.persist}
|
||||
}
|
||||
@@ -145,10 +141,6 @@ func (store *MySQLStore) Backups() BackupRepository {
|
||||
return &persistentRepository[domain.BackupRecord, domain.BackupFilter]{repository: store.MemoryStore.backups, persist: store.persist}
|
||||
}
|
||||
|
||||
func (store *MySQLStore) Alerts() AlertRepository {
|
||||
return &persistentRepository[domain.AlertRecord, domain.AlertFilter]{repository: store.MemoryStore.alerts, persist: store.persist}
|
||||
}
|
||||
|
||||
func (store *MySQLStore) PluginLifecycles() PluginLifecycleRepository {
|
||||
return &persistentRepository[domain.PluginLifecycleInstallation, domain.PluginLifecycleFilter]{repository: store.MemoryStore.pluginLifecycle, persist: store.persist}
|
||||
}
|
||||
@@ -254,10 +246,8 @@ func (store *MySQLStore) snapshot() StoreSnapshot {
|
||||
ClientManagerBuildJobs: snapshotRepository(store.MemoryStore.buildJobs),
|
||||
RunUpdateJobs: snapshotRepository(store.MemoryStore.updateJobs),
|
||||
LogStreams: snapshotRepository(store.MemoryStore.logStreams),
|
||||
AuditEvents: snapshotRepository(store.MemoryStore.auditEvents),
|
||||
MetricSamples: snapshotRepository(store.MemoryStore.metricSamples),
|
||||
Backups: snapshotRepository(store.MemoryStore.backups),
|
||||
Alerts: snapshotRepository(store.MemoryStore.alerts),
|
||||
PluginLifecycles: snapshotRepository(store.MemoryStore.pluginLifecycle),
|
||||
AIConfigDiffs: snapshotRepository(store.MemoryStore.aiConfigDiffs),
|
||||
GameClientBridgeCommands: snapshotRepository(store.MemoryStore.bridgeCommands.memoryRepository),
|
||||
@@ -288,10 +278,8 @@ func (store *MySQLStore) loadSnapshot(snapshot StoreSnapshot) {
|
||||
loadRepository(store.MemoryStore.buildJobs, snapshot.ClientManagerBuildJobs)
|
||||
loadRepository(store.MemoryStore.updateJobs, snapshot.RunUpdateJobs)
|
||||
loadRepository(store.MemoryStore.logStreams, snapshot.LogStreams)
|
||||
loadRepository(store.MemoryStore.auditEvents, snapshot.AuditEvents)
|
||||
loadRepository(store.MemoryStore.metricSamples, snapshot.MetricSamples)
|
||||
loadRepository(store.MemoryStore.backups, snapshot.Backups)
|
||||
loadRepository(store.MemoryStore.alerts, snapshot.Alerts)
|
||||
loadRepository(store.MemoryStore.pluginLifecycle, snapshot.PluginLifecycles)
|
||||
loadRepository(store.MemoryStore.aiConfigDiffs, snapshot.AIConfigDiffs)
|
||||
loadRepository(store.MemoryStore.bridgeCommands.memoryRepository, snapshot.GameClientBridgeCommands)
|
||||
|
||||
@@ -155,13 +155,6 @@ type LogStreamRepository interface {
|
||||
Update(domain.LogStream) error
|
||||
}
|
||||
|
||||
type AuditEventRepository interface {
|
||||
Create(domain.AuditEvent) error
|
||||
Get(id string) (domain.AuditEvent, error)
|
||||
List(domain.AuditEventFilter) ([]domain.AuditEvent, error)
|
||||
Update(domain.AuditEvent) error
|
||||
}
|
||||
|
||||
type MetricSampleRepository interface {
|
||||
Create(domain.MetricSample) error
|
||||
Get(id string) (domain.MetricSample, error)
|
||||
@@ -178,13 +171,6 @@ type BackupRepository interface {
|
||||
Delete(id string) error
|
||||
}
|
||||
|
||||
type AlertRepository interface {
|
||||
Create(domain.AlertRecord) error
|
||||
Get(id string) (domain.AlertRecord, error)
|
||||
List(domain.AlertFilter) ([]domain.AlertRecord, error)
|
||||
Update(domain.AlertRecord) error
|
||||
}
|
||||
|
||||
type PluginLifecycleRepository interface {
|
||||
Create(domain.PluginLifecycleInstallation) error
|
||||
Get(id string) (domain.PluginLifecycleInstallation, error)
|
||||
@@ -254,10 +240,8 @@ type Store interface {
|
||||
ClientManagerBuildJobs() ClientManagerBuildJobRepository
|
||||
RunUpdateJobs() RunUpdateJobRepository
|
||||
LogStreams() LogStreamRepository
|
||||
AuditEvents() AuditEventRepository
|
||||
MetricSamples() MetricSampleRepository
|
||||
Backups() BackupRepository
|
||||
Alerts() AlertRepository
|
||||
PluginLifecycles() PluginLifecycleRepository
|
||||
AIConfigDiffs() AIConfigDiffRepository
|
||||
GameClientBridgeCommands() GameClientBridgeCommandRepository
|
||||
@@ -287,10 +271,8 @@ type MemoryStore struct {
|
||||
buildJobs *memoryRepository[domain.ClientManagerBuildJob, domain.ClientManagerBuildJobFilter]
|
||||
updateJobs *memoryRepository[domain.RunUpdateJob, domain.RunUpdateJobFilter]
|
||||
logStreams *memoryRepository[domain.LogStream, domain.LogStreamFilter]
|
||||
auditEvents *memoryRepository[domain.AuditEvent, domain.AuditEventFilter]
|
||||
metricSamples *memoryRepository[domain.MetricSample, domain.MetricSampleFilter]
|
||||
backups *memoryRepository[domain.BackupRecord, domain.BackupFilter]
|
||||
alerts *memoryRepository[domain.AlertRecord, domain.AlertFilter]
|
||||
pluginLifecycle *memoryRepository[domain.PluginLifecycleInstallation, domain.PluginLifecycleFilter]
|
||||
aiConfigDiffs *memoryRepository[domain.AIConfigDiffPreview, domain.AIConfigDiffFilter]
|
||||
bridgeCommands *memoryGameClientBridgeCommandRepository
|
||||
@@ -397,11 +379,6 @@ func NewMemoryStore() *MemoryStore {
|
||||
domain.CopyLogStream,
|
||||
matchLogStream,
|
||||
),
|
||||
auditEvents: newMemoryRepository(
|
||||
func(event domain.AuditEvent) string { return event.ID },
|
||||
domain.CopyAuditEvent,
|
||||
matchAuditEvent,
|
||||
),
|
||||
metricSamples: newMemoryRepository(
|
||||
func(sample domain.MetricSample) string { return sample.ID },
|
||||
domain.CopyMetricSample,
|
||||
@@ -412,11 +389,6 @@ func NewMemoryStore() *MemoryStore {
|
||||
domain.CopyBackupRecord,
|
||||
matchBackup,
|
||||
),
|
||||
alerts: newMemoryRepository(
|
||||
func(alert domain.AlertRecord) string { return alert.ID },
|
||||
domain.CopyAlertRecord,
|
||||
matchAlert,
|
||||
),
|
||||
pluginLifecycle: newMemoryRepository(
|
||||
func(installation domain.PluginLifecycleInstallation) string { return installation.ID },
|
||||
domain.CopyPluginLifecycleInstallation,
|
||||
@@ -470,10 +442,8 @@ func (store *MemoryStore) ClientManagerBuildJobs() ClientManagerBuildJobReposito
|
||||
}
|
||||
func (store *MemoryStore) RunUpdateJobs() RunUpdateJobRepository { return store.updateJobs }
|
||||
func (store *MemoryStore) LogStreams() LogStreamRepository { return store.logStreams }
|
||||
func (store *MemoryStore) AuditEvents() AuditEventRepository { return store.auditEvents }
|
||||
func (store *MemoryStore) MetricSamples() MetricSampleRepository { return store.metricSamples }
|
||||
func (store *MemoryStore) Backups() BackupRepository { return store.backups }
|
||||
func (store *MemoryStore) Alerts() AlertRepository { return store.alerts }
|
||||
func (store *MemoryStore) PluginLifecycles() PluginLifecycleRepository {
|
||||
return store.pluginLifecycle
|
||||
}
|
||||
@@ -737,13 +707,6 @@ func matchLogStream(stream domain.LogStream, filter domain.LogStreamFilter) bool
|
||||
(filter.StreamKey == "" || stream.StreamKey == filter.StreamKey)
|
||||
}
|
||||
|
||||
func matchAuditEvent(event domain.AuditEvent, filter domain.AuditEventFilter) bool {
|
||||
return (filter.ActorID == "" || event.ActorID == filter.ActorID) &&
|
||||
(filter.ResourceKind == "" || event.ResourceKind == filter.ResourceKind) &&
|
||||
(filter.ResourceID == "" || event.ResourceID == filter.ResourceID) &&
|
||||
(filter.Result == "" || event.Result == filter.Result)
|
||||
}
|
||||
|
||||
func matchMetricSample(sample domain.MetricSample, filter domain.MetricSampleFilter) bool {
|
||||
return (filter.ServerInstanceID == "" || sample.ServerInstanceID == filter.ServerInstanceID) &&
|
||||
(filter.After.IsZero() || sample.CollectedAt.After(filter.After)) &&
|
||||
@@ -755,13 +718,6 @@ func matchBackup(record domain.BackupRecord, filter domain.BackupFilter) bool {
|
||||
(filter.State == "" || record.State == filter.State)
|
||||
}
|
||||
|
||||
func matchAlert(alert domain.AlertRecord, filter domain.AlertFilter) bool {
|
||||
return (filter.State == "" || alert.State == filter.State) &&
|
||||
(filter.SourceKind == "" || alert.SourceKind == filter.SourceKind) &&
|
||||
(filter.SourceID == "" || alert.SourceID == filter.SourceID) &&
|
||||
(filter.Severity == "" || alert.Severity == filter.Severity)
|
||||
}
|
||||
|
||||
func matchPluginLifecycle(installation domain.PluginLifecycleInstallation, filter domain.PluginLifecycleFilter) bool {
|
||||
return (filter.PluginID == "" || installation.PluginID == filter.PluginID) &&
|
||||
(filter.ServerInstanceID == "" || installation.ServerInstanceID == filter.ServerInstanceID) &&
|
||||
|
||||
@@ -145,7 +145,7 @@ func TestFileStorePersistsAndReloadsResources(t *testing.T) {
|
||||
},
|
||||
ServerDeploymentPlan: &domain.ServerDeploymentPlan{SchemaVersion: "1", Operation: "install", PluginID: "game.runtime", Prerequisites: []domain.RuntimeServerPrerequisite{{Key: "steamcmd", Kind: "tool"}}},
|
||||
},
|
||||
ExecutionResult: domain.JobExecutionResult{Kind: "file.read", Version: 2, Checksum: "sha256:" + strings.Repeat("2", 64), SizeBytes: 15, AuditSummary: "bounded read", Content: "private-read"},
|
||||
ExecutionResult: domain.JobExecutionResult{Kind: "file.read", Version: 2, Checksum: "sha256:" + strings.Repeat("2", 64), SizeBytes: 15, Summary: "bounded read", Content: "private-read"},
|
||||
}
|
||||
if err := store.Jobs().Create(job); err != nil {
|
||||
t.Fatalf("create job: %v", err)
|
||||
@@ -277,7 +277,7 @@ func TestMySQLSnapshotRoundTripsDurableJobSchedulingMetadata(t *testing.T) {
|
||||
PluginID: "game.runtime",
|
||||
},
|
||||
},
|
||||
ExecutionResult: domain.JobExecutionResult{Kind: "file.write", Version: 2, Checksum: "sha256:" + strings.Repeat("4", 64), SizeBytes: 14, AuditSummary: "atomic write"},
|
||||
ExecutionResult: domain.JobExecutionResult{Kind: "file.write", Version: 2, Checksum: "sha256:" + strings.Repeat("4", 64), SizeBytes: 14, Summary: "atomic write"},
|
||||
}
|
||||
if err := source.MemoryStore.Jobs().Create(job); err != nil {
|
||||
t.Fatalf("create source job: %v", err)
|
||||
@@ -313,20 +313,13 @@ func TestFileStorePersistsProductionOperationsStateAcrossRestart(t *testing.T) {
|
||||
t.Fatalf("create file store: %v", err)
|
||||
}
|
||||
stamp := time.Date(2026, 7, 18, 14, 0, 0, 0, time.UTC)
|
||||
alert := domain.AlertRecord{
|
||||
ID: "alert-capacity", SourceKind: "run-endpoint", SourceID: "run-1", RuleKey: "capacity.pressure",
|
||||
Severity: domain.AlertSeverityWarning, State: domain.AlertStateAcknowledged, Title: "Capacity pressure",
|
||||
Message: "endpoint capacity is temporarily under pressure", OccurrenceCount: 2, Retryable: true,
|
||||
RetryAfterSeconds: 30, LastAuditEventID: "audit-1", LastSeenAt: stamp, AcknowledgedBy: "operator-1",
|
||||
AcknowledgedAt: stamp, CreatedAt: stamp.Add(-time.Minute), UpdatedAt: stamp,
|
||||
}
|
||||
installation := domain.PluginLifecycleInstallation{
|
||||
ID: "plugin-lifecycle-1", PluginID: "game.scum", ServerInstanceID: "server-1",
|
||||
CurrentVersion: "1.0.0", TargetVersion: "2.0.0", PreviousVersion: "0.9.0",
|
||||
DesiredState: domain.PluginLifecycleStateEnabled, CurrentState: domain.PluginLifecycleStateUpgrading,
|
||||
LastOperation: domain.PluginLifecycleOperationUpgrade, Compatibility: "compatible",
|
||||
DependencyState: domain.DependencyStatePresent, JobID: "job-upgrade", AlertID: alert.ID,
|
||||
AuditEventID: "audit-2", IdempotencyKey: "upgrade-once", CreatedAt: stamp.Add(-time.Hour), UpdatedAt: stamp,
|
||||
DependencyState: domain.DependencyStatePresent, JobID: "job-upgrade",
|
||||
IdempotencyKey: "upgrade-once", CreatedAt: stamp.Add(-time.Hour), UpdatedAt: stamp,
|
||||
}
|
||||
diff := domain.AIConfigDiffPreview{
|
||||
ID: "ai-config-diff-1", RequestID: "ai-request-1", CreatedBy: "operator-1",
|
||||
@@ -335,9 +328,6 @@ func TestFileStorePersistsProductionOperationsStateAcrossRestart(t *testing.T) {
|
||||
ProposedConfig: "MaxPlayers=80\n", DiffSummary: "review required before config write dispatch",
|
||||
State: domain.AIConfigDiffStatePending, ExpiresAt: stamp.Add(30 * time.Minute), CreatedAt: stamp, UpdatedAt: stamp,
|
||||
}
|
||||
if err := store.Alerts().Create(alert); err != nil {
|
||||
t.Fatalf("create alert: %v", err)
|
||||
}
|
||||
if err := store.PluginLifecycles().Create(installation); err != nil {
|
||||
t.Fatalf("create plugin lifecycle: %v", err)
|
||||
}
|
||||
@@ -349,10 +339,6 @@ func TestFileStorePersistsProductionOperationsStateAcrossRestart(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("restart file store: %v", err)
|
||||
}
|
||||
gotAlert, alertErr := restarted.Alerts().Get(alert.ID)
|
||||
if alertErr != nil || gotAlert.State != alert.State || gotAlert.OccurrenceCount != 2 || gotAlert.LastAuditEventID != alert.LastAuditEventID {
|
||||
t.Fatalf("unexpected durable alert: alert=%+v err=%v", gotAlert, alertErr)
|
||||
}
|
||||
gotInstallation, lifecycleErr := restarted.PluginLifecycles().Get(installation.ID)
|
||||
if lifecycleErr != nil || gotInstallation.CurrentState != installation.CurrentState || gotInstallation.TargetVersion != installation.TargetVersion || gotInstallation.JobID != installation.JobID {
|
||||
t.Fatalf("unexpected durable plugin lifecycle: installation=%+v err=%v", gotInstallation, lifecycleErr)
|
||||
|
||||
Reference in New Issue
Block a user