|
1 | 1 | /** |
2 | | - * Access control + approval routing. |
| 2 | + * Approval routing helpers (temporary home). |
3 | 3 | * |
4 | | - * Privilege is user-level, not group-level. A user holds zero or more roles |
5 | | - * (owner | admin) via `user_roles`, and is optionally "known" in specific |
6 | | - * agent groups via `agent_group_members`. Admins are implicitly members of |
7 | | - * the groups they administer. |
| 4 | + * These functions pick an approver for a sensitive action and resolve the |
| 5 | + * DM messaging_group they should be delivered to. They're called only from |
| 6 | + * the approvals module. |
8 | 7 | * |
9 | | - * Sensitive actions trigger an approval flow, routed to the admin of the |
10 | | - * originating agent group; if none, the owner. Approval delivery lands in |
11 | | - * the approver's DM on (ideally) the same channel kind as the originating |
12 | | - * request. DM resolution (including cold DMs) is handled by ensureUserDm. |
| 8 | + * PR #5 moved the access-decision half of this file (canAccessAgentGroup + |
| 9 | + * AccessDecision) into src/modules/permissions/. The approver-picking half |
| 10 | + * stays here as a temporary shim — PR #7 relocates it into a new default |
| 11 | + * approvals-primitive module alongside the approvals re-tier. |
| 12 | + * |
| 13 | + * Tier note: this file lives in core but imports from the permissions |
| 14 | + * optional module. That's a deliberate temporary violation; see the module |
| 15 | + * contract + REFACTOR_PLAN open question #3. |
13 | 16 | */ |
14 | | -import { getAgentGroup } from './db/agent-groups.js'; |
15 | | -import { isMember } from './db/agent-group-members.js'; |
16 | 17 | import { |
17 | 18 | getAdminsOfAgentGroup, |
18 | 19 | getGlobalAdmins, |
19 | 20 | getOwners, |
20 | | - hasAdminPrivilege, |
21 | | - isAdminOfAgentGroup, |
22 | | - isGlobalAdmin, |
23 | | - isOwner, |
24 | | -} from './db/user-roles.js'; |
25 | | -import { getUser } from './db/users.js'; |
26 | | -import { ensureUserDm } from './user-dm.js'; |
| 21 | +} from './modules/permissions/db/user-roles.js'; |
| 22 | +import { ensureUserDm } from './modules/permissions/user-dm.js'; |
27 | 23 | import type { MessagingGroup } from './types.js'; |
28 | 24 |
|
29 | | -export type AccessDecision = |
30 | | - | { allowed: true; reason: 'owner' | 'global_admin' | 'admin_of_group' | 'member' } |
31 | | - | { allowed: false; reason: 'unknown_user' | 'not_member' }; |
32 | | - |
33 | | -/** Can this user interact with this agent group? */ |
34 | | -export function canAccessAgentGroup(userId: string, agentGroupId: string): AccessDecision { |
35 | | - if (!getUser(userId)) return { allowed: false, reason: 'unknown_user' }; |
36 | | - if (isOwner(userId)) return { allowed: true, reason: 'owner' }; |
37 | | - if (isGlobalAdmin(userId)) return { allowed: true, reason: 'global_admin' }; |
38 | | - if (isAdminOfAgentGroup(userId, agentGroupId)) return { allowed: true, reason: 'admin_of_group' }; |
39 | | - if (isMember(userId, agentGroupId)) return { allowed: true, reason: 'member' }; |
40 | | - return { allowed: false, reason: 'not_member' }; |
41 | | -} |
42 | | - |
43 | | -/** Can this user perform privileged (admin) operations on this agent group? */ |
44 | | -export function canAdminAgentGroup(userId: string, agentGroupId: string): boolean { |
45 | | - return hasAdminPrivilege(userId, agentGroupId); |
46 | | -} |
47 | | - |
48 | 25 | /** |
49 | 26 | * Ordered list of user IDs eligible to approve an action for the given agent |
50 | 27 | * group. Preference: admins @ that group → global admins → owners. |
51 | | - * |
52 | | - * The approver-picking policy is to try local admins first (they have direct |
53 | | - * context for the group), then fall back to global scope. |
54 | 28 | */ |
55 | 29 | export function pickApprover(agentGroupId: string | null): string[] { |
56 | 30 | const approvers: string[] = []; |
@@ -100,15 +74,6 @@ export async function pickApprovalDelivery( |
100 | 74 | return null; |
101 | 75 | } |
102 | 76 |
|
103 | | -/** |
104 | | - * Resolve the agent group id for a session's originating request. Used by |
105 | | - * approval routing so we know which scope to pick admins from. |
106 | | - */ |
107 | | -export function agentGroupIdForSession(sessionAgentGroupId: string | null): string | null { |
108 | | - if (!sessionAgentGroupId) return null; |
109 | | - return getAgentGroup(sessionAgentGroupId)?.id ?? null; |
110 | | -} |
111 | | - |
112 | 77 | function channelTypeOf(userId: string): string { |
113 | 78 | const idx = userId.indexOf(':'); |
114 | 79 | return idx < 0 ? '' : userId.slice(0, idx); |
|
0 commit comments