feat(webui): sanctioned restart and graceful reload controls (Closes #642)
Adds a gated `system.restart_namespace` action so operators and workers can restart or gracefully reload MCP namespaces through an authorized, audited path instead of manual host process killing (#630). - webui/sanctioned_restart.py: restart/reload operation model, dry-run intent preview, confirmation-string enforcement, audit emission, and post-restart health verification. Fails closed on unknown auth, missing capability, or ambiguous target namespace. - webui/console_authz.py: RBAC entries for the restart capability with secret redaction preserved. - webui/gated_actions.py: registers the restart action in the gated action framework so it cannot be invoked without capability + confirmation. - task_capability_map.py: capability mapping for the restart operation. - docs/sanctioned-restart-controls.md: operator documentation for the sanctioned path and the explicit prohibition on pkill recovery. - docs/webui-authz-audit.md: audit model updated for restart events. - tests/test_webui_sanctioned_restart.py: authorized preview, unauthorized deny, confirmation enforcement, contamination classification, and audit emission coverage. No unrestricted kill path is exposed; manual pkill remains classified as contamination and continues to block clean claims. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -91,6 +91,8 @@ already define, and a regression test asserts each mapping matches.
|
||||
| `close_pr` | controller | privileged | `gitea.pr.close` | Yes | No | No | 3 |
|
||||
| `merge_pr` | controller | privileged | `gitea.pr.merge` | Yes | **Yes** | **Yes** | 3 |
|
||||
| `delete_branch` | admin | destructive | `gitea.branch.delete` | Yes | **Yes** | **Yes** | 3 |
|
||||
| `system.reload_namespace` | controller | privileged | `runtime.reload_namespace` | Yes | No | No | 2 |
|
||||
| `system.restart_namespace` | admin | destructive | `runtime.restart_namespace` | Yes | **Yes** | **Yes** | 2 |
|
||||
|
||||
**Dual control** means the acting principal may not be the sole authority: a
|
||||
second distinct principal must confirm. **Break-glass** means the action is
|
||||
@@ -102,6 +104,13 @@ honouring it.
|
||||
`delete_branch` is admin-only rather than controller because it is the one
|
||||
irreversible action in the set.
|
||||
|
||||
`system.restart_namespace` is admin-only for the same reason: restarting a
|
||||
namespace drops every in-flight request on it. `system.reload_namespace` drains
|
||||
first, so it is privileged but not destructive. Neither action is ever executed
|
||||
by the console — both hand off to a host supervisor, and neither exposes a raw
|
||||
process kill. See
|
||||
[`sanctioned-restart-controls.md`](sanctioned-restart-controls.md) (#642).
|
||||
|
||||
### Authorization decision
|
||||
|
||||
`authorize(action_id, principal, for_execution=False)` returns a decision
|
||||
@@ -199,8 +208,8 @@ breaking the request it describes.
|
||||
| Class | Applies to | Default |
|
||||
|-------|-----------|---------|
|
||||
| `standard` | Routine gated writes | 90 days |
|
||||
| `privileged` | `review_pr`, `close_pr`, and any unclassifiable action | 365 days |
|
||||
| `break_glass` | `merge_pr`, `delete_branch` | 730 days |
|
||||
| `privileged` | `review_pr`, `close_pr`, `system.reload_namespace`, and any unclassifiable action | 365 days |
|
||||
| `break_glass` | `merge_pr`, `delete_branch`, `system.restart_namespace` | 730 days |
|
||||
|
||||
Each record carries its own class, day count, and computed `expires_at`, so
|
||||
retention is auditable per record rather than inferred from file age. An
|
||||
|
||||
Reference in New Issue
Block a user