Remove pre-1.0 bridge governance scaffolding
This commit is contained in:
@@ -434,7 +434,7 @@ func ValidatePluginCreateInputs(fields []domain.PluginCreateField, inputs map[st
|
||||
|
||||
func validateGameClientBridgeManifest(field string, bridge domain.GameClientBridgeManifest, permissions []string, pages []domain.GamePluginPage, runtimeProfiles domain.GamePluginRuntimeProfiles) []string {
|
||||
companionPresent := bridge.Companion != (domain.GameClientBridgeCompanionDeclaration{})
|
||||
if len(bridge.Commands) == 0 && len(bridge.Snapshots) == 0 && len(bridge.QueryTemplates) == 0 && len(bridge.LogProjections) == 0 && len(bridge.DataPacks) == 0 && len(bridge.OperationTemplates) == 0 && len(bridge.Pages) == 0 && len(bridge.Features) == 0 && bridge.Retention.KeepForSeconds == 0 && bridge.Retention.MaxRecords == 0 && !companionPresent {
|
||||
if len(bridge.Commands) == 0 && len(bridge.Snapshots) == 0 && len(bridge.QueryTemplates) == 0 && len(bridge.LogProjections) == 0 && len(bridge.DataPacks) == 0 && len(bridge.Pages) == 0 && len(bridge.Features) == 0 && bridge.Retention.KeepForSeconds == 0 && bridge.Retention.MaxRecords == 0 && !companionPresent {
|
||||
return nil
|
||||
}
|
||||
var violations []string
|
||||
@@ -513,9 +513,6 @@ func validateGameClientBridgeManifest(field string, bridge domain.GameClientBrid
|
||||
if !containsString(permissions, command.Permission) {
|
||||
violations = append(violations, prefix+".permission must be declared by the plugin")
|
||||
}
|
||||
if command.ApprovalLevel != domain.GameClientBridgeApprovalLevelNone && command.ApprovalLevel != domain.GameClientBridgeApprovalLevelOperator && command.ApprovalLevel != domain.GameClientBridgeApprovalLevelPlatformAdmin {
|
||||
violations = append(violations, prefix+".approvalLevel is invalid")
|
||||
}
|
||||
if !safeRelativeJSONRef(command.PayloadSchemaRef) || command.ResultSchemaRef != "" && !safeRelativeJSONRef(command.ResultSchemaRef) {
|
||||
violations = append(violations, prefix+" schema references must be safe relative JSON references")
|
||||
}
|
||||
@@ -647,72 +644,6 @@ func validateGameClientBridgeManifest(field string, bridge domain.GameClientBrid
|
||||
}
|
||||
}
|
||||
}
|
||||
operationTemplates := map[string]domain.GameClientBridgeOperationTemplateDeclaration{}
|
||||
for index, template := range bridge.OperationTemplates {
|
||||
prefix := fmt.Sprintf("%s.operationTemplates[%d]", field, index)
|
||||
if !clientManagerIdentifierPattern.MatchString(template.Key) || unsafeGameClientBridgeCommandType(template.Key) {
|
||||
violations = append(violations, prefix+".key is invalid or unsafe")
|
||||
}
|
||||
if _, exists := operationTemplates[template.Key]; exists {
|
||||
violations = append(violations, prefix+".key is duplicated")
|
||||
}
|
||||
operationTemplates[template.Key] = template
|
||||
if strings.TrimSpace(template.Title) == "" || len([]rune(template.Title)) > 80 {
|
||||
violations = append(violations, prefix+".title is invalid")
|
||||
}
|
||||
if !containsString(permissions, template.Permission) {
|
||||
violations = append(violations, prefix+".permission must be declared by the plugin")
|
||||
}
|
||||
if template.ApprovalLevel != domain.GameClientBridgeApprovalLevelNone && template.ApprovalLevel != domain.GameClientBridgeApprovalLevelOperator && template.ApprovalLevel != domain.GameClientBridgeApprovalLevelPlatformAdmin {
|
||||
violations = append(violations, prefix+".approvalLevel is invalid")
|
||||
}
|
||||
if template.Kind != domain.GameClientBridgeOperationKindRCON && template.Kind != domain.GameClientBridgeOperationKindSQLiteMutation {
|
||||
violations = append(violations, prefix+".kind is invalid")
|
||||
}
|
||||
if !safeRelativeJSONRef(template.PayloadSchemaRef) || template.ResultSchemaRef != "" && !safeRelativeJSONRef(template.ResultSchemaRef) || template.ConfirmationSchemaRef != "" && !safeRelativeJSONRef(template.ConfirmationSchemaRef) {
|
||||
violations = append(violations, prefix+" schema references must be safe relative JSON references")
|
||||
}
|
||||
if template.TimeoutSeconds < 1 || template.TimeoutSeconds > 3600 {
|
||||
violations = append(violations, prefix+".timeoutSeconds is invalid")
|
||||
}
|
||||
if template.MaxPayloadBytes < 1 || template.MaxPayloadBytes > maxGameClientBridgePayloadSize {
|
||||
violations = append(violations, prefix+".maxPayloadBytes is invalid")
|
||||
}
|
||||
transport, exists := transports[template.TransportKey]
|
||||
if !exists {
|
||||
violations = append(violations, prefix+".transportKey must reference a declared runtime transport profile")
|
||||
continue
|
||||
}
|
||||
if transport.TargetKey != template.TargetKey || strings.TrimSpace(template.TargetKey) == "" {
|
||||
violations = append(violations, prefix+".targetKey must match the declared runtime transport profile")
|
||||
}
|
||||
switch template.Kind {
|
||||
case domain.GameClientBridgeOperationKindRCON:
|
||||
if transport.Kind != "rcon" || !containsString(transport.Capabilities, domain.JobCapabilityRemoteRunRCONCommand) {
|
||||
violations = append(violations, prefix+" transport must be rcon with remote.run.rcon.command capability")
|
||||
}
|
||||
if template.MaxRowsAffected != 0 {
|
||||
violations = append(violations, prefix+".maxRowsAffected is only valid for sqlite-mutation")
|
||||
}
|
||||
if !emptyGameClientBridgeOperationMutation(template.Mutation) {
|
||||
violations = append(violations, prefix+".mutation is only valid for sqlite-mutation")
|
||||
}
|
||||
case domain.GameClientBridgeOperationKindSQLiteMutation:
|
||||
if transport.Kind != "sqlite" || !containsString(transport.Capabilities, domain.JobCapabilityRemoteRunProtectedSQL) {
|
||||
violations = append(violations, prefix+" transport must be sqlite with remote.run.protected.sql capability")
|
||||
}
|
||||
if template.ApprovalLevel != domain.GameClientBridgeApprovalLevelPlatformAdmin {
|
||||
violations = append(violations, prefix+".approvalLevel must require platform-admin approval for sqlite-mutation")
|
||||
}
|
||||
if template.MaxRowsAffected < 1 || template.MaxRowsAffected > 10 {
|
||||
violations = append(violations, prefix+".maxRowsAffected is invalid")
|
||||
}
|
||||
if !template.Safety.RequiresBeforeValue || !template.Safety.RequiresConfirmation || (!template.Safety.RequiresOfflinePlayer && !template.Safety.RequiresMaintenanceWindow) {
|
||||
violations = append(violations, prefix+".safety must require before value, confirmation, and offline or maintenance protection")
|
||||
}
|
||||
violations = append(violations, validateGameClientBridgeOperationMutation(prefix+".mutation", template.Mutation, queryTemplates)...)
|
||||
}
|
||||
}
|
||||
pageDeclarations := map[string]domain.GamePluginPage{}
|
||||
for _, page := range pages {
|
||||
pageDeclarations[page.Key] = page
|
||||
@@ -797,16 +728,6 @@ func validateGameClientBridgeManifest(field string, bridge domain.GameClientBrid
|
||||
violations = append(violations, prefix+" must declare remote.access.request for query templates")
|
||||
}
|
||||
}
|
||||
for _, operationKey := range page.OperationKeys {
|
||||
operation, exists := operationTemplates[operationKey]
|
||||
if !exists {
|
||||
violations = append(violations, prefix+" references undeclared operation template "+operationKey)
|
||||
continue
|
||||
}
|
||||
if !containsString(pageDeclaration.Permissions, operation.Permission) {
|
||||
violations = append(violations, prefix+" must declare operation template permission "+operation.Permission)
|
||||
}
|
||||
}
|
||||
for _, featureKey := range page.FeatureKeys {
|
||||
feature, exists := features[featureKey]
|
||||
if !exists {
|
||||
@@ -994,31 +915,6 @@ func unsafeGameClientBridgeCommandType(value string) bool {
|
||||
return has("shell", "powershell", "script", "terminal", "execute", "exec", "eval") || has("command", "cmd", "process", "system", "os", "executor") && has("run")
|
||||
}
|
||||
|
||||
func emptyGameClientBridgeOperationMutation(value domain.GameClientBridgeOperationMutationDeclaration) bool {
|
||||
return value.FieldKey == "" && value.TableKey == "" && value.IdentityKey == "" && value.ValueKey == "" && value.ConfirmationQueryKey == "" && value.AllowedValueType == "" && value.MinValue == 0 && value.MaxValue == 0
|
||||
}
|
||||
|
||||
func validateGameClientBridgeOperationMutation(prefix string, value domain.GameClientBridgeOperationMutationDeclaration, queryTemplates map[string]domain.GameClientBridgeQueryTemplateDeclaration) []string {
|
||||
var violations []string
|
||||
for field, item := range map[string]string{"fieldKey": value.FieldKey, "tableKey": value.TableKey, "identityKey": value.IdentityKey, "valueKey": value.ValueKey, "confirmationQueryKey": value.ConfirmationQueryKey} {
|
||||
if !validDistributionLogicalKey(item) || unsafeGameClientBridgePayloadKey(item) {
|
||||
violations = append(violations, prefix+"."+field+" must be a safe logical key")
|
||||
}
|
||||
}
|
||||
if !oneOf(value.AllowedValueType, "integer", "number", "string", "boolean") {
|
||||
violations = append(violations, prefix+".allowedValueType is invalid")
|
||||
}
|
||||
if value.MaxValue != 0 && value.MinValue > value.MaxValue {
|
||||
violations = append(violations, prefix+".minValue must not exceed maxValue")
|
||||
}
|
||||
if value.ConfirmationQueryKey != "" {
|
||||
if _, exists := queryTemplates[value.ConfirmationQueryKey]; !exists {
|
||||
violations = append(violations, prefix+".confirmationQueryKey must reference a declared query template")
|
||||
}
|
||||
}
|
||||
return violations
|
||||
}
|
||||
|
||||
func ValidatePluginBridgeAuthorizeRequest(request domain.PluginBridgeAuthorizeRequest) error {
|
||||
var violations []string
|
||||
violations = appendRequired(violations, "pluginId", request.PluginID)
|
||||
@@ -2078,7 +1974,6 @@ func pluginSafeStrings(plugin domain.GamePlugin) []fieldString {
|
||||
values = appendStringSliceFields(values, "tags", plugin.Tags)
|
||||
values = appendStringSliceFields(values, "aiPurposes", plugin.AIPurposes)
|
||||
values = appendStringSliceFields(values, "productionLifecycle.operations", plugin.ProductionLifecycle.Operations)
|
||||
values = appendStringSliceFields(values, "productionLifecycle.approvalRequired", plugin.ProductionLifecycle.ApprovalRequired)
|
||||
values = append(values, fieldString{field: "productionLifecycle.dependencyPolicy", value: plugin.ProductionLifecycle.DependencyPolicy})
|
||||
values = appendStringSliceFields(values, "bridgeActions", plugin.BridgeActions)
|
||||
values = appendStringSliceFields(values, "remoteAccess.methods", plugin.RemoteAccess.Methods)
|
||||
@@ -2125,7 +2020,6 @@ func manifestSafeStrings(registration domain.GamePluginManifestRegistration) []f
|
||||
values = appendStringSliceFields(values, "ai.purposes", manifest.AI.Purposes)
|
||||
values = append(values, fieldString{field: "ai.mediation", value: manifest.AI.Mediation}, fieldString{field: "ai.configWritePolicy", value: manifest.AI.ConfigWritePolicy}, fieldString{field: "productionLifecycle.dependencyPolicy", value: manifest.ProductionLifecycle.DependencyPolicy})
|
||||
values = appendStringSliceFields(values, "productionLifecycle.operations", manifest.ProductionLifecycle.Operations)
|
||||
values = appendStringSliceFields(values, "productionLifecycle.approvalRequired", manifest.ProductionLifecycle.ApprovalRequired)
|
||||
values = appendStringSliceFields(values, "remoteAccess.methods", manifest.RemoteAccess.Methods)
|
||||
values = appendStringSliceFields(values, "remoteAccess.runCapabilities", manifest.RemoteAccess.RunCapabilities)
|
||||
values = appendStringSliceFields(values, "remoteAccess.databaseEngines", manifest.RemoteAccess.DatabaseEngines)
|
||||
@@ -2339,7 +2233,7 @@ func validPluginRunCapability(capability string) bool {
|
||||
domain.JobCapabilityRemoteRunProcessStart, domain.JobCapabilityRemoteRunProcessStop,
|
||||
domain.JobCapabilityRemoteRunDBMySQLQuery, domain.JobCapabilityRemoteRunDBSQLiteQuery,
|
||||
domain.JobCapabilityRemoteRunLogsTransfer, domain.JobCapabilityRemoteRunRCONCommand,
|
||||
domain.JobCapabilityRemoteRunProtectedSQL, domain.JobCapabilityRemoteRunProgram,
|
||||
domain.JobCapabilityRemoteRunProgram,
|
||||
domain.JobCapabilityRunSelfUpdate, domain.JobCapabilityDependenciesCheck, domain.JobCapabilityDependenciesInstall,
|
||||
domain.JobCapabilityDeploymentPlan, domain.JobCapabilityDeploymentShellPosix, domain.JobCapabilityDeploymentShellPowerShell, domain.JobCapabilityDeploymentShellCmd,
|
||||
domain.JobCapabilityClientManagerDeploy, domain.JobCapabilityClientManagerControl, domain.JobCapabilityClientManagerUpdate,
|
||||
@@ -2372,7 +2266,7 @@ func remoteCapabilityRequiresInputRef(capability string) bool {
|
||||
domain.JobCapabilityRemoteRunFilesWrite,
|
||||
domain.JobCapabilityRemoteRunDBMySQLQuery,
|
||||
domain.JobCapabilityRemoteRunDBSQLiteQuery,
|
||||
domain.JobCapabilityRemoteRunRCONCommand, domain.JobCapabilityRemoteRunProtectedSQL, domain.JobCapabilityRemoteRunProgram:
|
||||
domain.JobCapabilityRemoteRunRCONCommand, domain.JobCapabilityRemoteRunProgram:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@@ -2516,16 +2410,6 @@ func validateProductionLifecycle(field string, lifecycle domain.GamePluginProduc
|
||||
if lifecycle.DependencyPolicy != "required" && lifecycle.DependencyPolicy != "optional" {
|
||||
violations = append(violations, field+".dependencyPolicy must be required or optional")
|
||||
}
|
||||
for i, operation := range lifecycle.ApprovalRequired {
|
||||
if operation != string(domain.PluginLifecycleOperationDisable) && operation != string(domain.PluginLifecycleOperationRollback) && operation != string(domain.PluginLifecycleOperationRetire) {
|
||||
violations = append(violations, fmt.Sprintf("%s.approvalRequired[%d] is invalid", field, i))
|
||||
}
|
||||
}
|
||||
for _, operation := range []string{string(domain.PluginLifecycleOperationDisable), string(domain.PluginLifecycleOperationRollback), string(domain.PluginLifecycleOperationRetire)} {
|
||||
if containsString(lifecycle.Operations, operation) && !containsString(lifecycle.ApprovalRequired, operation) {
|
||||
violations = append(violations, field+".approvalRequired must include "+operation)
|
||||
}
|
||||
}
|
||||
return violations
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user