Enforce the shared-machine lock on the server
Security surface (node authz). Run the autonomous security review lane before merge.
(a) Reproduction/evidence: 6412 (PR #5515) widened the UI lock in `apps/web/src/pages/NodeDetailPage.tsx` to `(operator_allocated || jaah_cloud || shared_machine) && !isOperator`. 6412's security review recorded LOW-1, deferred: "the UI shows the lock but the API still accepts a tenant's machine-setting change."
(b) Cause: `apps/api/app/node_allocation.py:62-66` `locked_for` returns `operator_allocated or jaah_cloud`. It never consults `placement(...).shared_machine`, so `refuse(...)` and `routes/nodes.py:1037` let a tenant change settings on a vnode carried by a self-hosted operator shared host.
(c) Fix: make `locked_for` also return true when `placement(session, [row.id])[row.id].shared_machine` (the same seam `NodeOut.shared_machine` uses, `routes/nodes.py:966`). Keep the operator bypass. Add no new column or flag.
(d) Acceptance:
- An API test: a tenant admin PATCHing a machine setting on a shared-machine node gets 403. The operator gets 200. A tenant's own self-hosted node is unchanged (200).
- A Jaah Cloud node still answers as today.
- The security lane verdict is in the PR body.
(e) Out of scope: the banner/badge copy, Delete/Re-enrol visibility (a separate UI decision), and placement semantics.
Done means: the tests above pass; `./dc check full` green; PR merged to develop; Jaah Deploy succeeded.
Outcome
locked_for now also locks shared-machine nodes for tenants (403; operator 200). Full gate green, security lane PASS, PR #5540 merged, Jaah Deploy success. Deferred: NodeVault reset ignores the lock; delete and CP-launched main_vpc lock are open questions.
Artifacts
Activity
- Ready
- Runner started
- Runner ended (done)