Remove SCUM server-management client path
This commit is contained in:
@@ -1215,6 +1215,9 @@ func (svc *CoreService) executeBridgeRemoteAccessRequest(sessionID string, base
|
||||
inputs[strings.TrimPrefix(key, "input.")] = value
|
||||
}
|
||||
}
|
||||
if capability == domain.JobCapabilityRemoteRunRCONCommand && strings.TrimSpace(inputs["command"]) != "" {
|
||||
return svc.executeBridgeSourceRCONCommand(sessionID, base, payload, inputs)
|
||||
}
|
||||
if capability == domain.JobCapabilityRemoteRunDBSQLiteQuery {
|
||||
templateKey := strings.TrimSpace(inputs["templateKey"])
|
||||
if templateKey == "" {
|
||||
@@ -1274,6 +1277,32 @@ func (svc *CoreService) executeBridgeRemoteAccessRequest(sessionID string, base
|
||||
return base
|
||||
}
|
||||
|
||||
func (svc *CoreService) executeBridgeSourceRCONCommand(sessionID string, base domain.PluginBridgeExecuteResponse, payload map[string]string, inputs map[string]string) domain.PluginBridgeExecuteResponse {
|
||||
dispatch, err := svc.DispatchSourceRCONCommandForSession(sessionID, domain.SourceRCONCommandRequest{
|
||||
ServerInstanceID: base.ServerInstanceID,
|
||||
Kind: domain.SourceRCONCommandKindCommand,
|
||||
Command: inputs["command"],
|
||||
IdempotencyKey: defaultBridgeValue(payload["idempotencyKey"], base.RequestID),
|
||||
})
|
||||
if err != nil {
|
||||
return bridgeExecutionError(base, err)
|
||||
}
|
||||
targetKey := strings.TrimSpace(payload["targetKey"])
|
||||
if job, getErr := svc.store.Jobs().Get(dispatch.JobID); getErr == nil && strings.TrimSpace(job.TargetKey) != "" {
|
||||
targetKey = job.TargetKey
|
||||
}
|
||||
base.Status = "queued"
|
||||
base.Result = map[string]string{
|
||||
"jobId": dispatch.JobID,
|
||||
"state": dispatch.Status,
|
||||
"capability": domain.JobCapabilityRemoteRunRCONCommand,
|
||||
"targetKey": targetKey,
|
||||
"serverInstanceId": dispatch.ServerInstanceID,
|
||||
"adapterKind": string(domain.RemoteAdapterRCON),
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
func findBridgeQueryTemplate(plugin domain.GamePlugin, routeKey string, templateKey string) (domain.GameClientBridgeQueryTemplateDeclaration, string) {
|
||||
pageFound := false
|
||||
pageAllowsTemplate := false
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"browser.local/platform/repo"
|
||||
)
|
||||
|
||||
func TestSourceRCONDispatchUsesOneTimeRedactedInput(t *testing.T) {
|
||||
func TestSourceRCONDispatchUsesOneTimeOpaqueInput(t *testing.T) {
|
||||
svc, session, runSession, instance := newSourceRCONFixture(t)
|
||||
request := domain.SourceRCONCommandRequest{ServerInstanceID: instance.ID, Kind: domain.SourceRCONCommandKindChat, ChatType: 4, Message: `Bounty "claimed"`, TargetSteamID: "76561198000000001", IdempotencyKey: "rcon-chat-1"}
|
||||
dispatch, err := svc.DispatchSourceRCONCommandForSession(session, request)
|
||||
@@ -150,14 +150,70 @@ func TestSourceRCONDispatchSelectsDeclaredProfileWithoutManualBinding(t *testing
|
||||
}
|
||||
}
|
||||
|
||||
func TestSourceRCONDispatchFallsBackFromCustomClientBinding(t *testing.T) {
|
||||
func TestBridgeRemoteAccessDispatchesDeclaredSourceRCONCommand(t *testing.T) {
|
||||
svc, session, runSession, instance := newSourceRCONFixture(t)
|
||||
plugin, err := svc.store.GamePlugins().Get(instance.PluginID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plugin.BridgeActions = []string{string(domain.PluginBridgeActionRemoteAccessRequest)}
|
||||
plugin.Pages = []domain.GamePluginPage{{Key: "remote", Title: "Remote", Path: "/remote", Permissions: []string{"server.remote.access"}, BridgeActions: []string{string(domain.PluginBridgeActionRemoteAccessRequest)}}}
|
||||
if err := svc.store.GamePlugins().Update(plugin); err != nil {
|
||||
t.Fatalf("update bridge-capable RCON plugin: %v", err)
|
||||
}
|
||||
|
||||
response, err := svc.ExecutePluginBridgeAction(session, domain.PluginBridgeExecuteRequest{
|
||||
RequestID: "bridge-rcon-1",
|
||||
PluginID: plugin.ID,
|
||||
RouteKey: "remote",
|
||||
ServerInstanceID: instance.ID,
|
||||
Action: domain.PluginBridgeActionRemoteAccessRequest,
|
||||
Payload: map[string]string{
|
||||
"capability": domain.JobCapabilityRemoteRunRCONCommand,
|
||||
"declarationKey": "rcon",
|
||||
"targetKey": "rcon",
|
||||
"idempotencyKey": "bridge-rcon-1",
|
||||
"input.command": "#ListPlayers",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("execute bridge RCON command: %v", err)
|
||||
}
|
||||
if response.Status != "queued" || response.Result["adapterKind"] != string(domain.RemoteAdapterRCON) || response.Result["targetKey"] != "rcon" || response.Result["capability"] != domain.JobCapabilityRemoteRunRCONCommand {
|
||||
t.Fatalf("expected queued source RCON bridge response, got %+v", response)
|
||||
}
|
||||
job, err := svc.store.Jobs().Get(response.Result["jobId"])
|
||||
if err != nil {
|
||||
t.Fatalf("get bridge RCON job: %v", err)
|
||||
}
|
||||
if job.ExecutionInput.SourceRCON == nil || !strings.HasPrefix(job.InputRef, "input://source-rcon/") || len(job.ExecutionInput.Inputs) != 0 {
|
||||
t.Fatalf("expected source RCON one-time input job, got %+v", job)
|
||||
}
|
||||
claim, err := svc.ClaimRunJob(domain.RunJobClaim{RunEndpointID: "run-local", SessionToken: runSession, Capabilities: []string{domain.JobCapabilityRemoteRunRCONCommand}, Capacity: domain.RunCapacity{MaxJobs: 1}})
|
||||
if err != nil || !claim.HasJob || claim.Job == nil || claim.Job.JobID != job.ID {
|
||||
t.Fatalf("claim bridge RCON job: claim=%+v err=%v", claim, err)
|
||||
}
|
||||
ack, err := svc.AckRunJob(domain.RunJobAck{RunEndpointID: "run-local", SessionToken: runSession, JobID: claim.Job.JobID, LeaseToken: claim.Job.LeaseToken, Attempt: claim.Job.Attempt, Message: "accepted"})
|
||||
if err != nil || !ack.Accepted {
|
||||
t.Fatalf("ack bridge RCON job: ack=%+v err=%v", ack, err)
|
||||
}
|
||||
input, err := svc.GetSourceRCONExecutionInput(domain.SourceRCONExecutionInputRequest{RunEndpointID: "run-local", SessionToken: runSession, JobID: job.ID, LeaseToken: ack.Job.LeaseToken, Attempt: ack.Job.Attempt})
|
||||
if err != nil {
|
||||
t.Fatalf("consume bridge RCON input: %v", err)
|
||||
}
|
||||
if input.Command != "#ListPlayers" {
|
||||
t.Fatalf("expected bridge RCON command to remain verbatim, got %q", input.Command)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSourceRCONDispatchFallsBackFromIncompatibleLegacyBinding(t *testing.T) {
|
||||
svc, session, _, instance := newSourceRCONFixture(t)
|
||||
plugin, err := svc.store.GamePlugins().Get(instance.PluginID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plugin.RuntimeProfiles.LifecycleProfiles[0].Key = "run-local"
|
||||
plugin.RuntimeProfiles.LifecycleProfiles = append(plugin.RuntimeProfiles.LifecycleProfiles, domain.RuntimeLifecycleProfile{Key: "scum-client", Mode: "custom-client", Capabilities: []string{"client-manager.deploy", "client-manager.control", "logs.read"}, ClientManagerRef: "scum-client-manager", Platforms: []string{"windows"}})
|
||||
plugin.RuntimeProfiles.LifecycleProfiles = append(plugin.RuntimeProfiles.LifecycleProfiles, domain.RuntimeLifecycleProfile{Key: "legacy-local", Mode: "local-process", Capabilities: []string{"logs.read"}, Platforms: []string{"windows"}})
|
||||
if err := svc.store.GamePlugins().Update(plugin); err != nil {
|
||||
t.Fatalf("update plugin profiles: %v", err)
|
||||
}
|
||||
@@ -165,23 +221,23 @@ func TestSourceRCONDispatchFallsBackFromCustomClientBinding(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("get runtime binding: %v", err)
|
||||
}
|
||||
binding.ProfileKey = "scum-client"
|
||||
binding.Mode = "custom-client"
|
||||
binding.Bindings = map[string]string{"scum-client-manager": "runtime-client-manager"}
|
||||
binding.ProfileKey = "legacy-local"
|
||||
binding.Mode = "local-process"
|
||||
binding.Bindings = map[string]string{"logs": "runtime-logs"}
|
||||
if err := svc.store.RuntimeBindings().Update(binding); err != nil {
|
||||
t.Fatalf("point binding at custom client profile: %v", err)
|
||||
t.Fatalf("point binding at incompatible profile: %v", err)
|
||||
}
|
||||
|
||||
dispatch, err := svc.DispatchSourceRCONCommandForSession(session, domain.SourceRCONCommandRequest{ServerInstanceID: instance.ID, Kind: domain.SourceRCONCommandKindCommand, Command: "#ListPlayers", IdempotencyKey: "rcon-custom-client-binding"})
|
||||
dispatch, err := svc.DispatchSourceRCONCommandForSession(session, domain.SourceRCONCommandRequest{ServerInstanceID: instance.ID, Kind: domain.SourceRCONCommandKindCommand, Command: "#ListPlayers", IdempotencyKey: "rcon-incompatible-binding"})
|
||||
if err != nil {
|
||||
t.Fatalf("dispatch RCON with custom-client binding fallback: %v", err)
|
||||
t.Fatalf("dispatch RCON with incompatible binding fallback: %v", err)
|
||||
}
|
||||
job, err := svc.store.Jobs().Get(dispatch.JobID)
|
||||
if err != nil {
|
||||
t.Fatalf("get RCON job: %v", err)
|
||||
}
|
||||
if job.ExecutionInput.WorkspaceScope != "run-local" || job.TargetKey != "rcon" || job.ExecutionInput.RemoteAdapterKey != "rcon" {
|
||||
t.Fatalf("expected source RCON to use run-local despite custom-client binding, got %+v", job)
|
||||
t.Fatalf("expected source RCON to use run-local despite incompatible binding, got %+v", job)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user