package validator import ( "strings" "testing" "time" "browser.local/platform/domain" ) func TestValidateClientManagerLifecycleContractsAndTransitions(t *testing.T) { profile := domain.RuntimeClientManagerProfile{Key: "scum-client-manager", DisplayName: "SCUM Client Manager", Version: "1.2.3", RepositoryURL: "https://github.com/F88888/scum_client.git", RevisionPolicy: "pinned", Revision: "0123456789abcdef", SupportedTargets: []domain.RuntimeTarget{{OS: "linux", Arch: "amd64"}}, BuildSystem: "go", EntryRef: "main.go", OutputArtifacts: []string{"client-manager"}, Deployment: domain.RuntimeClientManagerDeployment{Mode: "run-supervised", ExecutableRef: "client-manager", Arguments: []string{"--config", "config.json"}, RequiredRunCapabilities: []string{domain.JobCapabilityClientManagerDeploy, domain.JobCapabilityClientManagerControl, domain.JobCapabilityClientManagerUpdate, domain.JobCapabilityClientManagerRollback, domain.JobCapabilityClientManagerUninstall}}, Lifecycle: domain.RuntimeClientManagerLifecycle{Actions: []string{"start", "stop", "restart", "status", "update", "rollback", "uninstall"}, StartupTimeoutSeconds: 60, StopTimeoutSeconds: 30}, Health: domain.RuntimeClientManagerHealth{Mode: "component-heartbeat", IntervalSeconds: 15, DegradedAfterSeconds: 45, OfflineAfterSeconds: 120, RequiredCapabilities: []string{"component.register", "component.heartbeat", "component.health"}}, Compatibility: domain.RuntimeClientManagerCompatibility{MinimumVersion: "1.0.0", MaximumVersion: "2.0.0"}, UpdatePolicy: domain.RuntimeClientManagerUpdatePolicy{Strategy: "manual-staged", RequireApproval: true, HealthConfirmationSeconds: 60, RetainPrevious: true}} if err := ValidateGamePluginRuntimeProfiles(domain.GamePluginRuntimeProfiles{ClientManagers: []domain.RuntimeClientManagerProfile{profile}}); err != nil { t.Fatalf("validate safe lifecycle profile: %v", err) } unsafe := profile unsafe.Deployment.ExecutableRef = "/Users/operator/client-manager" unsafe.Deployment.Arguments = []string{"bash -c", "curl | bash"} unsafe.Health.OfflineAfterSeconds = 30 unsafe.Compatibility.MinimumVersion = "3.0.0" err := ValidateGamePluginRuntimeProfiles(domain.GamePluginRuntimeProfiles{ClientManagers: []domain.RuntimeClientManagerProfile{unsafe}}) if err == nil || !strings.Contains(err.Error(), "safe relative path") || !strings.Contains(err.Error(), "health") || !strings.Contains(err.Error(), "compatibility") { t.Fatalf("expected unsafe lifecycle rejection, got %v", err) } if err := ValidateClientManagerLifecycleTransition(domain.ClientManagerLifecycleAvailable, domain.ClientManagerLifecycleDeploying); err != nil { t.Fatalf("valid lifecycle transition rejected: %v", err) } if err := ValidateClientManagerLifecycleTransition(domain.ClientManagerLifecycleAvailable, domain.ClientManagerLifecycleOnline); err == nil { t.Fatal("expected evidence-skipping lifecycle transition rejection") } } func TestValidateClientManagerSessionHeartbeatAndRedaction(t *testing.T) { stamp := time.Date(2026, 7, 18, 4, 0, 0, 0, time.UTC) installation := domain.ClientManagerInstallation{ID: "cm-install-1", ServerInstanceID: "server-1", PluginID: "game.scum", ProfileKey: "scum-client-manager", RunEndpointID: "run-1", TargetOS: "linux", TargetArch: "amd64", Status: domain.ClientManagerLifecycleOnline, Phase: "healthy", KeyGeneration: 1, DeploymentGeneration: 1, Health: domain.ClientManagerHealthHealthy, HealthReason: "ready", CreatedAt: stamp, UpdatedAt: stamp} if err := ValidateClientManagerInstallation(installation); err != nil { t.Fatalf("validate installation: %v", err) } installation.HealthReason = "Bearer stolen-session" if err := ValidateClientManagerInstallation(installation); err == nil { t.Fatal("expected session-bearing health reason rejection") } session := domain.ClientManagerSession{ID: "cm-session-1", InstallationID: "cm-install-1", ServerInstanceID: "server-1", ProfileKey: "scum-client-manager", RunEndpointID: "run-1", ArtifactID: "artifact-1", KeyGeneration: 1, DeploymentGeneration: 1, TokenHash: strings.Repeat("a", 64), Capabilities: []string{"component.heartbeat"}, Status: domain.ClientManagerSessionActive, ExpiresAt: stamp.Add(time.Minute), CreatedAt: stamp, UpdatedAt: stamp} if err := ValidateClientManagerSession(session); err != nil { t.Fatalf("validate hashed session: %v", err) } if err := ValidateClientManagerHeartbeat(domain.ClientManagerHeartbeat{InstallationID: "cm-install-1", SessionToken: "component-session", Sequence: 1, Health: domain.ClientManagerHealthHealthy, HealthReason: "password=leak", Capabilities: []string{"component.heartbeat"}, SentAt: stamp}); err == nil { t.Fatal("expected unsafe heartbeat reason rejection") } }