better-notion 0.9.9__py3-none-any.whl → 1.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,371 @@
1
+ """Role-based access control (RBAC) for the agents workflow system.
2
+
3
+ This module provides role-based permission management for different agent types.
4
+ Each role has specific permissions that control what actions they can perform.
5
+ """
6
+
7
+ from typing import Dict, List, Literal, Optional
8
+
9
+
10
+ # Define valid roles
11
+ RoleType = Literal[
12
+ "Developer",
13
+ "PM",
14
+ "Product Analyst",
15
+ "QA",
16
+ "Designer",
17
+ "DevOps",
18
+ "Admin",
19
+ ]
20
+
21
+
22
+ # Define permission structure
23
+ # Format: resource:action (e.g., "tasks:claim", "projects:create")
24
+ PermissionType = str
25
+
26
+
27
+ class RoleManager:
28
+ """Manages role-based access control for agent operations.
29
+
30
+ The RoleManager defines permissions for each role and provides methods
31
+ to check if a role has a specific permission.
32
+
33
+ Roles:
34
+ - Developer: Can work on tasks, submit ideas, report issues
35
+ - PM: Can manage projects, tasks, review ideas, view analytics
36
+ - Product Analyst: Can view projects, analyze data, generate reports
37
+ - QA: Can review tasks, create incidents, report issues
38
+ - Designer: Can work on design tasks, submit ideas
39
+ - DevOps: Can manage deployments, infrastructure tasks
40
+ - Admin: Full access to all resources and actions
41
+
42
+ Example:
43
+ >>> # Check if a role has a permission
44
+ >>> RoleManager.check_permission("Developer", "tasks:claim")
45
+ True
46
+
47
+ >>> # Require a permission (raises PermissionError if denied)
48
+ >>> RoleManager.require_permission("Developer", "projects:create")
49
+ PermissionError: Role 'Developer' does not have permission 'projects:create'
50
+
51
+ >>> # Get all permissions for a role
52
+ >>> perms = RoleManager.get_permissions("PM")
53
+ >>> print(perms)
54
+ ['tasks:*', 'projects:create', 'projects:update', ...]
55
+ """
56
+
57
+ # Define permissions for each role
58
+ PERMISSIONS: Dict[RoleType, List[PermissionType]] = {
59
+ "Developer": [
60
+ # Task operations
61
+ "tasks:claim",
62
+ "tasks:start",
63
+ "tasks:complete",
64
+ "tasks:list",
65
+ "tasks:view",
66
+ "tasks:comment",
67
+ # Idea operations
68
+ "ideas:submit",
69
+ "ideas:view",
70
+ # Issue operations
71
+ "issues:report",
72
+ "issues:view",
73
+ # Version operations
74
+ "versions:view",
75
+ # Basic project visibility
76
+ "projects:view",
77
+ ],
78
+ "PM": [
79
+ # Full task access
80
+ "tasks:*",
81
+ # Project management
82
+ "projects:create",
83
+ "projects:update",
84
+ "projects:delete",
85
+ "projects:view",
86
+ "projects:list",
87
+ # Version management
88
+ "versions:create",
89
+ "versions:update",
90
+ "versions:delete",
91
+ "versions:view",
92
+ "versions:list",
93
+ # Idea management
94
+ "ideas:*",
95
+ # Issue management
96
+ "issues:*",
97
+ # Analytics and reporting
98
+ "analytics:*",
99
+ "report:*",
100
+ # Organization visibility
101
+ "organizations:view",
102
+ "organizations:list",
103
+ ],
104
+ "Product Analyst": [
105
+ # Read-only project access
106
+ "projects:view",
107
+ "projects:list",
108
+ # Read-only task access
109
+ "tasks:view",
110
+ "tasks:list",
111
+ # Analytics and reporting
112
+ "analytics:view",
113
+ "analytics:cycle-time",
114
+ "analytics:completion-rate",
115
+ "report:view",
116
+ "report:generate",
117
+ # Version visibility
118
+ "versions:view",
119
+ "versions:list",
120
+ # Organization visibility
121
+ "organizations:view",
122
+ "organizations:list",
123
+ ],
124
+ "QA": [
125
+ # Task review
126
+ "tasks:view",
127
+ "tasks:list",
128
+ "tasks:review",
129
+ "tasks:comment",
130
+ # Incident management
131
+ "incidents:create",
132
+ "incidents:update",
133
+ "incidents:resolve",
134
+ "incidents:view",
135
+ "incidents:list",
136
+ # Issue reporting
137
+ "issues:report",
138
+ "issues:view",
139
+ "issues:resolve",
140
+ # Project visibility
141
+ "projects:view",
142
+ "projects:list",
143
+ # Version visibility
144
+ "versions:view",
145
+ "versions:list",
146
+ ],
147
+ "Designer": [
148
+ # Task operations
149
+ "tasks:claim",
150
+ "tasks:start",
151
+ "tasks:complete",
152
+ "tasks:list",
153
+ "tasks:view",
154
+ "tasks:comment",
155
+ # Design task management
156
+ "tasks:create:design",
157
+ # Idea operations
158
+ "ideas:submit",
159
+ "ideas:view",
160
+ # Issue operations
161
+ "issues:report",
162
+ "issues:view",
163
+ # Project visibility
164
+ "projects:view",
165
+ ],
166
+ "DevOps": [
167
+ # Task operations
168
+ "tasks:claim",
169
+ "tasks:start",
170
+ "tasks:complete",
171
+ "tasks:list",
172
+ "tasks:view",
173
+ "tasks:comment",
174
+ # Infrastructure task management
175
+ "tasks:create:infrastructure",
176
+ "tasks:create:deployment",
177
+ # Incident management
178
+ "incidents:*",
179
+ # Issue operations
180
+ "issues:report",
181
+ "issues:view",
182
+ "issues:resolve",
183
+ # Version management
184
+ "versions:create",
185
+ "versions:update",
186
+ "versions:view",
187
+ # Project visibility
188
+ "projects:view",
189
+ "projects:list",
190
+ ],
191
+ "Admin": [
192
+ # Full access to everything
193
+ "*",
194
+ ],
195
+ }
196
+
197
+ @classmethod
198
+ def check_permission(
199
+ cls,
200
+ role: str,
201
+ permission: str,
202
+ ) -> bool:
203
+ """Check if a role has a specific permission.
204
+
205
+ Args:
206
+ role: Role name (e.g., "Developer", "PM")
207
+ permission: Permission string (e.g., "tasks:claim")
208
+
209
+ Returns:
210
+ True if role has the permission, False otherwise
211
+
212
+ Example:
213
+ >>> RoleManager.check_permission("Developer", "tasks:claim")
214
+ True
215
+
216
+ >>> RoleManager.check_permission("Developer", "projects:create")
217
+ False
218
+ """
219
+ # Admin has all permissions
220
+ if role == "Admin":
221
+ return True
222
+
223
+ # Check if role exists
224
+ if role not in cls.PERMISSIONS:
225
+ return False
226
+
227
+ permissions = cls.PERMISSIONS[role]
228
+
229
+ # Check for wildcard permission
230
+ if "*" in permissions:
231
+ return True
232
+
233
+ # Check for exact match
234
+ if permission in permissions:
235
+ return True
236
+
237
+ # Check for resource wildcard (e.g., "tasks:*" matches "tasks:claim")
238
+ for perm in permissions:
239
+ if perm.endswith(":*"):
240
+ resource = perm[:-2] # Remove ":*"
241
+ if permission.startswith(resource + ":"):
242
+ return True
243
+
244
+ # Check for action-specific wildcard (e.g., "tasks:create:*")
245
+ # This would match "tasks:create:design" but not "tasks:update"
246
+ if ":" in permission:
247
+ perm_resource, perm_action = permission.split(":", 1)
248
+
249
+ for role_perm in permissions:
250
+ if ":" in role_perm:
251
+ role_resource, role_action = role_perm.split(":", 1)
252
+
253
+ # Match resource and action
254
+ if role_resource == perm_resource:
255
+ if role_action == "*" or role_action == perm_action:
256
+ return True
257
+
258
+ # Check for sub-action wildcard (e.g., "create:*")
259
+ if role_action.endswith(":*"):
260
+ action_prefix = role_action[:-2]
261
+ if perm_action.startswith(action_prefix):
262
+ return True
263
+
264
+ return False
265
+
266
+ @classmethod
267
+ def require_permission(
268
+ cls,
269
+ role: str,
270
+ permission: str,
271
+ ) -> None:
272
+ """Require a permission for a role, raising PermissionError if denied.
273
+
274
+ This is a convenience method that raises an exception instead of
275
+ returning a boolean, making it useful for guard clauses.
276
+
277
+ Args:
278
+ role: Role name (e.g., "Developer", "PM")
279
+ permission: Permission string (e.g., "tasks:claim")
280
+
281
+ Raises:
282
+ PermissionError: If role does not have the permission
283
+
284
+ Example:
285
+ >>> RoleManager.require_permission("Developer", "tasks:claim")
286
+ >>> # OK, no error
287
+
288
+ >>> RoleManager.require_permission("Developer", "projects:create")
289
+ PermissionError: Role 'Developer' does not have permission 'projects:create'
290
+ """
291
+ if not cls.check_permission(role, permission):
292
+ raise PermissionError(
293
+ f"Role '{role}' does not have permission '{permission}'"
294
+ )
295
+
296
+ @classmethod
297
+ def get_permissions(cls, role: str) -> List[str]:
298
+ """Get all permissions for a role.
299
+
300
+ Args:
301
+ role: Role name
302
+
303
+ Returns:
304
+ List of permission strings for the role
305
+
306
+ Example:
307
+ >>> perms = RoleManager.get_permissions("Developer")
308
+ >>> print(perms)
309
+ ['tasks:claim', 'tasks:start', 'tasks:complete', ...]
310
+ """
311
+ return cls.PERMISSIONS.get(role, [])
312
+
313
+ @classmethod
314
+ def get_all_roles(cls) -> List[str]:
315
+ """Get list of all defined roles.
316
+
317
+ Returns:
318
+ List of role names
319
+
320
+ Example:
321
+ >>> roles = RoleManager.get_all_roles()
322
+ >>> print(roles)
323
+ ['Developer', 'PM', 'Product Analyst', 'QA', 'Designer', 'DevOps', 'Admin']
324
+ """
325
+ return list(cls.PERMISSIONS.keys())
326
+
327
+ @classmethod
328
+ def is_valid_role(cls, role: str) -> bool:
329
+ """Check if a role name is valid.
330
+
331
+ Args:
332
+ role: Role name to validate
333
+
334
+ Returns:
335
+ True if role is defined, False otherwise
336
+
337
+ Example:
338
+ >>> RoleManager.is_valid_role("Developer")
339
+ True
340
+
341
+ >>> RoleManager.is_valid_role("InvalidRole")
342
+ False
343
+ """
344
+ return role in cls.PERMISSIONS
345
+
346
+ @classmethod
347
+ def get_role_description(cls, role: str) -> Optional[str]:
348
+ """Get a human-readable description for a role.
349
+
350
+ Args:
351
+ role: Role name
352
+
353
+ Returns:
354
+ Role description or None if role doesn't exist
355
+
356
+ Example:
357
+ >>> desc = RoleManager.get_role_description("Developer")
358
+ >>> print(desc)
359
+ 'Can work on tasks, submit ideas, report issues'
360
+ """
361
+ descriptions = {
362
+ "Developer": "Can work on tasks, submit ideas, report issues",
363
+ "PM": "Can manage projects, tasks, review ideas, view analytics",
364
+ "Product Analyst": "Can view projects, analyze data, generate reports",
365
+ "QA": "Can review tasks, create incidents, report issues",
366
+ "Designer": "Can work on design tasks, submit ideas",
367
+ "DevOps": "Can manage deployments, infrastructure tasks",
368
+ "Admin": "Full access to all resources and actions",
369
+ }
370
+
371
+ return descriptions.get(role)