package runtime import ( "context" "encoding/binary" "encoding/json" "fmt" "net" "os" "strings" "testing" "time" "browser.local/run/protocol" ) func TestExecuteSourceRCONAuthenticatesRunsAndRedacts(t *testing.T) { listener, port := newSourceRCONListener(t) defer listener.Close() password := strings.Repeat("a", 64) assignment := sourceRCONAssignment(port) root := t.TempDir() writeSourceRCONConfig(t, root, assignment, "127.0.0.1", password) commands := make(chan string, 1) serverDone := serveSourceRCONSession(listener, password, func(connection net.Conn, command sourceRCONPacket) error { commands <- command.body if err := writeSourceRCONPacket(context.Background(), connection, sourceRCONPacket{id: command.id, typeCode: sourceRCONResponseValue, body: "queued"}); err != nil { return err } return writeSourceRCONPacket(context.Background(), connection, sourceRCONPacket{id: command.id, typeCode: sourceRCONResponseValue}) }) command := "SetTime 12" result := NewLifecycleExecutor(WithLifecycleWorkspaceRoot(root), WithDLLExtensionRuntimeTarget("windows", "amd64")).ExecuteSourceRCON(context.Background(), assignment, command) if result.State != lifecycleResultStateSucceeded || result.ErrorCode != "" || result.ExecutionResult.Kind != "source-rcon" { t.Fatalf("expected successful Source RCON delivery, got %+v", result) } if got := <-commands; got != command { t.Fatalf("expected transient command delivery, got %q", got) } awaitSourceRCONServer(t, serverDone) serialized, err := json.Marshal(result) if err != nil { t.Fatalf("marshal result: %v", err) } for _, private := range []string{command, password, "queued"} { if strings.Contains(string(serialized), private) { t.Fatalf("Source RCON result exposed private wire data %q: %s", private, serialized) } } } func TestExecuteSourceRCONReadsConfigFromManagedNestedDeployment(t *testing.T) { listener, port := newSourceRCONListener(t) defer listener.Close() password := strings.Repeat("e", 64) assignment := sourceRCONAssignment(port) root := t.TempDir() writeSourceRCONConfigAt(t, root, assignment, "bin/"+assignment.ExecutionInput.SourceRCON.ConfigRef, "127.0.0.1", password) serverDone := serveSourceRCONSession(listener, password, func(connection net.Conn, command sourceRCONPacket) error { if command.body != "rcon.status" { return fmt.Errorf("unexpected nested deployment command %q", command.body) } return writeSourceRCONPacket(context.Background(), connection, sourceRCONPacket{id: command.id, typeCode: sourceRCONResponseValue}) }) result := NewLifecycleExecutor(WithLifecycleWorkspaceRoot(root), WithDLLExtensionRuntimeTarget("windows", "amd64")).ExecuteSourceRCON(context.Background(), assignment, "rcon.status") if result.State != lifecycleResultStateSucceeded { t.Fatalf("expected nested managed config delivery, got %+v", result) } awaitSourceRCONServer(t, serverDone) } func TestExecuteSourceRCONRedactsSourceErrorsAndMalformedPackets(t *testing.T) { password := strings.Repeat("b", 64) command := "SpawnItem secret-item" for _, testCase := range []struct { name string respond func(net.Conn, sourceRCONPacket) error wantCode string private string }{ { name: "source error response", respond: func(connection net.Conn, packet sourceRCONPacket) error { if err := writeSourceRCONPacket(context.Background(), connection, sourceRCONPacket{id: packet.id, typeCode: sourceRCONResponseValue, body: "err"}); err != nil { return err } if err := writeSourceRCONPacket(context.Background(), connection, sourceRCONPacket{id: packet.id, typeCode: sourceRCONResponseValue, body: "or: denied secret-item"}); err != nil { return err } return writeSourceRCONPacket(context.Background(), connection, sourceRCONPacket{id: packet.id, typeCode: sourceRCONResponseValue}) }, wantCode: "source_rcon_command_failed", private: "denied secret-item", }, { name: "malformed response packet", respond: func(connection net.Conn, _ sourceRCONPacket) error { var size [4]byte binary.LittleEndian.PutUint32(size[:], sourceRCONMaxPacketSize+1) _, err := connection.Write(size[:]) return err }, wantCode: "source_rcon_protocol_failed", private: "source response body", }, } { t.Run(testCase.name, func(t *testing.T) { listener, port := newSourceRCONListener(t) defer listener.Close() assignment := sourceRCONAssignment(port) root := t.TempDir() writeSourceRCONConfig(t, root, assignment, "127.0.0.1", password) serverDone := serveSourceRCONSession(listener, password, testCase.respond) result := NewLifecycleExecutor(WithLifecycleWorkspaceRoot(root), WithDLLExtensionRuntimeTarget("windows", "amd64")).ExecuteSourceRCON(context.Background(), assignment, command) if result.State != lifecycleResultStateFailed || result.ErrorCode != testCase.wantCode || result.Retryable { t.Fatalf("expected safe non-retryable %s failure, got %+v", testCase.wantCode, result) } awaitSourceRCONServer(t, serverDone) serialized, err := json.Marshal(result) if err != nil { t.Fatalf("marshal result: %v", err) } for _, private := range []string{command, password, testCase.private} { if strings.Contains(string(serialized), private) { t.Fatalf("Source RCON failure exposed private wire data %q: %s", private, serialized) } } }) } } func TestExecuteSourceRCONRejectsUnsafeConfigAndNonWindowsBeforeDial(t *testing.T) { listener, port := newSourceRCONListener(t) acceptResult := make(chan error, 1) go func() { connection, err := listener.Accept() if err == nil { _ = connection.Close() } acceptResult <- err }() password := strings.Repeat("c", 64) assignment := sourceRCONAssignment(port) root := t.TempDir() writeSourceRCONConfig(t, root, assignment, "0.0.0.0", password) result := NewLifecycleExecutor(WithLifecycleWorkspaceRoot(root), WithDLLExtensionRuntimeTarget("windows", "amd64")).ExecuteSourceRCON(context.Background(), assignment, "rcon.status") if result.ErrorCode != "source_rcon_config_invalid" { t.Fatalf("expected unsafe local config rejection, got %+v", result) } acceptReturned := false acceptedConnection := false select { case err := <-acceptResult: acceptReturned = true if err == nil { acceptedConnection = true } case <-time.After(150 * time.Millisecond): // No connection is expected before the listener is closed below. } if acceptedConnection { t.Fatal("unsafe config opened a socket") } if err := listener.Close(); err != nil { t.Fatalf("close listener: %v", err) } if !acceptReturned { if err := <-acceptResult; err == nil { t.Fatal("unsafe config opened a socket") } } linuxResult := NewLifecycleExecutor(WithLifecycleWorkspaceRoot(t.TempDir()), WithDLLExtensionRuntimeTarget("linux", "amd64")).ExecuteSourceRCON(context.Background(), assignment, "rcon.status") if linuxResult.ErrorCode != "unsupported_extension_platform" { t.Fatalf("expected non-Windows rejection, got %+v", linuxResult) } } func TestWorkerSourceRCONConsumesInputOnceWithoutJournalOrResultLeakage(t *testing.T) { listener, port := newSourceRCONListener(t) defer listener.Close() password := strings.Repeat("d", 64) command := "SendChat 4 \"maintenance complete\"" client := newFakeWorkerClient() assignment := workerJobAssignment(protocol.RunCapabilityRemoteRunRCONCommand) assignment.TargetKey = "rcon.password" assignment.InputRef = "input://source-rcon/job-worker" assignment.MaxAttempts = 1 assignment.ExecutionInput = protocol.RunJobExecutionInput{ WorkspaceScope: "run-local", RemoteAdapterKey: "rcon", RemoteAdapterKind: "rcon", TimeoutSeconds: 5, SourceRCON: &protocol.RuntimeSourceRCONPlan{Protocol: "source-rcon", ExtensionKey: "scum-simple-rcon", ModKey: "scum_simple_rcon", ConfigRef: "ue4ss/Mods/scum_simple_rcon/config.ini", DeploymentStateRef: "runtime/ue4ss-dll/ue4ss/scum-simple-rcon/release.json", Port: port}, } client.claimJob = assignment client.sourceRCONInput = protocol.SourceRCONExecutionInputResponse{JobID: assignment.JobID, ServerInstanceID: assignment.ServerInstanceID, RunEndpointID: assignment.RunEndpointID, Command: command} serverDone := serveSourceRCONSession(listener, password, func(connection net.Conn, packet sourceRCONPacket) error { if err := writeSourceRCONPacket(context.Background(), connection, sourceRCONPacket{id: packet.id, typeCode: sourceRCONResponseValue, body: "accepted"}); err != nil { return err } return writeSourceRCONPacket(context.Background(), connection, sourceRCONPacket{id: packet.id, typeCode: sourceRCONResponseValue}) }) config := workerTestConfig(t) writeSourceRCONConfig(t, config.WorkspaceRoot, assignment, "127.0.0.1", password) worker, err := NewWorker(config, client, WithDLLExtensionRuntimeTarget("windows", "amd64")) if err != nil { t.Fatalf("new worker: %v", err) } if err := worker.Register(context.Background()); err != nil { t.Fatalf("register worker: %v", err) } if handled, err := worker.ClaimAndRunOnce(context.Background()); err != nil || !handled { t.Fatalf("claim Source RCON job handled=%v err=%v", handled, err) } awaitSourceRCONServer(t, serverDone) if len(client.sourceRCONRequests) != 1 || client.sourceRCONRequests[0].JobID != assignment.JobID { t.Fatalf("expected one active-lease Source RCON input read, got %+v", client.sourceRCONRequests) } if len(client.resultRequests) != 1 || client.resultRequests[0].Retryable || client.resultRequests[0].State != lifecycleResultStateSucceeded { t.Fatalf("expected one non-retryable safe result, got %+v", client.resultRequests) } for _, projection := range []any{worker.journal.ActiveJobs(), client.resultRequests, client.sourceRCONRequests} { body, marshalErr := json.Marshal(projection) if marshalErr != nil { t.Fatalf("marshal safe projection: %v", marshalErr) } for _, private := range []string{command, password, "accepted"} { if strings.Contains(string(body), private) { t.Fatalf("journal or result projection exposed %q: %s", private, body) } } } } func newSourceRCONListener(t *testing.T) (net.Listener, int) { t.Helper() listener, err := net.Listen("tcp4", "127.0.0.1:0") if err != nil { t.Fatalf("listen Source RCON fixture: %v", err) } address, ok := listener.Addr().(*net.TCPAddr) if !ok || address.Port < 1024 { _ = listener.Close() t.Fatal("invalid Source RCON fixture address") } return listener, address.Port } func sourceRCONAssignment(port int) protocol.RunJobAssignment { assignment := lifecycleAssignment(protocol.RunCapabilityRemoteRunRCONCommand) assignment.TargetKey = "rcon.password" assignment.InputRef = "input://source-rcon/job-1" assignment.MaxAttempts = 1 assignment.ExecutionInput = protocol.RunJobExecutionInput{ WorkspaceScope: "run-local", RemoteAdapterKey: "rcon", RemoteAdapterKind: "rcon", TimeoutSeconds: 5, SourceRCON: &protocol.RuntimeSourceRCONPlan{Protocol: "source-rcon", ExtensionKey: "scum-simple-rcon", ModKey: "scum_simple_rcon", ConfigRef: "ue4ss/Mods/scum_simple_rcon/config.ini", DeploymentStateRef: "runtime/ue4ss-dll/ue4ss/scum-simple-rcon/release.json", Port: port}, } return assignment } func writeSourceRCONConfig(t *testing.T, root string, assignment protocol.RunJobAssignment, bindAddress string, password string) { writeSourceRCONConfigAt(t, root, assignment, assignment.ExecutionInput.SourceRCON.ConfigRef, bindAddress, password) } func writeSourceRCONConfigAt(t *testing.T, root string, assignment protocol.RunJobAssignment, configRef string, bindAddress string, password string) { t.Helper() resolver := NewWorkspaceResolver(root) scope, err := resolver.Scope(assignment.ServerInstanceID, assignment.ExecutionInput.WorkspaceScope) if err != nil { t.Fatalf("create Source RCON scope: %v", err) } path, _, err := resolver.WritableTarget(scope, configRef) if err != nil { t.Fatalf("resolve Source RCON config: %v", err) } body := fmt.Sprintf("%s\n[rcon]\nbind_address=%s\nport=%d\npassword=%s\n", managedRCONConfigMarker, bindAddress, assignment.ExecutionInput.SourceRCON.Port, password) if err := os.WriteFile(path, []byte(body), 0o600); err != nil { t.Fatalf("write Source RCON config: %v", err) } markerPath, _, err := resolver.WritableTarget(scope, assignment.ExecutionInput.SourceRCON.DeploymentStateRef) if err != nil { t.Fatalf("resolve Source RCON deployment marker: %v", err) } markerBody, err := json.Marshal(managedDLLExtensionMarker{Version: ue4ssExtensionMarkerVersion, ReleaseVersion: "1.0.0", Checksum: "sha256:" + strings.Repeat("a", 64), SizeBytes: 1, ExtensionKey: assignment.ExecutionInput.SourceRCON.ExtensionKey, ModKey: assignment.ExecutionInput.SourceRCON.ModKey, ConfigRef: configRef, RCONPort: assignment.ExecutionInput.SourceRCON.Port}) if err != nil { t.Fatalf("marshal Source RCON deployment marker: %v", err) } if err := os.WriteFile(markerPath, markerBody, 0o600); err != nil { t.Fatalf("write Source RCON deployment marker: %v", err) } } func serveSourceRCONSession(listener net.Listener, password string, respond func(net.Conn, sourceRCONPacket) error) <-chan error { done := make(chan error, 1) go func() { connection, err := listener.Accept() if err != nil { done <- err return } defer connection.Close() context, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() auth, err := readSourceRCONPacket(context, connection) if err != nil { done <- err return } if auth.id != sourceRCONAuthRequestID || auth.typeCode != sourceRCONAuthenticate || auth.body != password { done <- fmt.Errorf("unexpected auth packet") return } if err := writeSourceRCONPacket(context, connection, sourceRCONPacket{id: auth.id, typeCode: sourceRCONAuthResponse}); err != nil { done <- err return } command, err := readSourceRCONPacket(context, connection) if err != nil { done <- err return } if command.id != sourceRCONCommandRequestID || command.typeCode != sourceRCONExecuteCommand { done <- fmt.Errorf("unexpected command packet") return } done <- respond(connection, command) }() return done } func awaitSourceRCONServer(t *testing.T, done <-chan error) { t.Helper() select { case err := <-done: if err != nil { t.Fatalf("Source RCON fixture: %v", err) } case <-time.After(2 * time.Second): t.Fatal("Source RCON fixture did not finish") } }