Revert SCUM real data management change
This commit is contained in:
@@ -148,7 +148,6 @@ type RunAutonomousLifecyclePlan struct {
|
||||
InstallPlans []RunAutonomousInstallPlan `json:"installPlans,omitempty"`
|
||||
LogSources []RunAutonomousLogSource `json:"logSources,omitempty"`
|
||||
DLLExtensions []RunAutonomousDLLExtension `json:"dllExtensions,omitempty"`
|
||||
DataTargets []RunAutonomousDataTarget `json:"dataTargets,omitempty"`
|
||||
RuntimeBindings map[string]string `json:"runtimeBindings,omitempty"`
|
||||
Deployment *RunAutonomousDeployment `json:"deployment,omitempty"`
|
||||
}
|
||||
@@ -209,18 +208,6 @@ type RunAutonomousDLLExtension struct {
|
||||
RCONPort int `json:"rconPort,omitempty"`
|
||||
}
|
||||
|
||||
type RunAutonomousDataTarget struct {
|
||||
Key string `json:"key"`
|
||||
Kind string `json:"kind"`
|
||||
TransportKey string `json:"transportKey"`
|
||||
SourceRootKey string `json:"sourceRootKey"`
|
||||
SourcePath string `json:"sourcePath"`
|
||||
WorkspaceKey string `json:"workspaceKey"`
|
||||
RefreshPolicy string `json:"refreshPolicy"`
|
||||
MaxBytes int64 `json:"maxBytes,omitempty"`
|
||||
Platforms []string `json:"platforms,omitempty"`
|
||||
}
|
||||
|
||||
type RunAutonomousDeployment struct {
|
||||
SchemaVersion string `json:"schemaVersion"`
|
||||
Mode ServerDeploymentMode `json:"mode"`
|
||||
@@ -435,10 +422,6 @@ func CopyRunJobAssignment(assignment RunJobAssignment) RunJobAssignment {
|
||||
assignment.ExecutionInput.LogSources = CopyRuntimeLogSources(assignment.ExecutionInput.LogSources)
|
||||
assignment.ExecutionInput.DLLExtensions = append([]RuntimeDLLExtensionPlan(nil), assignment.ExecutionInput.DLLExtensions...)
|
||||
assignment.ExecutionInput.SourceRCON = CopyRuntimeSourceRCONPlan(assignment.ExecutionInput.SourceRCON)
|
||||
assignment.ExecutionInput.SQLiteSchemaProbe = CopySCUMSchemaProbeRequestPtr(assignment.ExecutionInput.SQLiteSchemaProbe)
|
||||
assignment.ExecutionInput.SQLiteTemplate = CopySCUMSQLiteTemplateRequestPtr(assignment.ExecutionInput.SQLiteTemplate)
|
||||
assignment.ExecutionInput.RCONTemplate = CopySCUMTypedRCONTemplateRequestPtr(assignment.ExecutionInput.RCONTemplate)
|
||||
assignment.ExecutionInput.GuardedMutation = CopySCUMGuardedMutationRequestPtr(assignment.ExecutionInput.GuardedMutation)
|
||||
return assignment
|
||||
}
|
||||
|
||||
@@ -513,10 +496,6 @@ func CopyRunAutonomousLifecyclePlanPtr(plan *RunAutonomousLifecyclePlan) *RunAut
|
||||
}
|
||||
copy.LogSources = append([]RunAutonomousLogSource(nil), plan.LogSources...)
|
||||
copy.DLLExtensions = append([]RunAutonomousDLLExtension(nil), plan.DLLExtensions...)
|
||||
copy.DataTargets = append([]RunAutonomousDataTarget(nil), plan.DataTargets...)
|
||||
for i := range copy.DataTargets {
|
||||
copy.DataTargets[i].Platforms = CopyStringSlice(plan.DataTargets[i].Platforms)
|
||||
}
|
||||
copy.RuntimeBindings = CopyStringMap(plan.RuntimeBindings)
|
||||
if plan.Deployment != nil {
|
||||
deployment := *plan.Deployment
|
||||
|
||||
@@ -87,17 +87,15 @@ type RemoteAdapterDeclaration struct {
|
||||
}
|
||||
|
||||
type RemoteAdapterRequest struct {
|
||||
ServerInstanceID string
|
||||
DeclarationKey string
|
||||
TargetKey string
|
||||
Capability string
|
||||
TimeoutSeconds int
|
||||
MaxAttempts int
|
||||
IdempotencyKey string
|
||||
InputRef string
|
||||
Inputs map[string]string
|
||||
PlatformScheduled bool
|
||||
SQLiteSchemaProbe *SCUMSchemaProbeRequest
|
||||
ServerInstanceID string
|
||||
DeclarationKey string
|
||||
TargetKey string
|
||||
Capability string
|
||||
TimeoutSeconds int
|
||||
MaxAttempts int
|
||||
IdempotencyKey string
|
||||
InputRef string
|
||||
Inputs map[string]string
|
||||
}
|
||||
|
||||
type RemoteAdapterResult struct {
|
||||
@@ -213,7 +211,6 @@ func CopyRemoteAdapterDeclarations(declarations []RemoteAdapterDeclaration) []Re
|
||||
|
||||
func CopyRemoteAdapterRequest(request RemoteAdapterRequest) RemoteAdapterRequest {
|
||||
request.Inputs = CopyStringMap(request.Inputs)
|
||||
request.SQLiteSchemaProbe = CopySCUMSchemaProbeRequestPtr(request.SQLiteSchemaProbe)
|
||||
return request
|
||||
}
|
||||
func CopyRemoteAdapterResult(result RemoteAdapterResult) RemoteAdapterResult { return result }
|
||||
|
||||
@@ -479,18 +479,6 @@ type RuntimeTransportProfile struct {
|
||||
Capabilities []string
|
||||
}
|
||||
|
||||
type RuntimeDataTarget struct {
|
||||
Key string
|
||||
Kind string
|
||||
TransportKey string
|
||||
SourceRootKey string
|
||||
SourcePath string
|
||||
WorkspaceKey string
|
||||
RefreshPolicy string
|
||||
MaxBytes int64
|
||||
Platforms []string
|
||||
}
|
||||
|
||||
type RuntimeClientManagerProfile struct {
|
||||
Key string
|
||||
DisplayName string
|
||||
@@ -621,7 +609,6 @@ type GamePluginRuntimeProfiles struct {
|
||||
LogSources []RuntimeLogSource
|
||||
LogEvents []RuntimeLogEvent
|
||||
TransportProfiles []RuntimeTransportProfile
|
||||
DataTargets []RuntimeDataTarget
|
||||
ClientManagers []RuntimeClientManagerProfile
|
||||
DLLExtensions []RuntimeDLLExtensionProfile
|
||||
}
|
||||
@@ -646,7 +633,6 @@ type GamePluginManifest struct {
|
||||
RemoteAccess GamePluginRemoteAccess
|
||||
RuntimeProfiles GamePluginRuntimeProfiles
|
||||
GameClientBridge GameClientBridgeManifest
|
||||
SCUMLiveData SCUMLiveDataManifest
|
||||
MapTrajectories *GameMapTrajectoryDeclaration
|
||||
}
|
||||
|
||||
@@ -687,7 +673,6 @@ type GamePlugin struct {
|
||||
RemoteAccess GamePluginRemoteAccess
|
||||
RuntimeProfiles GamePluginRuntimeProfiles
|
||||
GameClientBridge GameClientBridgeManifest
|
||||
SCUMLiveData SCUMLiveDataManifest
|
||||
MapTrajectories *GameMapTrajectoryDeclaration
|
||||
ValidationViolations []string
|
||||
Status GamePluginStatus
|
||||
@@ -1093,7 +1078,6 @@ const (
|
||||
JobCapabilityRemoteRunProcessStart = "remote.run.process.start"
|
||||
JobCapabilityRemoteRunProcessStop = "remote.run.process.stop"
|
||||
JobCapabilityRemoteRunDBMySQLQuery = "remote.run.db.mysql.query"
|
||||
JobCapabilityRemoteRunDBSQLiteProbe = "remote.run.db.sqlite.probe"
|
||||
JobCapabilityRemoteRunDBSQLiteQuery = "remote.run.db.sqlite.query"
|
||||
JobCapabilityRemoteRunLogsTransfer = "remote.run.logs.transfer"
|
||||
JobCapabilityRemoteRunRCONCommand = "remote.run.rcon.command"
|
||||
@@ -1156,10 +1140,6 @@ type JobExecutionInput struct {
|
||||
SourceRCON *RuntimeSourceRCONPlan
|
||||
Deployment *ServerDeploymentDefinition
|
||||
ServerDeploymentPlan *ServerDeploymentPlan
|
||||
SQLiteSchemaProbe *SCUMSchemaProbeRequest
|
||||
SQLiteTemplate *SCUMSQLiteTemplateRequest
|
||||
RCONTemplate *SCUMTypedRCONTemplateRequest
|
||||
GuardedMutation *SCUMGuardedMutationRequest
|
||||
}
|
||||
|
||||
type ServerDeploymentPlan struct {
|
||||
@@ -1202,11 +1182,6 @@ type JobExecutionResult struct {
|
||||
SizeBytes int64
|
||||
AuditSummary string
|
||||
Content string
|
||||
SQLiteSchemaProbe *SCUMSchemaProbeResult
|
||||
SQLiteTemplate *SCUMSQLiteTemplateResult
|
||||
RCONTemplate *SCUMTypedRCONTemplateResult
|
||||
GuardedMutation *SCUMGuardedMutationResult
|
||||
ParsedLogBatch *SCUMParsedLogBatchResult
|
||||
ServerDeploymentEvidence *ServerDeploymentEvidence
|
||||
DeploymentReceipt *ServerDeploymentExecutionReceipt
|
||||
}
|
||||
@@ -1719,7 +1694,6 @@ func CopyGamePlugin(plugin GamePlugin) GamePlugin {
|
||||
plugin.RemoteAccess = CopyGamePluginRemoteAccess(plugin.RemoteAccess)
|
||||
plugin.RuntimeProfiles = CopyGamePluginRuntimeProfiles(plugin.RuntimeProfiles)
|
||||
plugin.GameClientBridge = CopyGameClientBridgeManifest(plugin.GameClientBridge)
|
||||
plugin.SCUMLiveData = CopySCUMLiveDataManifest(plugin.SCUMLiveData)
|
||||
if plugin.MapTrajectories != nil {
|
||||
value := CopyGameMapTrajectoryDeclaration(*plugin.MapTrajectories)
|
||||
plugin.MapTrajectories = &value
|
||||
@@ -1790,7 +1764,6 @@ func CopyGamePluginManifest(manifest GamePluginManifest) GamePluginManifest {
|
||||
manifest.RemoteAccess = CopyGamePluginRemoteAccess(manifest.RemoteAccess)
|
||||
manifest.RuntimeProfiles = CopyGamePluginRuntimeProfiles(manifest.RuntimeProfiles)
|
||||
manifest.GameClientBridge = CopyGameClientBridgeManifest(manifest.GameClientBridge)
|
||||
manifest.SCUMLiveData = CopySCUMLiveDataManifest(manifest.SCUMLiveData)
|
||||
if manifest.MapTrajectories != nil {
|
||||
value := CopyGameMapTrajectoryDeclaration(*manifest.MapTrajectories)
|
||||
manifest.MapTrajectories = &value
|
||||
@@ -1853,10 +1826,6 @@ func CopyGamePluginRuntimeProfiles(profiles GamePluginRuntimeProfiles) GamePlugi
|
||||
for i := range profiles.TransportProfiles {
|
||||
profiles.TransportProfiles[i].Capabilities = CopyStringSlice(profiles.TransportProfiles[i].Capabilities)
|
||||
}
|
||||
profiles.DataTargets = append([]RuntimeDataTarget(nil), profiles.DataTargets...)
|
||||
for i := range profiles.DataTargets {
|
||||
profiles.DataTargets[i].Platforms = CopyStringSlice(profiles.DataTargets[i].Platforms)
|
||||
}
|
||||
profiles.ClientManagers = append([]RuntimeClientManagerProfile(nil), profiles.ClientManagers...)
|
||||
for i := range profiles.ClientManagers {
|
||||
profiles.ClientManagers[i].SupportedTargets = append([]RuntimeTarget(nil), profiles.ClientManagers[i].SupportedTargets...)
|
||||
@@ -2051,15 +2020,6 @@ func CopyJob(job Job) Job {
|
||||
job.ExecutionInput.DLLExtensions = append([]RuntimeDLLExtensionPlan(nil), job.ExecutionInput.DLLExtensions...)
|
||||
job.ExecutionInput.SourceRCON = CopyRuntimeSourceRCONPlan(job.ExecutionInput.SourceRCON)
|
||||
job.ExecutionInput.ServerDeploymentPlan = CopyServerDeploymentPlan(job.ExecutionInput.ServerDeploymentPlan)
|
||||
job.ExecutionInput.SQLiteSchemaProbe = CopySCUMSchemaProbeRequestPtr(job.ExecutionInput.SQLiteSchemaProbe)
|
||||
job.ExecutionInput.SQLiteTemplate = CopySCUMSQLiteTemplateRequestPtr(job.ExecutionInput.SQLiteTemplate)
|
||||
job.ExecutionInput.RCONTemplate = CopySCUMTypedRCONTemplateRequestPtr(job.ExecutionInput.RCONTemplate)
|
||||
job.ExecutionInput.GuardedMutation = CopySCUMGuardedMutationRequestPtr(job.ExecutionInput.GuardedMutation)
|
||||
job.ExecutionResult.SQLiteSchemaProbe = CopySCUMSchemaProbeResultPtr(job.ExecutionResult.SQLiteSchemaProbe)
|
||||
job.ExecutionResult.SQLiteTemplate = CopySCUMSQLiteTemplateResultPtr(job.ExecutionResult.SQLiteTemplate)
|
||||
job.ExecutionResult.RCONTemplate = CopySCUMTypedRCONTemplateResultPtr(job.ExecutionResult.RCONTemplate)
|
||||
job.ExecutionResult.GuardedMutation = CopySCUMGuardedMutationResultPtr(job.ExecutionResult.GuardedMutation)
|
||||
job.ExecutionResult.ParsedLogBatch = CopySCUMParsedLogBatchResultPtr(job.ExecutionResult.ParsedLogBatch)
|
||||
job.ExecutionResult.ServerDeploymentEvidence = CopyServerDeploymentEvidence(job.ExecutionResult.ServerDeploymentEvidence)
|
||||
job.ExecutionResult.DeploymentReceipt = CopyServerDeploymentExecutionReceipt(job.ExecutionResult.DeploymentReceipt)
|
||||
if job.ExecutionInput.Deployment != nil {
|
||||
|
||||
@@ -1,712 +0,0 @@
|
||||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type SCUMDataCapability string
|
||||
|
||||
const (
|
||||
SCUMDataCapabilitySchemaProbe SCUMDataCapability = "schema-probe"
|
||||
SCUMDataCapabilityPlayerRead SCUMDataCapability = "players.read"
|
||||
SCUMDataCapabilityPlayerDetailRead SCUMDataCapability = "player-details.read"
|
||||
SCUMDataCapabilitySquadRead SCUMDataCapability = "squads.read"
|
||||
SCUMDataCapabilitySquadMemberRead SCUMDataCapability = "squad-members.read"
|
||||
SCUMDataCapabilityVehicleRead SCUMDataCapability = "vehicles.read"
|
||||
SCUMDataCapabilityFlagRead SCUMDataCapability = "flags.read"
|
||||
SCUMDataCapabilityPositionRead SCUMDataCapability = "positions.read"
|
||||
SCUMDataCapabilityProfileXMLWrite SCUMDataCapability = "profile-xml.write"
|
||||
SCUMDataCapabilityEconomyCommand SCUMDataCapability = "economy-command.write"
|
||||
SCUMDataCapabilityGiftCommand SCUMDataCapability = "gift-command.write"
|
||||
)
|
||||
|
||||
type SCUMCapabilityEvidenceStatus string
|
||||
|
||||
const (
|
||||
SCUMSchemaProbeStatusSucceeded SCUMCapabilityEvidenceStatus = "succeeded"
|
||||
SCUMCapabilityEvidenceMissing SCUMCapabilityEvidenceStatus = "missing"
|
||||
SCUMCapabilityEvidenceCompatible SCUMCapabilityEvidenceStatus = "compatible"
|
||||
SCUMCapabilityEvidenceIncompatible SCUMCapabilityEvidenceStatus = "incompatible"
|
||||
SCUMCapabilityEvidenceFailed SCUMCapabilityEvidenceStatus = "failed"
|
||||
)
|
||||
|
||||
type SCUMCapabilityGateState string
|
||||
|
||||
const (
|
||||
SCUMCapabilityGateEnabled SCUMCapabilityGateState = "enabled"
|
||||
SCUMCapabilityGateDisabled SCUMCapabilityGateState = "disabled"
|
||||
)
|
||||
|
||||
type SCUMSafeErrorCode string
|
||||
|
||||
const (
|
||||
SCUMSafeErrorNone SCUMSafeErrorCode = "none"
|
||||
SCUMSafeErrorProbeExecutorAbsent SCUMSafeErrorCode = "probe_executor_absent"
|
||||
SCUMSafeErrorProbeMissing SCUMSafeErrorCode = "probe_missing"
|
||||
SCUMSafeErrorProbeFailed SCUMSafeErrorCode = "probe_failed"
|
||||
SCUMSafeErrorSchemaIncompatible SCUMSafeErrorCode = "schema_incompatible"
|
||||
SCUMSafeErrorBindingMismatch SCUMSafeErrorCode = "binding_mismatch"
|
||||
SCUMSafeErrorAdapterMismatch SCUMSafeErrorCode = "adapter_mismatch"
|
||||
SCUMSafeErrorFingerprintMismatch SCUMSafeErrorCode = "fingerprint_mismatch"
|
||||
SCUMSafeErrorDigestMismatch SCUMSafeErrorCode = "digest_mismatch"
|
||||
SCUMSafeErrorEvidenceExpired SCUMSafeErrorCode = "evidence_expired"
|
||||
SCUMSafeErrorInvalidProbePayload SCUMSafeErrorCode = "invalid_probe_payload"
|
||||
SCUMSafeErrorInvalidRequest SCUMSafeErrorCode = "invalid_request"
|
||||
SCUMSafeErrorTargetUnavailable SCUMSafeErrorCode = "target_unavailable"
|
||||
SCUMSafeErrorSourceUnavailable SCUMSafeErrorCode = "source_unavailable"
|
||||
SCUMSafeErrorSQLiteOpenFailed SCUMSafeErrorCode = "sqlite_open_failed"
|
||||
SCUMSafeErrorSQLiteReadFailed SCUMSafeErrorCode = "sqlite_read_failed"
|
||||
SCUMSafeErrorDatabaseBusy SCUMSafeErrorCode = "database_busy"
|
||||
SCUMSafeErrorTimeout SCUMSafeErrorCode = "timeout"
|
||||
SCUMSafeErrorCancelled SCUMSafeErrorCode = "cancelled"
|
||||
SCUMSafeErrorSourceChanged SCUMSafeErrorCode = "source_changed"
|
||||
SCUMSafeErrorResultLimitExceeded SCUMSafeErrorCode = "result_limit_exceeded"
|
||||
SCUMSafeErrorTemplateMissing SCUMSafeErrorCode = "template_missing"
|
||||
SCUMSafeErrorTemplateMismatch SCUMSafeErrorCode = "template_digest_mismatch"
|
||||
SCUMSafeErrorParameterInvalid SCUMSafeErrorCode = "parameter_schema_invalid"
|
||||
SCUMSafeErrorRowLimitExceeded SCUMSafeErrorCode = "row_limit_exceeded"
|
||||
SCUMSafeErrorResultSchemaInvalid SCUMSafeErrorCode = "result_schema_invalid"
|
||||
SCUMSafeErrorMutationGuardMismatch SCUMSafeErrorCode = "mutation_guard_mismatch"
|
||||
SCUMSafeErrorMutationBackupUnavailable SCUMSafeErrorCode = "mutation_backup_unavailable"
|
||||
SCUMSafeErrorMutationOfflineRequired SCUMSafeErrorCode = "mutation_offline_required"
|
||||
SCUMSafeErrorMutationConfirmationMissing SCUMSafeErrorCode = "mutation_confirmation_missing"
|
||||
SCUMSafeErrorMutationPatchInvalid SCUMSafeErrorCode = "mutation_patch_invalid"
|
||||
SCUMSafeErrorAffectedRowsMismatch SCUMSafeErrorCode = "affected_rows_mismatch"
|
||||
SCUMSafeErrorReadbackMismatch SCUMSafeErrorCode = "readback_mismatch"
|
||||
SCUMSafeErrorRollbackFailed SCUMSafeErrorCode = "rollback_failed"
|
||||
)
|
||||
|
||||
type SCUMTerminalResultStatus string
|
||||
|
||||
const (
|
||||
SCUMTerminalResultSucceeded SCUMTerminalResultStatus = "succeeded"
|
||||
SCUMTerminalResultFailed SCUMTerminalResultStatus = "failed"
|
||||
SCUMTerminalResultCancelled SCUMTerminalResultStatus = "cancelled"
|
||||
)
|
||||
|
||||
type SCUMRCONConfirmationStatus string
|
||||
|
||||
const (
|
||||
SCUMRCONConfirmationConfirmed SCUMRCONConfirmationStatus = "confirmed"
|
||||
SCUMRCONConfirmationFailed SCUMRCONConfirmationStatus = "failed"
|
||||
SCUMRCONConfirmationUnknown SCUMRCONConfirmationStatus = "unknown"
|
||||
)
|
||||
|
||||
type SCUMMutationReadbackStatus string
|
||||
|
||||
const (
|
||||
SCUMMutationReadbackConfirmed SCUMMutationReadbackStatus = "confirmed"
|
||||
SCUMMutationReadbackFailed SCUMMutationReadbackStatus = "failed"
|
||||
SCUMMutationReadbackConflict SCUMMutationReadbackStatus = "conflict"
|
||||
SCUMMutationReadbackUnknown SCUMMutationReadbackStatus = "unknown"
|
||||
)
|
||||
|
||||
type SCUMSafeError struct {
|
||||
Code SCUMSafeErrorCode
|
||||
Message string
|
||||
Retryable bool
|
||||
}
|
||||
|
||||
type SCUMBindingIdentity struct {
|
||||
ServerInstanceID string
|
||||
RunBindingID string
|
||||
RunEndpointID string
|
||||
PluginID string
|
||||
PluginVersion string
|
||||
AdapterVersion string
|
||||
GameVersion string
|
||||
DatabaseIdentity string
|
||||
}
|
||||
|
||||
type SCUMSchemaProbeBounds struct {
|
||||
MaxObjects int
|
||||
MaxColumnsPerObject int
|
||||
MaxIndexesPerObject int
|
||||
MaxForeignKeys int
|
||||
MaxCardinalityReads int
|
||||
MaxSampleRows int
|
||||
TimeoutMS int
|
||||
MaxResultBytes int
|
||||
}
|
||||
|
||||
func DefaultSCUMSchemaProbeBounds() SCUMSchemaProbeBounds {
|
||||
return SCUMSchemaProbeBounds{MaxObjects: 256, MaxColumnsPerObject: 128, MaxIndexesPerObject: 64, MaxForeignKeys: 64, MaxCardinalityReads: 64, MaxSampleRows: 3, TimeoutMS: 5000, MaxResultBytes: 512 * 1024}
|
||||
}
|
||||
|
||||
type SCUMSQLiteTemplateBounds struct {
|
||||
MaxParameters int
|
||||
MaxRows int
|
||||
TimeoutMS int
|
||||
BusyTimeoutMS int
|
||||
MaxResultBytes int
|
||||
}
|
||||
|
||||
func DefaultSCUMSQLiteTemplateBounds() SCUMSQLiteTemplateBounds {
|
||||
return SCUMSQLiteTemplateBounds{MaxParameters: 64, MaxRows: 500, TimeoutMS: 5000, BusyTimeoutMS: 250, MaxResultBytes: 1024 * 1024}
|
||||
}
|
||||
|
||||
type SCUMTypedRCONTemplateBounds struct {
|
||||
MaxPayloadBytes int
|
||||
TimeoutMS int
|
||||
MaxResponseBytes int
|
||||
MaxConfirmRecords int
|
||||
}
|
||||
|
||||
func DefaultSCUMTypedRCONTemplateBounds() SCUMTypedRCONTemplateBounds {
|
||||
return SCUMTypedRCONTemplateBounds{MaxPayloadBytes: 2048, TimeoutMS: 5000, MaxResponseBytes: 16 * 1024, MaxConfirmRecords: 16}
|
||||
}
|
||||
|
||||
type SCUMGuardedMutationBounds struct {
|
||||
MaxPayloadBytes int
|
||||
TimeoutMS int
|
||||
BusyTimeoutMS int
|
||||
MaxReadbackBytes int
|
||||
MaxAffectedRows int
|
||||
}
|
||||
|
||||
func DefaultSCUMGuardedMutationBounds() SCUMGuardedMutationBounds {
|
||||
return SCUMGuardedMutationBounds{MaxPayloadBytes: 4096, TimeoutMS: 5000, BusyTimeoutMS: 250, MaxReadbackBytes: 16 * 1024, MaxAffectedRows: 1}
|
||||
}
|
||||
|
||||
type SCUMParsedLogBatchBounds struct {
|
||||
MaxEvents int
|
||||
MaxPayloadBytes int
|
||||
MaxLineBytes int
|
||||
MaxResultBytes int
|
||||
}
|
||||
|
||||
func DefaultSCUMParsedLogBatchBounds() SCUMParsedLogBatchBounds {
|
||||
return SCUMParsedLogBatchBounds{MaxEvents: 256, MaxPayloadBytes: 16 * 1024, MaxLineBytes: 4096, MaxResultBytes: 256 * 1024}
|
||||
}
|
||||
|
||||
type SCUMLogTailState string
|
||||
|
||||
const (
|
||||
SCUMLogTailAdvanced SCUMLogTailState = "advanced"
|
||||
SCUMLogTailRotated SCUMLogTailState = "rotated"
|
||||
SCUMLogTailTruncated SCUMLogTailState = "truncated"
|
||||
SCUMLogTailRestarted SCUMLogTailState = "restarted"
|
||||
SCUMLogTailPartial SCUMLogTailState = "partial-buffered"
|
||||
SCUMLogTailReplayed SCUMLogTailState = "replayed"
|
||||
)
|
||||
|
||||
type SCUMParsedLogCursor struct {
|
||||
SourceIdentityDigest string
|
||||
StreamGeneration string
|
||||
Sequence uint64
|
||||
}
|
||||
|
||||
type SCUMParsedLogEvent struct {
|
||||
EventType string
|
||||
OccurredAt time.Time
|
||||
Cursor SCUMParsedLogCursor
|
||||
LogicalEventDigest string
|
||||
EventDigest string
|
||||
PayloadDigest string
|
||||
Payload map[string]any
|
||||
}
|
||||
|
||||
type SCUMSchemaProbeRequest struct {
|
||||
RequestID string
|
||||
JobID string
|
||||
Binding SCUMBindingIdentity
|
||||
Bounds SCUMSchemaProbeBounds
|
||||
RequestedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMSQLiteTemplateRequest struct {
|
||||
RequestID string
|
||||
JobID string
|
||||
Binding SCUMBindingIdentity
|
||||
Capability SCUMDataCapability
|
||||
TargetKey string
|
||||
TemplateKey string
|
||||
AdapterVersion string
|
||||
RequiredSchemaFingerprint string
|
||||
AssetDigest string
|
||||
ParameterDigest string
|
||||
Parameters map[string]any
|
||||
Bounds SCUMSQLiteTemplateBounds
|
||||
RequestedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMTypedRCONTemplateRequest struct {
|
||||
RequestID string
|
||||
JobID string
|
||||
Binding SCUMBindingIdentity
|
||||
Capability SCUMDataCapability
|
||||
TransportKey string
|
||||
TargetKey string
|
||||
TemplateKey string
|
||||
AdapterVersion string
|
||||
RequiredSchemaFingerprint string
|
||||
AssetDigest string
|
||||
PayloadDigest string
|
||||
ConfirmationDigest string
|
||||
TargetIdentityDigest string
|
||||
IdempotencyKey string
|
||||
Payload map[string]any
|
||||
ReviewReason string
|
||||
Bounds SCUMTypedRCONTemplateBounds
|
||||
RequestedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMGuardedMutationRequest struct {
|
||||
RequestID string
|
||||
JobID string
|
||||
Binding SCUMBindingIdentity
|
||||
Capability SCUMDataCapability
|
||||
TargetKey string
|
||||
TemplateKey string
|
||||
AdapterVersion string
|
||||
RequiredSchemaFingerprint string
|
||||
AssetDigest string
|
||||
TargetIdentityDigest string
|
||||
ExpectedRowDigest string
|
||||
ExpectedValueDigest string
|
||||
ExpectedXMLDigest string
|
||||
PatchDigest string
|
||||
BackupEvidenceDigest string
|
||||
OfflineEvidenceDigest string
|
||||
DangerConfirmationDigest string
|
||||
ReadbackExpectationDigest string
|
||||
IdempotencyKey string
|
||||
Payload map[string]any
|
||||
ReviewReason string
|
||||
Bounds SCUMGuardedMutationBounds
|
||||
RequestedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMSchemaProbeDeclaration struct {
|
||||
Capability string
|
||||
TargetKey string
|
||||
Bounds SCUMSchemaProbeBounds
|
||||
}
|
||||
|
||||
type SCUMLiveDataCapabilityGateDeclaration struct {
|
||||
Capability SCUMDataCapability
|
||||
Gate SCUMCapabilityGateState
|
||||
AdapterVersion string
|
||||
RequiredSchemaFingerprint string
|
||||
RequiredAssetDigests []string
|
||||
EvidenceStatus SCUMCapabilityEvidenceStatus
|
||||
SafeReason string
|
||||
}
|
||||
|
||||
type SCUMLiveDataManifest struct {
|
||||
SchemaVersion string
|
||||
Probe SCUMSchemaProbeDeclaration
|
||||
CapabilityGates []SCUMLiveDataCapabilityGateDeclaration
|
||||
}
|
||||
|
||||
type SCUMSchemaColumnEvidence struct {
|
||||
NameFingerprint string
|
||||
DeclaredType string
|
||||
Nullable *bool
|
||||
PrimaryKey bool
|
||||
Ordinal int
|
||||
}
|
||||
|
||||
type SCUMSchemaIndexEvidence struct {
|
||||
NameFingerprint string
|
||||
Unique bool
|
||||
ColumnHashes []string
|
||||
}
|
||||
|
||||
type SCUMSchemaForeignKeyEvidence struct {
|
||||
FromColumnHash string
|
||||
ToObjectHash string
|
||||
ToColumnHash string
|
||||
}
|
||||
|
||||
type SCUMSchemaObjectEvidence struct {
|
||||
ObjectHash string
|
||||
Kind string
|
||||
NameFingerprint string
|
||||
DeclaredColumns []SCUMSchemaColumnEvidence
|
||||
Indexes []SCUMSchemaIndexEvidence
|
||||
ForeignKeys []SCUMSchemaForeignKeyEvidence
|
||||
ApproximateRows *int64
|
||||
SampleFingerprints []string
|
||||
}
|
||||
|
||||
type SCUMSchemaProbeResult struct {
|
||||
RequestID string
|
||||
JobID string
|
||||
Binding SCUMBindingIdentity
|
||||
Status SCUMCapabilityEvidenceStatus
|
||||
SourceFingerprint string
|
||||
SchemaFingerprint string
|
||||
ObservedAt time.Time
|
||||
ResultDigest string
|
||||
Objects []SCUMSchemaObjectEvidence
|
||||
SafeError SCUMSafeError
|
||||
Limits SCUMSchemaProbeBounds
|
||||
}
|
||||
|
||||
type SCUMSQLiteTemplateResult struct {
|
||||
RequestID string
|
||||
JobID string
|
||||
Binding SCUMBindingIdentity
|
||||
Status SCUMTerminalResultStatus
|
||||
Capability SCUMDataCapability
|
||||
TargetKey string
|
||||
TemplateKey string
|
||||
AdapterVersion string
|
||||
SchemaFingerprint string
|
||||
AssetDigest string
|
||||
ParameterDigest string
|
||||
SourceFingerprint string
|
||||
ObservedAt time.Time
|
||||
ResultDigest string
|
||||
RowCount int
|
||||
Rows []map[string]any
|
||||
Truncated bool
|
||||
SafeError SCUMSafeError
|
||||
Limits SCUMSQLiteTemplateBounds
|
||||
}
|
||||
|
||||
type SCUMTypedRCONTemplateResult struct {
|
||||
RequestID string
|
||||
JobID string
|
||||
Binding SCUMBindingIdentity
|
||||
Status SCUMTerminalResultStatus
|
||||
Capability SCUMDataCapability
|
||||
TransportKey string
|
||||
TargetKey string
|
||||
TemplateKey string
|
||||
AdapterVersion string
|
||||
SchemaFingerprint string
|
||||
AssetDigest string
|
||||
PayloadDigest string
|
||||
ConfirmationDigest string
|
||||
TargetIdentityDigest string
|
||||
ObservedAt time.Time
|
||||
ResultDigest string
|
||||
ResponseDigest string
|
||||
ConfirmationStatus SCUMRCONConfirmationStatus
|
||||
ConfirmationDigestID string
|
||||
SafeSummary string
|
||||
SafeError SCUMSafeError
|
||||
Limits SCUMTypedRCONTemplateBounds
|
||||
}
|
||||
|
||||
type SCUMGuardedMutationResult struct {
|
||||
RequestID string
|
||||
JobID string
|
||||
Binding SCUMBindingIdentity
|
||||
Status SCUMTerminalResultStatus
|
||||
Capability SCUMDataCapability
|
||||
TargetKey string
|
||||
TemplateKey string
|
||||
AdapterVersion string
|
||||
SchemaFingerprint string
|
||||
AssetDigest string
|
||||
SourceFingerprint string
|
||||
TargetIdentityDigest string
|
||||
ExpectedRowDigest string
|
||||
ExpectedValueDigest string
|
||||
ExpectedXMLDigest string
|
||||
PatchDigest string
|
||||
BackupEvidenceDigest string
|
||||
OfflineEvidenceDigest string
|
||||
DangerConfirmationDigest string
|
||||
ReadbackExpectationDigest string
|
||||
ObservedAt time.Time
|
||||
ResultDigest string
|
||||
BeforeDigest string
|
||||
AfterDigest string
|
||||
ReadbackDigest string
|
||||
AffectedRows int
|
||||
ReadbackStatus SCUMMutationReadbackStatus
|
||||
SafeSummary string
|
||||
SafeError SCUMSafeError
|
||||
Limits SCUMGuardedMutationBounds
|
||||
}
|
||||
|
||||
type SCUMParsedLogBatchResult struct {
|
||||
RequestID string
|
||||
JobID string
|
||||
Binding SCUMBindingIdentity
|
||||
Status SCUMTerminalResultStatus
|
||||
SourceKey string
|
||||
StreamKey string
|
||||
ParserKey string
|
||||
ParserVersion string
|
||||
AdapterVersion string
|
||||
AssetDigest string
|
||||
ParserDigest string
|
||||
ObservedAt time.Time
|
||||
ResultDigest string
|
||||
FirstCursor SCUMParsedLogCursor
|
||||
LastCursor SCUMParsedLogCursor
|
||||
TailState SCUMLogTailState
|
||||
PartialLineBuffered bool
|
||||
Replay bool
|
||||
EventCount int
|
||||
Events []SCUMParsedLogEvent
|
||||
SafeSummary string
|
||||
SafeError SCUMSafeError
|
||||
Limits SCUMParsedLogBatchBounds
|
||||
}
|
||||
|
||||
type SCUMCapabilityRequirement struct {
|
||||
Capability SCUMDataCapability
|
||||
AdapterVersion string
|
||||
SchemaFingerprint string
|
||||
AssetDigests []string
|
||||
}
|
||||
|
||||
type SCUMCapabilityEvidence struct {
|
||||
Capability SCUMDataCapability
|
||||
Status SCUMCapabilityEvidenceStatus
|
||||
Binding SCUMBindingIdentity
|
||||
AdapterVersion string
|
||||
SchemaFingerprint string
|
||||
ProbeResultDigest string
|
||||
AssetDigests []string
|
||||
ObservedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
SafeError SCUMSafeError
|
||||
}
|
||||
|
||||
type SCUMCapabilityGate struct {
|
||||
Capability SCUMDataCapability
|
||||
State SCUMCapabilityGateState
|
||||
Enabled bool
|
||||
ReasonCode SCUMSafeErrorCode
|
||||
Reason string
|
||||
Evidence SCUMCapabilityEvidence
|
||||
}
|
||||
|
||||
type SCUMCapabilityNegotiation struct {
|
||||
ServerInstanceID string
|
||||
RunEndpointID string
|
||||
RunBindingID string
|
||||
PluginID string
|
||||
PluginVersion string
|
||||
AdapterVersion string
|
||||
GameVersion string
|
||||
DatabaseIdentity string
|
||||
ProbeExecutorAvailable bool
|
||||
EvaluatedAt time.Time
|
||||
Gates []SCUMCapabilityGate
|
||||
}
|
||||
|
||||
func EvaluateSCUMCapabilityGate(requirement SCUMCapabilityRequirement, evidence SCUMCapabilityEvidence, active SCUMBindingIdentity, probeExecutorAvailable bool, now time.Time) SCUMCapabilityGate {
|
||||
gate := SCUMCapabilityGate{Capability: requirement.Capability, State: SCUMCapabilityGateDisabled, ReasonCode: SCUMSafeErrorProbeMissing, Reason: "current-service evidence is required before this SCUM capability can run"}
|
||||
if !probeExecutorAvailable {
|
||||
gate.ReasonCode = SCUMSafeErrorProbeExecutorAbsent
|
||||
gate.Reason = "bound Run does not expose the generic SQLite schema-probe executor"
|
||||
return gate
|
||||
}
|
||||
if evidence.Status == SCUMCapabilityEvidenceMissing || evidence.Capability == "" {
|
||||
return gate
|
||||
}
|
||||
gate.Evidence = CopySCUMCapabilityEvidence(evidence)
|
||||
if evidence.Status == SCUMCapabilityEvidenceFailed {
|
||||
gate.ReasonCode = SCUMSafeErrorProbeFailed
|
||||
gate.Reason = safeReason(evidence.SafeError.Message, "last schema probe failed")
|
||||
return gate
|
||||
}
|
||||
if evidence.Status == SCUMCapabilityEvidenceIncompatible {
|
||||
gate.ReasonCode = SCUMSafeErrorSchemaIncompatible
|
||||
gate.Reason = safeReason(evidence.SafeError.Message, "current schema is incompatible with the plugin adapter")
|
||||
return gate
|
||||
}
|
||||
if evidence.Capability != requirement.Capability {
|
||||
gate.ReasonCode = SCUMSafeErrorSchemaIncompatible
|
||||
gate.Reason = "capability evidence does not match the requested SCUM capability"
|
||||
return gate
|
||||
}
|
||||
if !sameSCUMBinding(evidence.Binding, active) {
|
||||
gate.ReasonCode = SCUMSafeErrorBindingMismatch
|
||||
gate.Reason = "evidence belongs to a different server, Run binding, plugin, adapter, game, or database identity"
|
||||
return gate
|
||||
}
|
||||
if evidence.AdapterVersion != requirement.AdapterVersion {
|
||||
gate.ReasonCode = SCUMSafeErrorAdapterMismatch
|
||||
gate.Reason = "evidence adapter version does not match the plugin requirement"
|
||||
return gate
|
||||
}
|
||||
if evidence.SchemaFingerprint == "" || evidence.SchemaFingerprint != requirement.SchemaFingerprint {
|
||||
gate.ReasonCode = SCUMSafeErrorFingerprintMismatch
|
||||
gate.Reason = "schema fingerprint does not match the plugin requirement"
|
||||
return gate
|
||||
}
|
||||
if !containsAllStrings(evidence.AssetDigests, requirement.AssetDigests) {
|
||||
gate.ReasonCode = SCUMSafeErrorDigestMismatch
|
||||
gate.Reason = "packaged asset digest does not match the compatible evidence"
|
||||
return gate
|
||||
}
|
||||
if !evidence.ExpiresAt.IsZero() && !now.IsZero() && !now.Before(evidence.ExpiresAt) {
|
||||
gate.ReasonCode = SCUMSafeErrorEvidenceExpired
|
||||
gate.Reason = "current-service evidence has expired and must be probed again"
|
||||
return gate
|
||||
}
|
||||
gate.State = SCUMCapabilityGateEnabled
|
||||
gate.Enabled = true
|
||||
gate.ReasonCode = SCUMSafeErrorNone
|
||||
gate.Reason = "current-service evidence matches the versioned plugin adapter"
|
||||
return gate
|
||||
}
|
||||
|
||||
func CopySCUMCapabilityEvidence(value SCUMCapabilityEvidence) SCUMCapabilityEvidence {
|
||||
value.AssetDigests = append([]string(nil), value.AssetDigests...)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMSQLiteTemplateRequestPtr(value *SCUMSQLiteTemplateRequest) *SCUMSQLiteTemplateRequest {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
copy.Parameters = CopySCUMValueMap(value.Parameters)
|
||||
return ©
|
||||
}
|
||||
|
||||
func CopySCUMTypedRCONTemplateRequestPtr(value *SCUMTypedRCONTemplateRequest) *SCUMTypedRCONTemplateRequest {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
copy.Payload = CopySCUMValueMap(value.Payload)
|
||||
return ©
|
||||
}
|
||||
|
||||
func CopySCUMGuardedMutationRequestPtr(value *SCUMGuardedMutationRequest) *SCUMGuardedMutationRequest {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
copy.Payload = CopySCUMValueMap(value.Payload)
|
||||
return ©
|
||||
}
|
||||
|
||||
func CopySCUMSQLiteTemplateResultPtr(value *SCUMSQLiteTemplateResult) *SCUMSQLiteTemplateResult {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
copy.Rows = CopySCUMRows(value.Rows)
|
||||
return ©
|
||||
}
|
||||
|
||||
func CopySCUMTypedRCONTemplateResultPtr(value *SCUMTypedRCONTemplateResult) *SCUMTypedRCONTemplateResult {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
return ©
|
||||
}
|
||||
|
||||
func CopySCUMGuardedMutationResultPtr(value *SCUMGuardedMutationResult) *SCUMGuardedMutationResult {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
return ©
|
||||
}
|
||||
|
||||
func CopySCUMParsedLogBatchResultPtr(value *SCUMParsedLogBatchResult) *SCUMParsedLogBatchResult {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
copy.Events = CopySCUMParsedLogEvents(value.Events)
|
||||
return ©
|
||||
}
|
||||
|
||||
func CopySCUMParsedLogEvents(events []SCUMParsedLogEvent) []SCUMParsedLogEvent {
|
||||
if events == nil {
|
||||
return nil
|
||||
}
|
||||
copy := make([]SCUMParsedLogEvent, len(events))
|
||||
for index, event := range events {
|
||||
copy[index] = event
|
||||
copy[index].Payload = CopySCUMValueMap(event.Payload)
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
func CopySCUMValueMap(value map[string]any) map[string]any {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := make(map[string]any, len(value))
|
||||
for key, item := range value {
|
||||
copy[key] = item
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
func CopySCUMRows(rows []map[string]any) []map[string]any {
|
||||
if rows == nil {
|
||||
return nil
|
||||
}
|
||||
copy := make([]map[string]any, len(rows))
|
||||
for index, row := range rows {
|
||||
copy[index] = CopySCUMValueMap(row)
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
func CopySCUMSchemaProbeResult(value SCUMSchemaProbeResult) SCUMSchemaProbeResult {
|
||||
value.Objects = append([]SCUMSchemaObjectEvidence(nil), value.Objects...)
|
||||
for index := range value.Objects {
|
||||
value.Objects[index].DeclaredColumns = append([]SCUMSchemaColumnEvidence(nil), value.Objects[index].DeclaredColumns...)
|
||||
value.Objects[index].Indexes = append([]SCUMSchemaIndexEvidence(nil), value.Objects[index].Indexes...)
|
||||
value.Objects[index].ForeignKeys = append([]SCUMSchemaForeignKeyEvidence(nil), value.Objects[index].ForeignKeys...)
|
||||
value.Objects[index].SampleFingerprints = append([]string(nil), value.Objects[index].SampleFingerprints...)
|
||||
for idx := range value.Objects[index].Indexes {
|
||||
value.Objects[index].Indexes[idx].ColumnHashes = append([]string(nil), value.Objects[index].Indexes[idx].ColumnHashes...)
|
||||
}
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMSchemaProbeRequestPtr(value *SCUMSchemaProbeRequest) *SCUMSchemaProbeRequest {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := *value
|
||||
return ©
|
||||
}
|
||||
|
||||
func CopySCUMSchemaProbeResultPtr(value *SCUMSchemaProbeResult) *SCUMSchemaProbeResult {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
copy := CopySCUMSchemaProbeResult(*value)
|
||||
return ©
|
||||
}
|
||||
|
||||
func CopySCUMLiveDataManifest(value SCUMLiveDataManifest) SCUMLiveDataManifest {
|
||||
value.CapabilityGates = append([]SCUMLiveDataCapabilityGateDeclaration(nil), value.CapabilityGates...)
|
||||
for index := range value.CapabilityGates {
|
||||
value.CapabilityGates[index].RequiredAssetDigests = append([]string(nil), value.CapabilityGates[index].RequiredAssetDigests...)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func sameSCUMBinding(a SCUMBindingIdentity, b SCUMBindingIdentity) bool {
|
||||
return a.ServerInstanceID == b.ServerInstanceID && a.RunBindingID == b.RunBindingID && a.RunEndpointID == b.RunEndpointID && a.PluginID == b.PluginID && a.PluginVersion == b.PluginVersion && a.AdapterVersion == b.AdapterVersion && a.GameVersion == b.GameVersion && a.DatabaseIdentity == b.DatabaseIdentity
|
||||
}
|
||||
|
||||
func containsAllStrings(values []string, required []string) bool {
|
||||
set := map[string]struct{}{}
|
||||
for _, value := range values {
|
||||
set[value] = struct{}{}
|
||||
}
|
||||
for _, value := range required {
|
||||
if _, ok := set[value]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func safeReason(value string, fallback string) string {
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
return value
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSCUMCapabilityGateDefaultsClosedWithoutProbeEvidence(t *testing.T) {
|
||||
active := scumGateBinding()
|
||||
requirement := SCUMCapabilityRequirement{Capability: SCUMDataCapabilityPlayerRead, AdapterVersion: "adapter-1", SchemaFingerprint: "schema-1", AssetDigests: []string{"sha256:query"}}
|
||||
|
||||
gate := EvaluateSCUMCapabilityGate(requirement, SCUMCapabilityEvidence{}, active, true, time.Now())
|
||||
|
||||
if gate.Enabled || gate.State != SCUMCapabilityGateDisabled || gate.ReasonCode != SCUMSafeErrorProbeMissing {
|
||||
t.Fatalf("expected closed gate without evidence, got %#v", gate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSCUMCapabilityGateDefaultsClosedWhenProbeExecutorUnavailable(t *testing.T) {
|
||||
active := scumGateBinding()
|
||||
requirement := SCUMCapabilityRequirement{Capability: SCUMDataCapabilityPlayerRead, AdapterVersion: "adapter-1", SchemaFingerprint: "schema-1"}
|
||||
evidence := SCUMCapabilityEvidence{Capability: SCUMDataCapabilityPlayerRead, Status: SCUMCapabilityEvidenceCompatible, Binding: active, AdapterVersion: "adapter-1", SchemaFingerprint: "schema-1"}
|
||||
|
||||
gate := EvaluateSCUMCapabilityGate(requirement, evidence, active, false, time.Now())
|
||||
|
||||
if gate.Enabled || gate.ReasonCode != SCUMSafeErrorProbeExecutorAbsent {
|
||||
t.Fatalf("expected executor gate failure, got %#v", gate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSCUMCapabilityGateEnablesOnlyMatchingEvidence(t *testing.T) {
|
||||
now := time.Date(2026, 8, 11, 12, 0, 0, 0, time.UTC)
|
||||
active := scumGateBinding()
|
||||
requirement := SCUMCapabilityRequirement{Capability: SCUMDataCapabilityVehicleRead, AdapterVersion: "adapter-1", SchemaFingerprint: "schema-1", AssetDigests: []string{"sha256:vehicle-query"}}
|
||||
evidence := SCUMCapabilityEvidence{Capability: SCUMDataCapabilityVehicleRead, Status: SCUMCapabilityEvidenceCompatible, Binding: active, AdapterVersion: "adapter-1", SchemaFingerprint: "schema-1", AssetDigests: []string{"sha256:vehicle-query", "sha256:result-schema"}, ExpiresAt: now.Add(time.Hour)}
|
||||
|
||||
gate := EvaluateSCUMCapabilityGate(requirement, evidence, active, true, now)
|
||||
|
||||
if !gate.Enabled || gate.State != SCUMCapabilityGateEnabled || gate.ReasonCode != SCUMSafeErrorNone {
|
||||
t.Fatalf("expected enabled gate, got %#v", gate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSCUMCapabilityGateRejectsMismatchedCurrentServiceEvidence(t *testing.T) {
|
||||
now := time.Date(2026, 8, 11, 12, 0, 0, 0, time.UTC)
|
||||
active := scumGateBinding()
|
||||
requirement := SCUMCapabilityRequirement{Capability: SCUMDataCapabilityPositionRead, AdapterVersion: "adapter-1", SchemaFingerprint: "schema-1", AssetDigests: []string{"sha256:positions"}}
|
||||
evidence := SCUMCapabilityEvidence{Capability: SCUMDataCapabilityPositionRead, Status: SCUMCapabilityEvidenceCompatible, Binding: active, AdapterVersion: "adapter-1", SchemaFingerprint: "schema-1", AssetDigests: []string{"sha256:positions"}, ExpiresAt: now.Add(time.Hour)}
|
||||
|
||||
changedBinding := evidence
|
||||
changedBinding.Binding.DatabaseIdentity = "db-other"
|
||||
if gate := EvaluateSCUMCapabilityGate(requirement, changedBinding, active, true, now); gate.Enabled || gate.ReasonCode != SCUMSafeErrorBindingMismatch {
|
||||
t.Fatalf("expected binding mismatch, got %#v", gate)
|
||||
}
|
||||
|
||||
changedFingerprint := evidence
|
||||
changedFingerprint.SchemaFingerprint = "schema-other"
|
||||
if gate := EvaluateSCUMCapabilityGate(requirement, changedFingerprint, active, true, now); gate.Enabled || gate.ReasonCode != SCUMSafeErrorFingerprintMismatch {
|
||||
t.Fatalf("expected fingerprint mismatch, got %#v", gate)
|
||||
}
|
||||
|
||||
changedDigest := evidence
|
||||
changedDigest.AssetDigests = []string{"sha256:different"}
|
||||
if gate := EvaluateSCUMCapabilityGate(requirement, changedDigest, active, true, now); gate.Enabled || gate.ReasonCode != SCUMSafeErrorDigestMismatch {
|
||||
t.Fatalf("expected digest mismatch, got %#v", gate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultSCUMSchemaProbeBoundsAreBoundedAndDiagnosticOnly(t *testing.T) {
|
||||
bounds := DefaultSCUMSchemaProbeBounds()
|
||||
if bounds.MaxObjects <= 0 || bounds.MaxSampleRows > 3 || bounds.TimeoutMS > 5000 || bounds.MaxResultBytes > 512*1024 {
|
||||
t.Fatalf("unexpected unsafe default probe bounds: %#v", bounds)
|
||||
}
|
||||
}
|
||||
|
||||
func scumGateBinding() SCUMBindingIdentity {
|
||||
return SCUMBindingIdentity{ServerInstanceID: "server-1", RunBindingID: "binding-1", RunEndpointID: "run-1", PluginID: "game.scum", PluginVersion: "0.1.6", AdapterVersion: "adapter-1", GameVersion: "scum-1", DatabaseIdentity: "db-current"}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type SCUMProjectionSubject string
|
||||
|
||||
const (
|
||||
SCUMProjectionSubjectPlayer SCUMProjectionSubject = "player"
|
||||
SCUMProjectionSubjectLiveState SCUMProjectionSubject = "player-live-state"
|
||||
SCUMProjectionSubjectSquad SCUMProjectionSubject = "squad"
|
||||
SCUMProjectionSubjectMember SCUMProjectionSubject = "squad-member"
|
||||
SCUMProjectionSubjectVehicle SCUMProjectionSubject = "vehicle"
|
||||
SCUMProjectionSubjectFlag SCUMProjectionSubject = "flag"
|
||||
SCUMProjectionSubjectPosition SCUMProjectionSubject = "position"
|
||||
)
|
||||
|
||||
type SCUMProjectionFilter struct {
|
||||
ServerInstanceID string
|
||||
GamePlayerID string
|
||||
GamePlayerRecordID string
|
||||
UserProfileID string
|
||||
SteamID string
|
||||
SquadID string
|
||||
VehicleID string
|
||||
FlagID string
|
||||
SubjectType SCUMProjectionSubject
|
||||
QueryKey string
|
||||
Freshness SCUMProjectionFreshness
|
||||
Search string
|
||||
Limit int
|
||||
}
|
||||
|
||||
type SCUMPlayerLiveState struct {
|
||||
ID string
|
||||
ServerInstanceID string
|
||||
GamePlayerRecordID string
|
||||
GamePlayerID string
|
||||
UserProfileID string
|
||||
SteamID string
|
||||
DisplayName string
|
||||
SquadID string
|
||||
SquadName string
|
||||
Online bool
|
||||
FamePoints float64
|
||||
NormalBalance float64
|
||||
GoldBalance float64
|
||||
LastLoginAt time.Time
|
||||
LastLogoutAt time.Time
|
||||
LastSaveTime time.Time
|
||||
Position SCUMCurrentPosition
|
||||
UnknownFields map[string]any
|
||||
Freshness SCUMProjectionFreshnessState
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMSquad struct {
|
||||
ID string
|
||||
ServerInstanceID string
|
||||
SquadID string
|
||||
Name string
|
||||
LeaderProfileID string
|
||||
LeaderPlayerID string
|
||||
MemberCount int
|
||||
Score float64
|
||||
UnknownFields map[string]any
|
||||
Freshness SCUMProjectionFreshnessState
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMSquadMember struct {
|
||||
ID string
|
||||
ServerInstanceID string
|
||||
SquadID string
|
||||
UserProfileID string
|
||||
GamePlayerRecordID string
|
||||
GamePlayerID string
|
||||
SteamID string
|
||||
DisplayName string
|
||||
Rank string
|
||||
IsLeader bool
|
||||
JoinedAt time.Time
|
||||
UnknownFields map[string]any
|
||||
Freshness SCUMProjectionFreshnessState
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMVehicle struct {
|
||||
ID string
|
||||
ServerInstanceID string
|
||||
VehicleID string
|
||||
EntityID string
|
||||
ClassName string
|
||||
Label string
|
||||
OwnerProfileID string
|
||||
OwnerPlayerID string
|
||||
SquadID string
|
||||
Position SCUMCurrentPosition
|
||||
UnknownFields map[string]any
|
||||
Freshness SCUMProjectionFreshnessState
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMFlag struct {
|
||||
ID string
|
||||
ServerInstanceID string
|
||||
FlagID string
|
||||
EntityID string
|
||||
OwnerProfileID string
|
||||
OwnerPlayerID string
|
||||
OwnerSquadID string
|
||||
OwnerSquadName string
|
||||
OwnershipConfidence string
|
||||
Position SCUMCurrentPosition
|
||||
UnknownFields map[string]any
|
||||
Freshness SCUMProjectionFreshnessState
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMCurrentPosition struct {
|
||||
ID string
|
||||
ServerInstanceID string
|
||||
SubjectType SCUMProjectionSubject
|
||||
SubjectID string
|
||||
GamePlayerRecordID string
|
||||
GamePlayerID string
|
||||
VehicleID string
|
||||
EntityID string
|
||||
MapID string
|
||||
MapVersion string
|
||||
X float64
|
||||
Y float64
|
||||
Z float64
|
||||
HasCoordinates bool
|
||||
LastSaveTime time.Time
|
||||
Freshness SCUMProjectionFreshnessState
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
func SCUMProjectionStateUnknown() SCUMProjectionFreshnessState {
|
||||
return SCUMProjectionFreshnessState{Status: SCUMProjectionUnknown}
|
||||
}
|
||||
|
||||
func CopySCUMPlayerLiveState(value SCUMPlayerLiveState) SCUMPlayerLiveState {
|
||||
value.Position = CopySCUMCurrentPosition(value.Position)
|
||||
value.UnknownFields = CopyGameClientBridgePayload(value.UnknownFields)
|
||||
value.Freshness = CopySCUMProjectionFreshnessState(value.Freshness)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMSquad(value SCUMSquad) SCUMSquad {
|
||||
value.UnknownFields = CopyGameClientBridgePayload(value.UnknownFields)
|
||||
value.Freshness = CopySCUMProjectionFreshnessState(value.Freshness)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMSquadMember(value SCUMSquadMember) SCUMSquadMember {
|
||||
value.UnknownFields = CopyGameClientBridgePayload(value.UnknownFields)
|
||||
value.Freshness = CopySCUMProjectionFreshnessState(value.Freshness)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMVehicle(value SCUMVehicle) SCUMVehicle {
|
||||
value.Position = CopySCUMCurrentPosition(value.Position)
|
||||
value.UnknownFields = CopyGameClientBridgePayload(value.UnknownFields)
|
||||
value.Freshness = CopySCUMProjectionFreshnessState(value.Freshness)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMFlag(value SCUMFlag) SCUMFlag {
|
||||
value.Position = CopySCUMCurrentPosition(value.Position)
|
||||
value.UnknownFields = CopyGameClientBridgePayload(value.UnknownFields)
|
||||
value.Freshness = CopySCUMProjectionFreshnessState(value.Freshness)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMCurrentPosition(value SCUMCurrentPosition) SCUMCurrentPosition {
|
||||
value.Freshness = CopySCUMProjectionFreshnessState(value.Freshness)
|
||||
return value
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type SCUMObservationStatus string
|
||||
|
||||
const (
|
||||
SCUMObservationAccepted SCUMObservationStatus = "accepted"
|
||||
SCUMObservationStale SCUMObservationStatus = "stale"
|
||||
SCUMObservationFailed SCUMObservationStatus = "failed"
|
||||
)
|
||||
|
||||
type SCUMProjectionFreshness string
|
||||
|
||||
const (
|
||||
SCUMProjectionFresh SCUMProjectionFreshness = "fresh"
|
||||
SCUMProjectionStale SCUMProjectionFreshness = "stale"
|
||||
SCUMProjectionUnknown SCUMProjectionFreshness = "unknown"
|
||||
)
|
||||
|
||||
type SCUMWorkflowStatus string
|
||||
|
||||
const (
|
||||
SCUMWorkflowDraft SCUMWorkflowStatus = "draft"
|
||||
SCUMWorkflowQueued SCUMWorkflowStatus = "queued"
|
||||
SCUMWorkflowRunning SCUMWorkflowStatus = "running"
|
||||
SCUMWorkflowWaiting SCUMWorkflowStatus = "waiting"
|
||||
SCUMWorkflowBlocked SCUMWorkflowStatus = "blocked"
|
||||
SCUMWorkflowConfirming SCUMWorkflowStatus = "confirming"
|
||||
SCUMWorkflowConfirmed SCUMWorkflowStatus = "confirmed"
|
||||
SCUMWorkflowFailed SCUMWorkflowStatus = "failed"
|
||||
SCUMWorkflowUnknown SCUMWorkflowStatus = "unknown"
|
||||
SCUMWorkflowCancelled SCUMWorkflowStatus = "cancelled"
|
||||
)
|
||||
|
||||
type SCUMWorkflowStepStatus string
|
||||
|
||||
const (
|
||||
SCUMWorkflowStepQueued SCUMWorkflowStepStatus = "queued"
|
||||
SCUMWorkflowStepRunning SCUMWorkflowStepStatus = "running"
|
||||
SCUMWorkflowStepWaiting SCUMWorkflowStepStatus = "waiting"
|
||||
SCUMWorkflowStepBlocked SCUMWorkflowStepStatus = "blocked"
|
||||
SCUMWorkflowStepConfirming SCUMWorkflowStepStatus = "confirming"
|
||||
SCUMWorkflowStepConfirmed SCUMWorkflowStepStatus = "confirmed"
|
||||
SCUMWorkflowStepFailed SCUMWorkflowStepStatus = "failed"
|
||||
SCUMWorkflowStepUnknown SCUMWorkflowStepStatus = "unknown"
|
||||
SCUMWorkflowStepCancelled SCUMWorkflowStepStatus = "cancelled"
|
||||
)
|
||||
|
||||
type SCUMSafeSummary struct {
|
||||
Title string
|
||||
Message string
|
||||
Details map[string]string
|
||||
}
|
||||
|
||||
type SCUMDataObservation struct {
|
||||
ID string
|
||||
ServerInstanceID string
|
||||
PluginID string
|
||||
Source string
|
||||
QueryKey string
|
||||
SubjectType string
|
||||
SubjectID string
|
||||
Sequence uint64
|
||||
Checksum string
|
||||
Status SCUMObservationStatus
|
||||
ErrorCode string
|
||||
SafeSummary SCUMSafeSummary
|
||||
ObservedAt time.Time
|
||||
ReceivedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMObservationResult struct {
|
||||
ServerInstanceID string
|
||||
PluginID string
|
||||
Source string
|
||||
QueryKey string
|
||||
Sequence uint64
|
||||
Checksum string
|
||||
Status SCUMObservationStatus
|
||||
ErrorCode string
|
||||
SafeSummary SCUMSafeSummary
|
||||
ObservedAt time.Time
|
||||
ReceivedAt time.Time
|
||||
Rows []map[string]any
|
||||
}
|
||||
|
||||
type SCUMProjectionFreshnessState struct {
|
||||
Status SCUMProjectionFreshness
|
||||
ObservationID string
|
||||
Source string
|
||||
QueryKey string
|
||||
Sequence uint64
|
||||
Checksum string
|
||||
StaleReason string
|
||||
ObservedAt time.Time
|
||||
ReceivedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMMutationGuard struct {
|
||||
FieldKey string
|
||||
Before any
|
||||
After any
|
||||
MaxRowsAffected int
|
||||
SafetyWindow string
|
||||
BackupRef string
|
||||
RequiresOfflinePlayer bool
|
||||
RequiresMaintenance bool
|
||||
RequiresBackup bool
|
||||
}
|
||||
|
||||
type SCUMOperationConfirmation struct {
|
||||
Status string
|
||||
ObservationID string
|
||||
ConfirmedFields map[string]any
|
||||
AffectedRows int
|
||||
MutationChecksum string
|
||||
Checksum string
|
||||
ObservedAt time.Time
|
||||
SafeSummary SCUMSafeSummary
|
||||
}
|
||||
|
||||
type SCUMOperationRequest struct {
|
||||
ID string
|
||||
ServerInstanceID string
|
||||
PluginID string
|
||||
TemplateKey string
|
||||
PlayerID string
|
||||
RequesterID string
|
||||
ApproverID string
|
||||
ApprovalLevel GameClientBridgeApprovalLevel
|
||||
Payload map[string]any
|
||||
Guard SCUMMutationGuard
|
||||
Confirmation SCUMOperationConfirmation
|
||||
Status SCUMWorkflowStepStatus
|
||||
Reason string
|
||||
IdempotencyKey string
|
||||
RunJobID string
|
||||
SafeSummary SCUMSafeSummary
|
||||
AuditReferences []string
|
||||
CreatedAt time.Time
|
||||
ApprovedAt time.Time
|
||||
CompletedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMOperationRequestFilter struct {
|
||||
ServerInstanceID string
|
||||
PluginID string
|
||||
TemplateKey string
|
||||
PlayerID string
|
||||
RequesterID string
|
||||
Status SCUMWorkflowStepStatus
|
||||
IdempotencyKey string
|
||||
Limit int
|
||||
}
|
||||
|
||||
type SCUMWorkflowInstanceFilter struct {
|
||||
ServerInstanceID string
|
||||
PluginID string
|
||||
TemplateKey string
|
||||
RequestedBy string
|
||||
Status SCUMWorkflowStatus
|
||||
IdempotencyKey string
|
||||
Limit int
|
||||
}
|
||||
|
||||
type SCUMWorkflowStepFilter struct {
|
||||
WorkflowID string
|
||||
ServerInstanceID string
|
||||
StepKey string
|
||||
Status SCUMWorkflowStepStatus
|
||||
MutatesState *bool
|
||||
Limit int
|
||||
}
|
||||
|
||||
type SCUMWorkflowInstance struct {
|
||||
ID string
|
||||
ServerInstanceID string
|
||||
PluginID string
|
||||
TemplateKey string
|
||||
RequestedBy string
|
||||
IdempotencyKey string
|
||||
Status SCUMWorkflowStatus
|
||||
CurrentStepKey string
|
||||
Input map[string]any
|
||||
SafeSummary SCUMSafeSummary
|
||||
BlockerReason string
|
||||
AuditReferences []string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
CompletedAt time.Time
|
||||
}
|
||||
|
||||
type SCUMWorkflowStep struct {
|
||||
ID string
|
||||
WorkflowID string
|
||||
ServerInstanceID string
|
||||
StepKey string
|
||||
DependsOn []string
|
||||
Status SCUMWorkflowStepStatus
|
||||
OperationKey string
|
||||
QueryTemplateKey string
|
||||
Capability string
|
||||
TargetKey string
|
||||
JobID string
|
||||
Attempt int
|
||||
MaxAttempts int
|
||||
MutatesState bool
|
||||
Confirmation SCUMOperationConfirmation
|
||||
SafeSummary SCUMSafeSummary
|
||||
BlockerReason string
|
||||
AuditReferences []string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
CompletedAt time.Time
|
||||
}
|
||||
|
||||
func CopySCUMSafeSummary(value SCUMSafeSummary) SCUMSafeSummary {
|
||||
value.Details = CopyStringMap(value.Details)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMDataObservation(value SCUMDataObservation) SCUMDataObservation {
|
||||
value.SafeSummary = CopySCUMSafeSummary(value.SafeSummary)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMObservationResult(value SCUMObservationResult) SCUMObservationResult {
|
||||
value.SafeSummary = CopySCUMSafeSummary(value.SafeSummary)
|
||||
value.Rows = CopyGameClientBridgeRows(value.Rows)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopyGameClientBridgeRows(values []map[string]any) []map[string]any {
|
||||
if values == nil {
|
||||
return nil
|
||||
}
|
||||
out := make([]map[string]any, len(values))
|
||||
for index, row := range values {
|
||||
out[index] = CopyGameClientBridgePayload(row)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func CopySCUMProjectionFreshnessState(value SCUMProjectionFreshnessState) SCUMProjectionFreshnessState {
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMMutationGuard(value SCUMMutationGuard) SCUMMutationGuard {
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMOperationConfirmation(value SCUMOperationConfirmation) SCUMOperationConfirmation {
|
||||
value.ConfirmedFields = CopyGameClientBridgePayload(value.ConfirmedFields)
|
||||
value.SafeSummary = CopySCUMSafeSummary(value.SafeSummary)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMOperationRequest(value SCUMOperationRequest) SCUMOperationRequest {
|
||||
value.Payload = CopyGameClientBridgePayload(value.Payload)
|
||||
value.Guard = CopySCUMMutationGuard(value.Guard)
|
||||
value.Confirmation = CopySCUMOperationConfirmation(value.Confirmation)
|
||||
value.SafeSummary = CopySCUMSafeSummary(value.SafeSummary)
|
||||
value.AuditReferences = CopyStringSlice(value.AuditReferences)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMWorkflowInstance(value SCUMWorkflowInstance) SCUMWorkflowInstance {
|
||||
value.Input = CopyGameClientBridgePayload(value.Input)
|
||||
value.SafeSummary = CopySCUMSafeSummary(value.SafeSummary)
|
||||
value.AuditReferences = CopyStringSlice(value.AuditReferences)
|
||||
return value
|
||||
}
|
||||
|
||||
func CopySCUMWorkflowStep(value SCUMWorkflowStep) SCUMWorkflowStep {
|
||||
value.DependsOn = CopyStringSlice(value.DependsOn)
|
||||
value.Confirmation = CopySCUMOperationConfirmation(value.Confirmation)
|
||||
value.SafeSummary = CopySCUMSafeSummary(value.SafeSummary)
|
||||
value.AuditReferences = CopyStringSlice(value.AuditReferences)
|
||||
return value
|
||||
}
|
||||
Reference in New Issue
Block a user