Integrate SCUM real ops workflows

This commit is contained in:
npc0-hue
2026-08-10 21:12:53 +08:00
parent 1063330710
commit a770bc6250
88 changed files with 6375 additions and 2719 deletions
+38
View File
@@ -3,6 +3,7 @@ package dto
import (
"encoding/json"
"reflect"
"strings"
"testing"
"browser.local/platform/domain"
@@ -177,3 +178,40 @@ func TestGameClientBridgeQueryTemplateDeclarationRoundTripIsSafe(t *testing.T) {
}
}
}
func TestGameClientBridgeOperationTemplateDeclarationRoundTripIsSafe(t *testing.T) {
body := GameClientBridgeManifestBody{
OperationTemplates: []GameClientBridgeOperationTemplateDeclarationBody{{
Key: "player.attribute.855.set", Title: "Set player attribute 855", Permission: "server.game-client.maintenance", ApprovalLevel: "platform-admin", Kind: "sqlite-mutation", TransportKey: "scum-mutation-db", TargetKey: "scum-mutation-db",
PayloadSchemaRef: "schemas/bridge/operations/player-attribute-855-set.payload.schema.json", ResultSchemaRef: "schemas/bridge/operations/player-attribute-855-set.result.schema.json", ConfirmationSchemaRef: "schemas/bridge/operations/player-attribute-855-set.confirmation.schema.json", TimeoutSeconds: 120, MaxPayloadBytes: 4096, MaxRowsAffected: 1,
Safety: GameClientBridgeOperationSafetyBody{RequiresApproval: true, RequiresOfflinePlayer: true, RequiresBeforeValue: true, RequiresConfirmation: true, BackupRequired: true},
}},
CommandRetentionSeconds: 86400,
MaxCommands: 1000,
Pages: []GameClientBridgePageContractBody{{PageKey: "players", OperationKeys: []string{"player.attribute.855.set"}}},
}
domainManifest := body.ToDomain()
if len(domainManifest.OperationTemplates) != 1 || domainManifest.OperationTemplates[0].Kind != "sqlite-mutation" || domainManifest.OperationTemplates[0].MaxRowsAffected != 1 || !domainManifest.OperationTemplates[0].Safety.RequiresBeforeValue || domainManifest.Pages[0].OperationKeys[0] != "player.attribute.855.set" {
t.Fatalf("operation template conversion lost declaration fields: %#v", domainManifest)
}
domainManifest.Pages[0].OperationKeys[0] = "mutated"
if body.Pages[0].OperationKeys[0] != "player.attribute.855.set" {
t.Fatal("operation template page keys alias request DTO data")
}
domainManifest.Pages[0].OperationKeys[0] = "player.attribute.855.set"
response := gameClientBridgeManifestFromDomain(domainManifest)
response.Pages[0].OperationKeys[0] = "mutated"
if domainManifest.Pages[0].OperationKeys[0] != "player.attribute.855.set" {
t.Fatal("operation template page keys alias domain data")
}
encoded, err := json.Marshal(response.OperationTemplates[0])
if err != nil {
t.Fatalf("marshal safe operation template projection: %v", err)
}
if strings.Contains(strings.ToLower(string(encoded)), "sqltext") || strings.Contains(strings.ToLower(string(encoded)), "dsn") || strings.Contains(strings.ToLower(string(encoded)), "hostpath") || strings.Contains(strings.ToLower(string(encoded)), "socket") || strings.Contains(strings.ToLower(string(encoded)), "credential") {
t.Fatalf("operation template projection leaked unsafe material: %s", encoded)
}
}