Remove pre-1.0 audit and protected request scaffolding

This commit is contained in:
npc0-hue
2026-08-20 23:42:02 +08:00
parent 40b35b05c7
commit a7e2e4c6c0
130 changed files with 526 additions and 3767 deletions
-14
View File
@@ -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)
+3 -3
View File
@@ -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)
}
-12
View File
@@ -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)
-44
View File
@@ -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) &&
+4 -18
View File
@@ -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)