Skip to content

Commit 06cfa32

Browse files
committed
fix(rbac): verify user membership in rbac service
1 parent c2f61e0 commit 06cfa32

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

packages/tracecat-ee/tracecat_ee/rbac/service.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -622,11 +622,14 @@ async def create_user_assignment(
622622
Returns:
623623
Created UserRoleAssignment
624624
"""
625-
# Verify user exists
626-
stmt = select(User).where(User.id == user_id) # pyright: ignore[reportArgumentType]
625+
# Verify user belongs to this organization
626+
stmt = select(OrganizationMembership).where(
627+
OrganizationMembership.user_id == user_id,
628+
OrganizationMembership.organization_id == self.organization_id,
629+
)
627630
result = await self.session.execute(stmt)
628631
if result.scalar_one_or_none() is None:
629-
raise TracecatNotFoundError("User not found")
632+
raise TracecatNotFoundError("User not found in organization")
630633

631634
# Verify role exists
632635
await self.get_role(role_id)

tests/unit/test_rbac_service.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,55 @@ async def test_update_assignment(
412412
assert updated.role_id == role2.id
413413

414414

415+
@pytest.mark.anyio
416+
class TestRBACServiceUserAssignments:
417+
"""Test direct user role assignment management."""
418+
419+
async def test_create_user_assignment_for_org_member(
420+
self,
421+
session: AsyncSession,
422+
role: Role,
423+
user: User,
424+
):
425+
"""Create direct assignment for org member."""
426+
service = RBACService(session, role=role)
427+
custom_role = await service.create_role(name="Direct User Role")
428+
429+
assignment = await service.create_user_assignment(
430+
user_id=user.id,
431+
role_id=custom_role.id,
432+
)
433+
434+
assert assignment.user_id == user.id
435+
assert assignment.role_id == custom_role.id
436+
assert assignment.organization_id == role.organization_id
437+
438+
async def test_create_user_assignment_rejects_non_member(
439+
self,
440+
session: AsyncSession,
441+
role: Role,
442+
):
443+
"""Cannot assign org role to user outside organization."""
444+
service = RBACService(session, role=role)
445+
custom_role = await service.create_role(name="Direct User Role")
446+
447+
external_user = User(
448+
id=uuid.uuid4(),
449+
email="external@example.com",
450+
hashed_password="test",
451+
)
452+
session.add(external_user)
453+
await session.commit()
454+
455+
with pytest.raises(
456+
TracecatNotFoundError, match="User not found in organization"
457+
):
458+
await service.create_user_assignment(
459+
user_id=external_user.id,
460+
role_id=custom_role.id,
461+
)
462+
463+
415464
@pytest.mark.anyio
416465
class TestRBACServiceScopeComputation:
417466
"""Test scope computation from group memberships."""

0 commit comments

Comments
 (0)