fix(restart): block Restart on removed workspaces to prevent resurrection (#306) #2394
Reference in New Issue
Block a user
Delete Branch "fix/restart-guard-removed-workspace"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The manual Restart handler reads workspace status but never validated it before flipping to 'provisioning'. A removed workspace could be resurrected via manual Restart because the sync UPDATE fires before the async runRestartCycle guard.
Add an early guard: if status == 'removed', return 404 (same as not-found). This prevents both the DB flip and the downstream provision cycle.
Regression test verifies 404 on removed workspace.
Closes :306 from Researcher cleanup audit.
SOP Checklist
The manual Restart handler reads workspace status at line 221-223 but never validated it before flipping to 'provisioning' at line 304-306. A removed workspace could be resurrected via manual Restart because: 1. The sync UPDATE at 306 fires before the async runRestartCycle guard 2. The async guard at 810-812 checks AND status NOT IN ('removed', ...) but by then status is already 'provisioning' Add an early guard after the initial SELECT: if status == 'removed', return 404 (same as not-found, preserving information-hiding). This prevents both the DB flip and the downstream provision cycle. Regression test verifies 404 on removed workspace. Closes :306 from Researcher cleanup audit.REQUEST_CHANGES on current head
99bcb9df. The intended removed-workspace guard is in the right location before the sync UPDATE to provisioning, and removed-only is sufficient for the validated resurrection vector because paused/hibernated are handled by separate lifecycle contracts while async restart already excludes them. Scope is workspace_restart.go plus test only.Blocker: Platform Go is red at build. The changed line compares
status(string) tomodels.StatusRemoved(models.WorkspaceStatus), producingworkspace_restart.go:235:15: invalid operation: status == models.StatusRemoved (mismatched types string and models.WorkspaceStatus). Fix the compile error and rerun Platform Go before approval.APPROVE on current head
4855ba40. Platform Go is green, including build and blocking tests; the previous type-mismatch compile error is resolved. The early removed-workspace guard now comparesstatus == string(models.StatusRemoved), returns 404 before the syncprovisioningUPDATE, and the regression test asserts the removed path stops there. Removed-only is sufficient for this validated resurrection vector because paused/hibernated have separate lifecycle handling while async restart excludes the broader terminal set. Scope is workspace_restart.go plus workspace_restart_test.go only; no gate/auth changes.APPROVED molecule-core#2394 @4855ba40. Fetched live current head
4855ba400aand verified the diff is scoped to workspace_restart.go plus its regression test. The early removed-status 404 guard runs before any restart/provisioning update, preserves normal restart flow for non-removed statuses, and TestRestartHandler_RemovedWorkspaceReturns404 covers the resurrection-prevention path. Platform Go and CI/all-required are green; aggregate red is from review/SOP gating, not this code path.Security pass: Restart now returns not-found for removed workspaces before any provisioning update. This prevents resurrection and avoids existence leakage; no auth/credential/gate weakening found. Posted as authorized SOP-ceremony security-review trigger.
QA pass: scoped Restart removed-workspace resurrection guard with regression test; workspace lifecycle/status integrity warrants SOP tier med. No QA blocker found.