Remove manual runtime controls from server detail

This commit is contained in:
npc0-hue
2026-08-10 12:23:17 +08:00
parent b789925ae5
commit fbd24b6a44
24 changed files with 272 additions and 1361 deletions
+4 -2
View File
@@ -542,8 +542,10 @@ func (svc *CoreService) PushRunUpdateForSession(sessionID string, request domain
if err := svc.validateDistributionPluginPermission(user.ID, plugin, instance.ID, "server.run.distribution", "run.update.denied"); err != nil {
return domain.RunUpdateJob{}, err
}
if err := svc.requireCompleteRuntimeBindings(user.ID, instance.ID, "run.update.denied"); err != nil {
return domain.RunUpdateJob{}, err
if deploymentNeedsCompleteRuntimeBinding(plugin, instance.Deployment) {
if err := svc.requireCompleteRuntimeBindings(user.ID, instance.ID, "run.update.denied"); err != nil {
return domain.RunUpdateJob{}, err
}
}
artifact, err := svc.GetArtifactForSession(sessionID, request.ArtifactID)
if err != nil {
+9 -6
View File
@@ -61,16 +61,18 @@ func TestRuntimeBindingValidationAndLifecycleGating(t *testing.T) {
if err := svc.store.RuntimeBindings().Create(domain.RuntimeBinding{ID: "runtime-binding-" + forged.ID, ServerInstanceID: forged.ID, PluginID: plugin.ID, PluginVersion: plugin.Version, ProfileKey: "local", Mode: "local-process", Bindings: map[string]string{}, Status: domain.RuntimeBindingStatusComplete, CreatedAt: fixedTime, UpdatedAt: fixedTime}); err != nil {
t.Fatalf("store forged complete binding: %v", err)
}
if _, err := svc.StartServerInstanceForSession(ownerSession, domain.ServerLifecycleCommand{ServerInstanceID: forged.ID, ExpectedConfigVersion: forged.ConfigVersion, IdempotencyKey: "start-forged-complete"}); err == nil || !strings.Contains(err.Error(), "rcon.password") {
t.Fatalf("expected derived missing keys to override stored complete status, got %v", err)
forgedView, err := svc.GetServerRuntimeBindingForSession(ownerSession, forged.ID)
if err != nil || forgedView.Status != domain.RuntimeBindingStatusIncomplete || len(forgedView.MissingKeys) != 2 || !containsString(forgedView.MissingKeys, "server-root") || !containsString(forgedView.MissingKeys, "rcon.password") {
t.Fatalf("expected derived missing keys to override stored complete status in the readiness view, view=%+v err=%v", forgedView, err)
}
view, err := svc.GetServerRuntimeBindingForSession(ownerSession, instance.ID)
if err != nil || view.Configured || view.Reason != "runtime profile is not configured" {
t.Fatalf("unexpected unconfigured view: view=%+v err=%v", view, err)
}
if _, err := svc.StartServerInstanceForSession(ownerSession, domain.ServerLifecycleCommand{ServerInstanceID: instance.ID, ExpectedConfigVersion: instance.ConfigVersion, IdempotencyKey: "start-without-binding"}); err == nil || !strings.Contains(err.Error(), "runtime profile is not configured") {
t.Fatalf("expected missing binding to block start, got %v", err)
withoutBinding, err := svc.StartServerInstanceForSession(ownerSession, domain.ServerLifecycleCommand{ServerInstanceID: instance.ID, ExpectedConfigVersion: instance.ConfigVersion, IdempotencyKey: "start-without-binding"})
if err != nil || withoutBinding.Job.TargetKey != "actions/start.json" || withoutBinding.Job.ExecutionInput.WorkspaceScope != "" {
t.Fatalf("expected plugin lifecycle start without manual runtime binding, result=%+v err=%v", withoutBinding, err)
}
if _, err := svc.UpdateServerRuntimeBindingForSession(otherSession, instance.ID, domain.RuntimeBindingUpdate{ProfileKey: "local"}); err != ErrForbidden {
t.Fatalf("expected non-owner update forbidden, got %v", err)
@@ -86,8 +88,9 @@ func TestRuntimeBindingValidationAndLifecycleGating(t *testing.T) {
if err != nil || view.Status != domain.RuntimeBindingStatusIncomplete || len(view.MissingKeys) != 1 || view.MissingKeys[0] != "rcon.password" {
t.Fatalf("unexpected incomplete binding: view=%+v err=%v", view, err)
}
if _, err := svc.StartServerInstanceForSession(ownerSession, domain.ServerLifecycleCommand{ServerInstanceID: instance.ID, ExpectedConfigVersion: instance.ConfigVersion, IdempotencyKey: "start-incomplete-binding"}); err == nil || !strings.Contains(err.Error(), "rcon.password") {
t.Fatalf("expected missing logical key to block start, got %v", err)
incompleteStart, err := svc.StartServerInstanceForSession(ownerSession, domain.ServerLifecycleCommand{ServerInstanceID: instance.ID, ExpectedConfigVersion: instance.ConfigVersion, IdempotencyKey: "start-incomplete-binding"})
if err != nil || incompleteStart.Job.TargetKey != "actions/start.json" || incompleteStart.Job.ExecutionInput.WorkspaceScope != "local" {
t.Fatalf("expected plugin lifecycle start to tolerate incomplete optional bindings, result=%+v err=%v", incompleteStart, err)
}
view, err = svc.UpdateServerRuntimeBindingForSession(ownerSession, instance.ID, domain.RuntimeBindingUpdate{ProfileKey: "local", Bindings: map[string]string{"rcon.password": "secret://runtime-server/rcon"}})
-5
View File
@@ -252,11 +252,6 @@ func (svc *CoreService) dispatchExistingServerLifecycle(command domain.ServerLif
}
}
}
if deploymentNeedsCompleteRuntimeBinding(plugin, instance.Deployment) {
if err := svc.requireCompleteRuntimeBindings(instance.OwnerUserID, instance.ID, "server.lifecycle."+string(action)+".denied"); err != nil {
return domain.ServerLifecycleResult{}, err
}
}
if err := svc.validateRunnableEndpoint(endpoint, domain.LifecycleCapabilityForAction(action)); err != nil {
return domain.ServerLifecycleResult{}, err
}