package validator import ( "strings" "testing" "browser.local/platform/domain" ) func validGameClientBridgeCompanionManifest() (domain.GameClientBridgeManifest, domain.GamePluginRuntimeProfiles) { bridge := domain.GameClientBridgeManifest{ Retention: domain.GameClientBridgeRetention{KeepForSeconds: 86400, MaxRecords: 1000}, Companion: domain.GameClientBridgeCompanionDeclaration{ ProfileKey: "scum-client-manager", ConfigTemplateKey: "client-config", ConfigSchemaRef: "schemas/companion/config.schema.json", ConfigFormat: "yaml", PlatformBaseURLSource: "run-control", RegistrationProof: "hmac-sha256", ProofMaterialSource: "component-package", ProofMaterialEnv: "SCUM_COMPONENT_PROOF", SessionMode: "component-session", TLSPolicy: "verify-system-roots", HeartbeatIntervalSeconds: 30, CommandPollIntervalSeconds: 5, RequestTimeoutSeconds: 15, }, } profiles := domain.GamePluginRuntimeProfiles{ClientManagers: []domain.RuntimeClientManagerProfile{{ Key: "scum-client-manager", ConfigTemplates: []domain.RuntimeConfigTemplate{{Key: "client-config", TemplateRef: "config.yaml.example", OutputRef: "config.yaml"}}, Health: domain.RuntimeClientManagerHealth{IntervalSeconds: 30, RequiredCapabilities: []string{"component.register", "component.heartbeat", "component.health", "game-client.bridge"}}, }}} return bridge, profiles } func TestValidateGameClientBridgeCompanionDeclaration(t *testing.T) { bridge, profiles := validGameClientBridgeCompanionManifest() if violations := validateGameClientBridgeManifest("gameClientBridge", bridge, nil, nil, profiles); len(violations) != 0 { t.Fatalf("expected valid companion declaration, got %v", violations) } tests := []struct { name string expected string mutate func(*domain.GameClientBridgeManifest, *domain.GamePluginRuntimeProfiles) }{ {name: "undeclared profile", expected: "profileKey must reference", mutate: func(bridge *domain.GameClientBridgeManifest, _ *domain.GamePluginRuntimeProfiles) { bridge.Companion.ProfileKey = "missing" }}, {name: "undeclared template", expected: "configTemplateKey must reference", mutate: func(bridge *domain.GameClientBridgeManifest, _ *domain.GamePluginRuntimeProfiles) { bridge.Companion.ConfigTemplateKey = "missing" }}, {name: "unsafe schema", expected: "configSchemaRef", mutate: func(bridge *domain.GameClientBridgeManifest, _ *domain.GamePluginRuntimeProfiles) { bridge.Companion.ConfigSchemaRef = "/etc/config.json" }}, {name: "insecure tls", expected: "security policy", mutate: func(bridge *domain.GameClientBridgeManifest, _ *domain.GamePluginRuntimeProfiles) { bridge.Companion.TLSPolicy = "skip-verification" }}, {name: "heartbeat mismatch", expected: "must match", mutate: func(bridge *domain.GameClientBridgeManifest, _ *domain.GamePluginRuntimeProfiles) { bridge.Companion.HeartbeatIntervalSeconds = 31 }}, {name: "missing bridge capability", expected: "game-client.bridge", mutate: func(_ *domain.GameClientBridgeManifest, profiles *domain.GamePluginRuntimeProfiles) { profiles.ClientManagers[0].Health.RequiredCapabilities = []string{"component.register", "component.heartbeat", "component.health"} }}, {name: "partial declaration", expected: "profile or config template key", mutate: func(bridge *domain.GameClientBridgeManifest, _ *domain.GamePluginRuntimeProfiles) { bridge.Companion.ProfileKey = "" }}, {name: "reserved proof environment", expected: "proofMaterialEnv", mutate: func(bridge *domain.GameClientBridgeManifest, _ *domain.GamePluginRuntimeProfiles) { bridge.Companion.ProofMaterialEnv = "LD_PRELOAD" }}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { candidateBridge, candidateProfiles := validGameClientBridgeCompanionManifest() test.mutate(&candidateBridge, &candidateProfiles) violations := validateGameClientBridgeManifest("gameClientBridge", candidateBridge, nil, nil, candidateProfiles) if !strings.Contains(strings.Join(violations, "; "), test.expected) { t.Fatalf("expected %q violation, got %v", test.expected, violations) } }) } } func TestValidateClientManagerCompanionConfigInputFailsClosed(t *testing.T) { valid := domain.ClientManagerCompanionConfigInput{ SchemaVersion: domain.ClientManagerCompanionConfigSchemaVersion, ConfigTemplateKey: "client-config", ConfigTemplateRef: "config.yaml.example", ConfigOutputRef: "config.yaml", ConfigSchemaRef: "schemas/companion/config.schema.json", ConfigFormat: "yaml", PlatformBaseURLSource: "run-control", InstallationID: "installation-1", ServerInstanceID: "server-1", PluginID: "game.scum", ProfileKey: "scum-client-manager", ArtifactID: "artifact-1", Version: "1.0.0", SourceRevision: "revision-1", TargetOS: "windows", TargetArch: "amd64", KeyGeneration: 1, DeploymentGeneration: 2, Capabilities: []string{"component.register", "component.heartbeat", "component.health", "game-client.bridge"}, RegistrationProof: "hmac-sha256", ProofMaterialSource: "component-package", ProofMaterialEnv: "SCUM_COMPONENT_PROOF", SessionMode: "component-session", TLSPolicy: "verify-system-roots", HeartbeatIntervalSeconds: 30, CommandPollIntervalSeconds: 5, RequestTimeoutSeconds: 15, } if err := ValidateClientManagerCompanionConfigInput(valid); err != nil { t.Fatalf("expected valid companion input, got %v", err) } for name, mutate := range map[string]func(*domain.ClientManagerCompanionConfigInput){ "insecure tls": func(value *domain.ClientManagerCompanionConfigInput) { value.TLSPolicy = "skip-verification" }, "legacy session": func(value *domain.ClientManagerCompanionConfigInput) { value.SessionMode = "shared-token" }, "reserved env": func(value *domain.ClientManagerCompanionConfigInput) { value.ProofMaterialEnv = "PATH" }, "unsafe template": func(value *domain.ClientManagerCompanionConfigInput) { value.ConfigTemplateRef = "../config.yaml" }, } { t.Run(name, func(t *testing.T) { candidate := domain.CopyClientManagerCompanionConfigInput(valid) mutate(&candidate) if err := ValidateClientManagerCompanionConfigInput(candidate); err == nil { t.Fatalf("expected invalid companion input: %+v", candidate) } }) } }