Add multi-action policy holds and exempt collect_now from policy
Adds PolicyActionHold so an admin can suspend specific actions on a computer without editing the policy itself, covering the break-glass case where a machine must be quiesced immediately. Holds cover multiple actions in one atomic submission rather than one row per action, so a partial failure cannot leave a half-applied hold. Duration is free-form with 0 meaning indefinite (migration 0006 makes expiresat nullable); the prior fixed ceiling was removed because an admin quiescing a misbehaving machine does not know in advance how long it needs, and a hold silently expiring is worse than one that must be cleared deliberately. The What This Does explainer reflects indefinite holds. collect_now exemption: refreshing status was denied on any endpoint with a non-empty effective policy even when the caller held the matching grant, because policy intersection silently removed the action. collect_now is a read-only status refresh with no side effects, so it now sits in POLICY_EXEMPT_ACTIONS alongside the other routine actions. Verified against a synthetic non-empty policy: operators can refresh status again while every write action stays gated.
This commit is contained in:
@@ -17,9 +17,13 @@
|
||||
v-for="opt in filteredCommands"
|
||||
:key="opt.action"
|
||||
class="action-option"
|
||||
:class="{ 'action-locked': opt.mayauthor === false }"
|
||||
@mousedown.prevent="selectCommand(opt)"
|
||||
>
|
||||
{{ opt.label || opt.action }}
|
||||
<span v-if="opt.mayauthor === false" class="action-lock-note">
|
||||
needs {{ opt.requiredpermission }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="action-option action-branch"
|
||||
@@ -171,6 +175,9 @@ function enterMonitorLevel() {
|
||||
}
|
||||
|
||||
function selectCommand(opt) {
|
||||
// The server refuses this action anyway; declining here turns a confusing 403
|
||||
// on save into an obvious "you cannot pick that" at the point of choosing.
|
||||
if (opt.mayauthor === false) return
|
||||
emit('update:modelValue', opt.action)
|
||||
open.value = false
|
||||
level.value = 'command'
|
||||
@@ -254,6 +261,8 @@ function cancelCreate() {
|
||||
}
|
||||
.action-option { padding: 8px 12px; cursor: pointer; color: var(--text); }
|
||||
.action-option:hover { background: var(--bg); }
|
||||
.action-locked { opacity: 0.55; cursor: not-allowed; }
|
||||
.action-lock-note { font-size: 0.75rem; color: var(--text-light); margin-left: 6px; }
|
||||
.action-branch { font-style: italic; }
|
||||
.action-create { font-weight: 600; color: var(--primary); }
|
||||
.action-divider { height: 1px; background: var(--border); margin: 2px 0; }
|
||||
|
||||
Reference in New Issue
Block a user