also looking at this
fix(dashboard): confirm destructive actions that ran on first click
#130Closes #123.
Four destructive dashboard actions executed on the first click. All now stage a typed confirmation, using the pattern already established by firewall/secrets/alarms.
Removals
- team —
RemovefiredDELETE /api/usersimmediately, pulling someone's access to every site on the box. - ssh-keys —
RemovefiredDELETE /api/ssh-keysimmediately. Removing the wrong key can lock every operator out of the box.
Both now require typing the username / key name. Neither endpoint enforces a confirm server-side, so the UI was the only guard and there wasn't one.
Command runners
This one is worth reading closely. The API already required a typed confirmation — /api/server/command answers Type "run" to execute this command on the server. (local-dashboard-server.ts:1042), and /api/serverless/command does the same. But the UI never implemented that step and sent confirm: 'run' in the body itself, so the gate was satisfied unconditionally and Enter in the box ran arbitrary shell on the production server (or an arbitrary app command — migrate:fresh, queue:flush — against production).
Note server/actions.stx states "Mutating commands require typed confirmation" directly above the runner that bypassed it.
The operator now types the word, and the client sends what they actually typed rather than asserting the confirmation on their behalf. The confirm bar echoes the exact command so you can see what you're about to run.
The token stays run because that's the contract the server enforces today; making it the resource name needs a coordinated server change and is tracked in #124.
Also
aria-labels on the repeated row buttons (they previously announced as a bare "Remove, Remove, Remove") and on the confirm inputs, which only had a placeholder — a small slice of #128 that was free to do here.
Testing
Lint clean (pickier). Verified no signal-name collisions with the pending/typed/canRun trio these pages already bind to the shared op-confirm partial, and that no hardcoded confirm: 'run' remains outside a comment. I could not render the pages locally — packages/ui pins @stacksjs/stx@^0.2.73, which isn't installed in this checkout, and the global stx binary is a newer version that rejects --pages. Worth a click-through before merge.
4 changed files on the files tab, with 0 review threads.