Skip to content

Commit c0360c7

Browse files
committed
refactor(rbac): rename SYSTEM_ROLE to PRESET_ROLE
1 parent fd2382b commit c0360c7

File tree

10 files changed

+217
-207
lines changed

10 files changed

+217
-207
lines changed

alembic/versions/4bb7e59026f3_drop_role_from_membership_and_.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""drop_role_from_membership_and_invitation_tables
22
33
Revision ID: 4bb7e59026f3
4-
Revises: 8b630b0a094e
4+
Revises: 55c5d2499eee
55
Create Date: 2026-01-29 14:55:11.408522
66
77
"""
@@ -15,7 +15,7 @@
1515

1616
# revision identifiers, used by Alembic.
1717
revision: str = "4bb7e59026f3"
18-
down_revision: str | None = "8b630b0a094e"
18+
down_revision: str | None = "55c5d2499eee"
1919
branch_labels: str | Sequence[str] | None = None
2020
depends_on: str | Sequence[str] | None = None
2121

tests/unit/api/test_api_workspaces.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from sqlalchemy.exc import IntegrityError
1111

1212
from tracecat.auth.types import Role
13-
from tracecat.authz.enums import WorkspaceRole
1413
from tracecat.authz.service import MembershipWithOrg
1514
from tracecat.db.models import Workspace
1615
from tracecat.logger import logger
@@ -175,7 +174,6 @@ async def test_get_workspace_success(
175174
mock_membership = AsyncMock()
176175
mock_membership.user_id = test_admin_role.user_id
177176
mock_membership.workspace_id = mock_workspace_data.id
178-
mock_membership.role = WorkspaceRole.ADMIN
179177
mock_membership_svc.get_membership.return_value = MembershipWithOrg(
180178
membership=mock_membership, org_id=mock_workspace_data.organization_id
181179
)

tests/unit/test_auth_middleware.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,6 @@ async def test_performance_improvement(mocker):
222222
# Mock membership
223223
mock_membership = MagicMock(spec=Membership)
224224
mock_membership.workspace_id = workspace_id
225-
mock_membership.role = WorkspaceRole.EDITOR
226225

227226
# Track timing for database calls
228227
db_delay_ms = 10 # Simulate 10ms database query
@@ -458,7 +457,6 @@ async def test_cache_size_limit():
458457
spec=Membership,
459458
user_id=user.id,
460459
workspace_id=uuid.uuid4(),
461-
role=WorkspaceRole.EDITOR,
462460
)
463461
for _ in range(1500)
464462
]
@@ -625,7 +623,6 @@ async def test_role_dependency_infers_org_from_single_membership(
625623
membership = Membership(
626624
user_id=user.id,
627625
workspace_id=workspace.id,
628-
role=WorkspaceRole.EDITOR,
629626
)
630627
# Also create organization membership - required for org context resolution
631628
org_membership = OrganizationMembership(
@@ -703,12 +700,10 @@ async def test_role_dependency_requires_workspace_for_multi_org(
703700
Membership(
704701
user_id=user.id,
705702
workspace_id=workspace_a.id,
706-
role=WorkspaceRole.EDITOR,
707703
),
708704
Membership(
709705
user_id=user.id,
710706
workspace_id=workspace_b.id,
711-
role=WorkspaceRole.EDITOR,
712707
),
713708
]
714709
# Also create organization memberships for both orgs

tests/unit/test_invitation.py

Lines changed: 136 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from sqlalchemy.ext.asyncio import AsyncSession
1010

1111
from tracecat.auth.schemas import UserRole
12-
from tracecat.authz.enums import OrgRole, WorkspaceRole
1312
from tracecat.db.models import (
1413
Invitation,
1514
Organization,
@@ -48,13 +47,25 @@ async def test_create_organization_invitation(self, session: AsyncSession):
4847
session.add(inviter)
4948
await session.flush()
5049

50+
# Create role for invitation
51+
from tracecat.db.models import Role
52+
53+
member_role = Role(
54+
id=uuid.uuid4(),
55+
name="Member",
56+
slug="member",
57+
organization_id=org.id,
58+
)
59+
session.add(member_role)
60+
await session.flush()
61+
5162
# Create invitation
5263
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
5364
expires_at = datetime.now(UTC) + timedelta(days=7)
5465
invitation = OrganizationInvitation(
5566
organization_id=org.id,
5667
57-
role=OrgRole.MEMBER,
68+
role_id=member_role.id,
5869
status=InvitationStatus.PENDING,
5970
invited_by=inviter.id,
6071
token=token,
@@ -67,7 +78,7 @@ async def test_create_organization_invitation(self, session: AsyncSession):
6778
assert invitation.id is not None
6879
assert invitation.organization_id == org.id
6980
assert invitation.email == "[email protected]"
70-
assert invitation.role == OrgRole.MEMBER
81+
assert invitation.role.slug == "member"
7182
assert invitation.status == InvitationStatus.PENDING
7283
assert invitation.invited_by == inviter.id
7384
assert invitation.token == token
@@ -86,11 +97,23 @@ async def test_organization_invitation_admin_role(self, session: AsyncSession):
8697
session.add(org)
8798
await session.flush()
8899

100+
# Create admin role for invitation
101+
from tracecat.db.models import Role
102+
103+
admin_role = Role(
104+
id=uuid.uuid4(),
105+
name="Admin",
106+
slug="admin",
107+
organization_id=org.id,
108+
)
109+
session.add(admin_role)
110+
await session.flush()
111+
89112
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
90113
invitation = OrganizationInvitation(
91114
organization_id=org.id,
92115
93-
role=OrgRole.ADMIN,
116+
role_id=admin_role.id,
94117
status=InvitationStatus.PENDING,
95118
invited_by=None,
96119
token=token,
@@ -100,7 +123,7 @@ async def test_organization_invitation_admin_role(self, session: AsyncSession):
100123
await session.commit()
101124
await session.refresh(invitation)
102125

103-
assert invitation.role == OrgRole.ADMIN
126+
assert invitation.role.slug == "admin"
104127

105128
@pytest.mark.anyio
106129
async def test_organization_invitation_status_transition(
@@ -116,11 +139,23 @@ async def test_organization_invitation_status_transition(
116139
session.add(org)
117140
await session.flush()
118141

142+
# Create role for invitation
143+
from tracecat.db.models import Role
144+
145+
member_role = Role(
146+
id=uuid.uuid4(),
147+
name="Member",
148+
slug="member",
149+
organization_id=org.id,
150+
)
151+
session.add(member_role)
152+
await session.flush()
153+
119154
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
120155
invitation = OrganizationInvitation(
121156
organization_id=org.id,
122157
123-
role=OrgRole.MEMBER,
158+
role_id=member_role.id,
124159
status=InvitationStatus.PENDING,
125160
invited_by=None,
126161
token=token,
@@ -150,11 +185,23 @@ async def test_organization_invitation_cascade_delete(self, session: AsyncSessio
150185
session.add(org)
151186
await session.flush()
152187

188+
# Create role for invitation
189+
from tracecat.db.models import Role
190+
191+
member_role = Role(
192+
id=uuid.uuid4(),
193+
name="Member",
194+
slug="member",
195+
organization_id=org.id,
196+
)
197+
session.add(member_role)
198+
await session.flush()
199+
153200
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
154201
invitation = OrganizationInvitation(
155202
organization_id=org.id,
156203
157-
role=OrgRole.MEMBER,
204+
role_id=member_role.id,
158205
status=InvitationStatus.PENDING,
159206
invited_by=None,
160207
token=token,
@@ -188,11 +235,23 @@ async def test_organization_invitation_unique_token(self, session: AsyncSession)
188235
session.add(org)
189236
await session.flush()
190237

238+
# Create role for invitation
239+
from tracecat.db.models import Role
240+
241+
member_role = Role(
242+
id=uuid.uuid4(),
243+
name="Member",
244+
slug="member",
245+
organization_id=org.id,
246+
)
247+
session.add(member_role)
248+
await session.flush()
249+
191250
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
192251
invitation1 = OrganizationInvitation(
193252
organization_id=org.id,
194253
195-
role=OrgRole.MEMBER,
254+
role_id=member_role.id,
196255
status=InvitationStatus.PENDING,
197256
invited_by=None,
198257
token=token,
@@ -205,7 +264,7 @@ async def test_organization_invitation_unique_token(self, session: AsyncSession)
205264
invitation2 = OrganizationInvitation(
206265
organization_id=org.id,
207266
208-
role=OrgRole.MEMBER,
267+
role_id=member_role.id,
209268
status=InvitationStatus.PENDING,
210269
invited_by=None,
211270
token=token, # Same token
@@ -254,13 +313,25 @@ async def test_create_workspace_invitation(self, session: AsyncSession):
254313
session.add(inviter)
255314
await session.flush()
256315

316+
# Create role for invitation
317+
from tracecat.db.models import Role
318+
319+
editor_role = Role(
320+
id=uuid.uuid4(),
321+
name="Editor",
322+
slug="editor",
323+
organization_id=org.id,
324+
)
325+
session.add(editor_role)
326+
await session.flush()
327+
257328
# Create invitation
258329
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
259330
expires_at = datetime.now(UTC) + timedelta(days=7)
260331
invitation = Invitation(
261332
workspace_id=workspace.id,
262333
263-
role=WorkspaceRole.EDITOR,
334+
role_id=editor_role.id,
264335
status=InvitationStatus.PENDING,
265336
invited_by=inviter.id,
266337
token=token,
@@ -273,7 +344,7 @@ async def test_create_workspace_invitation(self, session: AsyncSession):
273344
assert invitation.id is not None
274345
assert invitation.workspace_id == workspace.id
275346
assert invitation.email == "[email protected]"
276-
assert invitation.role == WorkspaceRole.EDITOR
347+
assert invitation.role.slug == "editor"
277348
assert invitation.status == InvitationStatus.PENDING
278349
assert invitation.invited_by == inviter.id
279350
assert invitation.token == token
@@ -300,11 +371,23 @@ async def test_workspace_invitation_admin_role(self, session: AsyncSession):
300371
session.add(workspace)
301372
await session.flush()
302373

374+
# Create admin role for invitation
375+
from tracecat.db.models import Role
376+
377+
admin_role = Role(
378+
id=uuid.uuid4(),
379+
name="Admin",
380+
slug="admin",
381+
organization_id=org.id,
382+
)
383+
session.add(admin_role)
384+
await session.flush()
385+
303386
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
304387
invitation = Invitation(
305388
workspace_id=workspace.id,
306389
307-
role=WorkspaceRole.ADMIN,
390+
role_id=admin_role.id,
308391
status=InvitationStatus.PENDING,
309392
invited_by=None,
310393
token=token,
@@ -314,7 +397,7 @@ async def test_workspace_invitation_admin_role(self, session: AsyncSession):
314397
await session.commit()
315398
await session.refresh(invitation)
316399

317-
assert invitation.role == WorkspaceRole.ADMIN
400+
assert invitation.role.slug == "admin"
318401

319402
@pytest.mark.anyio
320403
async def test_workspace_invitation_status_transition(self, session: AsyncSession):
@@ -336,11 +419,23 @@ async def test_workspace_invitation_status_transition(self, session: AsyncSessio
336419
session.add(workspace)
337420
await session.flush()
338421

422+
# Create role for invitation
423+
from tracecat.db.models import Role
424+
425+
editor_role = Role(
426+
id=uuid.uuid4(),
427+
name="Editor",
428+
slug="editor",
429+
organization_id=org.id,
430+
)
431+
session.add(editor_role)
432+
await session.flush()
433+
339434
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
340435
invitation = Invitation(
341436
workspace_id=workspace.id,
342437
343-
role=WorkspaceRole.EDITOR,
438+
role_id=editor_role.id,
344439
status=InvitationStatus.PENDING,
345440
invited_by=None,
346441
token=token,
@@ -376,11 +471,23 @@ async def test_workspace_invitation_cascade_delete(self, session: AsyncSession):
376471
session.add(workspace)
377472
await session.flush()
378473

474+
# Create role for invitation
475+
from tracecat.db.models import Role
476+
477+
editor_role = Role(
478+
id=uuid.uuid4(),
479+
name="Editor",
480+
slug="editor",
481+
organization_id=org.id,
482+
)
483+
session.add(editor_role)
484+
await session.flush()
485+
379486
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
380487
invitation = Invitation(
381488
workspace_id=workspace.id,
382489
383-
role=WorkspaceRole.EDITOR,
490+
role_id=editor_role.id,
384491
status=InvitationStatus.PENDING,
385492
invited_by=None,
386493
token=token,
@@ -420,11 +527,23 @@ async def test_workspace_invitation_unique_token(self, session: AsyncSession):
420527
session.add(workspace)
421528
await session.flush()
422529

530+
# Create role for invitation
531+
from tracecat.db.models import Role
532+
533+
editor_role = Role(
534+
id=uuid.uuid4(),
535+
name="Editor",
536+
slug="editor",
537+
organization_id=org.id,
538+
)
539+
session.add(editor_role)
540+
await session.flush()
541+
423542
token = uuid.uuid4().hex + uuid.uuid4().hex[:32]
424543
invitation1 = Invitation(
425544
workspace_id=workspace.id,
426545
427-
role=WorkspaceRole.EDITOR,
546+
role_id=editor_role.id,
428547
status=InvitationStatus.PENDING,
429548
invited_by=None,
430549
token=token,
@@ -437,7 +556,7 @@ async def test_workspace_invitation_unique_token(self, session: AsyncSession):
437556
invitation2 = Invitation(
438557
workspace_id=workspace.id,
439558
440-
role=WorkspaceRole.EDITOR,
559+
role_id=editor_role.id,
441560
status=InvitationStatus.PENDING,
442561
invited_by=None,
443562
token=token, # Same token

0 commit comments

Comments
 (0)