Complete platform management workflows
This commit is contained in:
@@ -876,6 +876,105 @@ func TestCoreServiceAuthorizesPluginBridgeActions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoreServiceRemoteAccessRequiresPluginDeclaration(t *testing.T) {
|
||||
svc := newTestCoreService()
|
||||
registration := validPluginManifestRegistration()
|
||||
registration.Manifest.Capabilities = append(registration.Manifest.Capabilities,
|
||||
domain.JobCapabilityRemoteRunDBSQLiteQuery,
|
||||
domain.JobCapabilityRemoteRunLogsTransfer,
|
||||
domain.JobCapabilityRemoteRunRCONCommand,
|
||||
)
|
||||
registration.Manifest.Permissions = append(registration.Manifest.Permissions, "server.remote.access")
|
||||
registration.Manifest.Bridge.Actions = append(registration.Manifest.Bridge.Actions, string(domain.PluginBridgeActionRemoteAccessRequest))
|
||||
registration.Manifest.Pages = append(registration.Manifest.Pages, domain.GamePluginPage{
|
||||
Key: "remote",
|
||||
Title: "Remote",
|
||||
Path: "/remote",
|
||||
Permissions: []string{"server.remote.access"},
|
||||
BridgeActions: []string{string(domain.PluginBridgeActionRemoteAccessRequest)},
|
||||
})
|
||||
registration.Manifest.RemoteAccess = domain.GamePluginRemoteAccess{
|
||||
Methods: []string{"run"},
|
||||
RunCapabilities: []string{domain.JobCapabilityRemoteRunDBSQLiteQuery, domain.JobCapabilityRemoteRunLogsTransfer, domain.JobCapabilityRemoteRunRCONCommand},
|
||||
DatabaseEngines: []string{"sqlite"},
|
||||
RCON: true,
|
||||
LogTransfer: true,
|
||||
}
|
||||
plugin, err := svc.RegisterGamePluginManifest(registration)
|
||||
if err != nil {
|
||||
t.Fatalf("register remote manifest: %v", err)
|
||||
}
|
||||
if !plugin.Permissions.RemoteAccess || !plugin.RemoteAccess.RCON || plugin.RemoteAccess.DatabaseEngines[0] != "sqlite" {
|
||||
t.Fatalf("expected remote access metadata from manifest, got %+v", plugin)
|
||||
}
|
||||
marketplace, err := svc.GetMarketplacePlugin(plugin.ID)
|
||||
if err != nil || !marketplace.RemoteAccess.LogTransfer || marketplace.RemoteAccess.Methods[0] != "run" {
|
||||
t.Fatalf("expected marketplace remote access projection, got %+v err=%v", marketplace, err)
|
||||
}
|
||||
|
||||
endpoint, err := svc.CreateRunEndpoint(domain.RunEndpoint{
|
||||
ID: "run-remote",
|
||||
DisplayName: "Remote Run",
|
||||
Version: "0.1.0",
|
||||
Capabilities: append([]string{"process.install", "process.start", "process.stop", "logs.read", "files.read", "artifacts.read", "ai.invoke"}, plugin.RemoteAccess.RunCapabilities...),
|
||||
Capacity: domain.RunCapacity{MaxJobs: 2},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create remote endpoint: %v", err)
|
||||
}
|
||||
ownerSession := createServiceUserAndLogin(t, svc, domain.User{
|
||||
ID: "user-remote-owner",
|
||||
DisplayName: "Remote Owner",
|
||||
Email: "remote-owner@example.test",
|
||||
Roles: []string{"server-owner"},
|
||||
PasswordHash: "secret-password",
|
||||
})
|
||||
instance, err := svc.CreateServerInstanceForSession(ownerSession, domain.ServerInstance{
|
||||
ID: "server-remote",
|
||||
PluginID: plugin.ID,
|
||||
RunEndpointID: endpoint.ID,
|
||||
Name: "Remote Server",
|
||||
State: domain.ServerInstanceStateRunning,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create remote server: %v", err)
|
||||
}
|
||||
|
||||
queued, err := svc.ExecutePluginBridgeAction(ownerSession, domain.PluginBridgeExecuteRequest{
|
||||
RequestID: "remote-rcon-1",
|
||||
PluginID: plugin.ID,
|
||||
RouteKey: "remote",
|
||||
ServerInstanceID: instance.ID,
|
||||
Action: domain.PluginBridgeActionRemoteAccessRequest,
|
||||
Payload: map[string]string{
|
||||
"capability": domain.JobCapabilityRemoteRunRCONCommand,
|
||||
"targetKey": "rcon/command",
|
||||
"inputRef": "input://server-remote/rcon/command/1",
|
||||
"idempotencyKey": "idem-remote-rcon",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("execute remote bridge action: %v", err)
|
||||
}
|
||||
if queued.Status != "queued" || queued.Result["capability"] != domain.JobCapabilityRemoteRunRCONCommand {
|
||||
t.Fatalf("expected queued remote bridge job, got %+v", queued)
|
||||
}
|
||||
|
||||
plainPlugin, plainEndpoint := createPluginAndRunEndpoint(t, svc)
|
||||
plainEndpoint.Capabilities = append(plainEndpoint.Capabilities, domain.JobCapabilityRemoteRunRCONCommand)
|
||||
if err := svc.store.RunEndpoints().Update(plainEndpoint); err != nil {
|
||||
t.Fatalf("extend plain endpoint: %v", err)
|
||||
}
|
||||
plainInstance, err := svc.CreateServerInstance(domain.ServerInstance{ID: "server-plain", PluginID: plainPlugin.ID, RunEndpointID: plainEndpoint.ID, Name: "Plain Server"})
|
||||
if err != nil {
|
||||
t.Fatalf("create plain server: %v", err)
|
||||
}
|
||||
_, err = svc.CreateJob(domain.Job{ID: "job-remote-denied", ServerInstanceID: plainInstance.ID, RunEndpointID: plainEndpoint.ID, Capability: domain.JobCapabilityRemoteRunRCONCommand, TargetKey: "rcon/command", InputRef: "input://plain/rcon/command/1", IdempotencyKey: "idem-denied"})
|
||||
if err == nil || !strings.Contains(err.Error(), "plugin missing required capability") {
|
||||
t.Fatalf("expected undeclared remote job denial, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoreServiceRejectsDuplicateGamePluginManifest(t *testing.T) {
|
||||
svc := newTestCoreService()
|
||||
registration := validPluginManifestRegistration()
|
||||
@@ -1034,7 +1133,7 @@ func createPluginAndRunEndpoint(t *testing.T, svc *CoreService) (domain.GamePlug
|
||||
ServerType: "scum",
|
||||
ManifestRef: "artifact://manifests/server.scum/1.0.0",
|
||||
CreateFormSchemaRef: "artifact://schemas/server.scum/create-form/1.0.0",
|
||||
RequiredRunCapabilities: []string{"process.install", "process.start", "process.stop", "logs.read"},
|
||||
RequiredRunCapabilities: []string{"process.install", "process.start", "process.stop", "logs.read", "config.write", "files.read", "files.write"},
|
||||
DeclaredPermissions: []string{"server.files.read", "server.files.write"},
|
||||
LifecycleActions: domain.PluginLifecycleActions{
|
||||
Install: "actions/install.json",
|
||||
|
||||
Reference in New Issue
Block a user