Add runtime policy overrides and TUI policy management view

- server/policy_overrides.mjs: persistent group/action override store
- Group toggle: disabling a group forces all its actions to auto-deny without
  touching individual overrides; re-enabling restores them intact
- Action overrides: cycle auto-accept/queue/auto-deny/clear per action
- Effective policy resolution in index.mjs: group > action override > hardcoded default
- auth.mjs: add check_can_manage_policies (requires canApprove.length > 0)
- Three new endpoints: GET /policies, POST /policies/group/:group, POST /policies/action/:action
- client/conduit.mjs: get_policies, set_group_policy, set_action_policy
- ccc-queue.mjs: policy view (Tab to switch); group/action panel with space/e/←/→
- actions.mjs: group fields on desktop/email/calendar actions; list-actions includes group
- config.example.json: add policy_overrides key
- Bump version to 1.3.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 16:01:45 +00:00
parent 25891ece7e
commit dd7743501a
14 changed files with 609 additions and 102 deletions

View File

@@ -39,5 +39,33 @@ export function create_conduit_client(username, secret, base_url = process.env.C
return res.json();
}
return { call_action, list_actions, get_queue, resolve_queue_item };
async function get_policies() {
const res = await fetch(`${base_url}/policies`, {
headers: auth_headers(''),
});
return res.json();
}
async function set_group_policy(group, disabled) {
const body_string = JSON.stringify({ disabled });
const res = await fetch(`${base_url}/policies/group/${encodeURIComponent(group)}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...auth_headers(body_string) },
body: body_string,
});
return res.json();
}
// policy = null clears the override
async function set_action_policy(action, policy) {
const body_string = JSON.stringify({ policy });
const res = await fetch(`${base_url}/policies/action/${encodeURIComponent(action)}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', ...auth_headers(body_string) },
body: body_string,
});
return res.json();
}
return { call_action, list_actions, get_queue, resolve_queue_item, get_policies, set_group_policy, set_action_policy };
}