Skip to content

Commit 69e5c60

Browse files
committed
refactor(rbac): remove role-dropping changes from scope-seeding branch
1 parent 7d34d43 commit 69e5c60

File tree

22 files changed

+346
-964
lines changed

22 files changed

+346
-964
lines changed

frontend/src/app/invitations/accept/page.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,13 @@ function AcceptInvitationContent() {
201201
<>
202202
<strong>{invitation.inviter_name}</strong> has invited you to
203203
join <strong>{invitation.organization_name}</strong> as a{" "}
204-
<strong>{invitation.role_name}</strong>.
204+
<strong>{invitation.role}</strong>.
205205
</>
206206
) : (
207207
<>
208208
You&apos;ve been invited to join{" "}
209209
<strong>{invitation.organization_name}</strong> as a{" "}
210-
<strong>{invitation.role_name}</strong>.
210+
<strong>{invitation.role}</strong>.
211211
</>
212212
)}
213213
</CardDescription>
@@ -224,7 +224,7 @@ function AcceptInvitationContent() {
224224
<div className="flex justify-between">
225225
<span className="text-muted-foreground">Role</span>
226226
<span className="font-medium capitalize">
227-
{invitation.role_name}
227+
{invitation.role}
228228
</span>
229229
</div>
230230
{invitation.inviter_email && (
@@ -320,12 +320,12 @@ function AcceptInvitationContent() {
320320
{invitation.inviter_name ? (
321321
<>
322322
<strong>{invitation.inviter_name}</strong> has invited you to join
323-
this organization as a <strong>{invitation.role_name}</strong>.
323+
this organization as a <strong>{invitation.role}</strong>.
324324
</>
325325
) : (
326326
<>
327327
You&apos;ve been invited to join this organization as a{" "}
328-
<strong>{invitation.role_name}</strong>.
328+
<strong>{invitation.role}</strong>.
329329
</>
330330
)}
331331
</CardDescription>
@@ -341,9 +341,7 @@ function AcceptInvitationContent() {
341341
</div>
342342
<div className="flex justify-between">
343343
<span className="text-muted-foreground">Role</span>
344-
<span className="font-medium capitalize">
345-
{invitation.role_name}
346-
</span>
344+
<span className="font-medium capitalize">{invitation.role}</span>
347345
</div>
348346
{invitation.inviter_email && (
349347
<div className="flex justify-between">

frontend/src/client/schemas.gen.ts

Lines changed: 13 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -10022,37 +10022,15 @@ export const $OrgInvitationCreate = {
1002210022
format: "email",
1002310023
title: "Email",
1002410024
},
10025-
role_id: {
10026-
anyOf: [
10027-
{
10028-
type: "string",
10029-
format: "uuid",
10030-
},
10031-
{
10032-
type: "null",
10033-
},
10034-
],
10035-
title: "Role Id",
10036-
},
10037-
role_slug: {
10038-
anyOf: [
10039-
{
10040-
type: "string",
10041-
},
10042-
{
10043-
type: "null",
10044-
},
10045-
],
10046-
title: "Role Slug",
10025+
role: {
10026+
$ref: "#/components/schemas/OrgRole",
10027+
default: "member",
1004710028
},
1004810029
},
1004910030
type: "object",
1005010031
required: ["email"],
1005110032
title: "OrgInvitationCreate",
10052-
description: `Request body for creating an organization invitation.
10053-
10054-
Either role_id or role_slug must be provided to specify the role to grant.
10055-
If both are provided, role_id takes precedence.`,
10033+
description: "Request body for creating an organization invitation.",
1005610034
} as const
1005710035

1005810036
export const $OrgInvitationRead = {
@@ -10072,25 +10050,8 @@ export const $OrgInvitationRead = {
1007210050
format: "email",
1007310051
title: "Email",
1007410052
},
10075-
role_id: {
10076-
type: "string",
10077-
format: "uuid",
10078-
title: "Role Id",
10079-
},
10080-
role_slug: {
10081-
anyOf: [
10082-
{
10083-
type: "string",
10084-
},
10085-
{
10086-
type: "null",
10087-
},
10088-
],
10089-
title: "Role Slug",
10090-
},
10091-
role_name: {
10092-
type: "string",
10093-
title: "Role Name",
10053+
role: {
10054+
$ref: "#/components/schemas/OrgRole",
1009410055
},
1009510056
status: {
1009610057
$ref: "#/components/schemas/InvitationStatus",
@@ -10135,9 +10096,7 @@ export const $OrgInvitationRead = {
1013510096
"id",
1013610097
"organization_id",
1013710098
"email",
10138-
"role_id",
10139-
"role_slug",
10140-
"role_name",
10099+
"role",
1014110100
"status",
1014210101
"invited_by",
1014310102
"expires_at",
@@ -10181,20 +10140,8 @@ export const $OrgInvitationReadMinimal = {
1018110140
],
1018210141
title: "Inviter Email",
1018310142
},
10184-
role_slug: {
10185-
anyOf: [
10186-
{
10187-
type: "string",
10188-
},
10189-
{
10190-
type: "null",
10191-
},
10192-
],
10193-
title: "Role Slug",
10194-
},
10195-
role_name: {
10196-
type: "string",
10197-
title: "Role Name",
10143+
role: {
10144+
$ref: "#/components/schemas/OrgRole",
1019810145
},
1019910146
status: {
1020010147
$ref: "#/components/schemas/InvitationStatus",
@@ -10222,8 +10169,7 @@ export const $OrgInvitationReadMinimal = {
1022210169
"organization_name",
1022310170
"inviter_name",
1022410171
"inviter_email",
10225-
"role_slug",
10226-
"role_name",
10172+
"role",
1022710173
"status",
1022810174
"expires_at",
1022910175
],
@@ -10268,28 +10214,8 @@ export const $OrgMemberRead = {
1026810214
format: "email",
1026910215
title: "Email",
1027010216
},
10271-
role_id: {
10272-
anyOf: [
10273-
{
10274-
type: "string",
10275-
format: "uuid",
10276-
},
10277-
{
10278-
type: "null",
10279-
},
10280-
],
10281-
title: "Role Id",
10282-
},
10283-
role_slug: {
10284-
anyOf: [
10285-
{
10286-
type: "string",
10287-
},
10288-
{
10289-
type: "null",
10290-
},
10291-
],
10292-
title: "Role Slug",
10217+
role: {
10218+
$ref: "#/components/schemas/OrgRole",
1029310219
},
1029410220
is_active: {
1029510221
type: "boolean",
@@ -10322,8 +10248,7 @@ export const $OrgMemberRead = {
1032210248
"first_name",
1032310249
"last_name",
1032410250
"email",
10325-
"role_id",
10326-
"role_slug",
10251+
"role",
1032710252
"is_active",
1032810253
"is_superuser",
1032910254
"is_verified",

frontend/src/client/types.gen.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3241,14 +3241,10 @@ export type OrgInvitationAccept = {
32413241

32423242
/**
32433243
* Request body for creating an organization invitation.
3244-
*
3245-
* Either role_id or role_slug must be provided to specify the role to grant.
3246-
* If both are provided, role_id takes precedence.
32473244
*/
32483245
export type OrgInvitationCreate = {
32493246
email: string
3250-
role_id?: string | null
3251-
role_slug?: string | null
3247+
role?: OrgRole
32523248
}
32533249

32543250
/**
@@ -3258,9 +3254,7 @@ export type OrgInvitationRead = {
32583254
id: string
32593255
organization_id: string
32603256
email: string
3261-
role_id: string
3262-
role_slug: string | null
3263-
role_name: string
3257+
role: OrgRole
32643258
status: InvitationStatus
32653259
invited_by: string | null
32663260
expires_at: string
@@ -3279,8 +3273,7 @@ export type OrgInvitationReadMinimal = {
32793273
organization_name: string
32803274
inviter_name: string | null
32813275
inviter_email: string | null
3282-
role_slug: string | null
3283-
role_name: string
3276+
role: OrgRole
32843277
status: InvitationStatus
32853278
expires_at: string
32863279
email_matches?: boolean | null
@@ -3291,8 +3284,7 @@ export type OrgMemberRead = {
32913284
first_name: string | null
32923285
last_name: string | null
32933286
email: string
3294-
role_id: string | null
3295-
role_slug: string | null
3287+
role: OrgRole
32963288
is_active: boolean
32973289
is_superuser: boolean
32983290
is_verified: boolean

frontend/src/components/organization/org-invitations-table.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useForm } from "react-hook-form"
77
import { z } from "zod"
88
import {
99
type OrgInvitationRead,
10+
type OrgRole,
1011
organizationGetInvitationToken,
1112
} from "@/client"
1213
import {
@@ -67,7 +68,7 @@ import { useOrgInvitations } from "@/lib/hooks"
6768

6869
const invitationFormSchema = z.object({
6970
email: z.string().email("Invalid email address"),
70-
role_slug: z.enum(["member", "admin", "owner"]),
71+
role: z.enum(["member", "admin", "owner"]),
7172
})
7273

7374
type InvitationFormValues = z.infer<typeof invitationFormSchema>
@@ -84,15 +85,15 @@ export function OrgInvitationsTable() {
8485
resolver: zodResolver(invitationFormSchema),
8586
defaultValues: {
8687
email: "",
87-
role_slug: "member",
88+
role: "member",
8889
},
8990
})
9091

9192
const handleCreateInvitation = async (values: InvitationFormValues) => {
9293
try {
9394
await createInvitation({
9495
email: values.email,
95-
role_slug: values.role_slug,
96+
role: values.role as OrgRole,
9697
})
9798
form.reset()
9899
setIsCreateDialogOpen(false)
@@ -175,7 +176,7 @@ export function OrgInvitationsTable() {
175176
/>
176177
<FormField
177178
control={form.control}
178-
name="role_slug"
179+
name="role"
179180
render={({ field }) => (
180181
<FormItem>
181182
<FormLabel>Role</FormLabel>
@@ -248,7 +249,7 @@ export function OrgInvitationsTable() {
248249
enableHiding: false,
249250
},
250251
{
251-
accessorKey: "role_name",
252+
accessorKey: "role",
252253
header: ({ column }) => (
253254
<DataTableColumnHeader
254255
className="text-xs"
@@ -258,7 +259,7 @@ export function OrgInvitationsTable() {
258259
),
259260
cell: ({ row }) => (
260261
<div className="text-xs capitalize">
261-
{row.getValue<OrgInvitationRead["role_name"]>("role_name")}
262+
{row.getValue<OrgInvitationRead["role"]>("role")}
262263
</div>
263264
),
264265
enableSorting: true,

frontend/src/components/organization/org-members-table.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export function OrgMembersTable() {
5959
const handleChangeRole = async (role: UserRole) => {
6060
try {
6161
if (selectedMember) {
62-
if (selectedMember.role_slug === role) {
62+
if (selectedMember.role === role) {
6363
toast({
6464
title: "Update skipped",
6565
description: `User ${selectedMember.email} is already a ${role} member`,
@@ -161,7 +161,7 @@ export function OrgMembersTable() {
161161
enableHiding: false,
162162
},
163163
{
164-
accessorKey: "role_slug",
164+
accessorKey: "role",
165165
header: ({ column }) => (
166166
<DataTableColumnHeader
167167
className="text-xs"
@@ -171,7 +171,7 @@ export function OrgMembersTable() {
171171
),
172172
cell: ({ row }) => (
173173
<div className="text-xs capitalize">
174-
{row.getValue<OrgMemberRead["role_slug"]>("role_slug") || "-"}
174+
{row.getValue<OrgMemberRead["role"]>("role")}
175175
</div>
176176
),
177177
enableSorting: true,

frontend/src/hooks/use-org-membership.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function useOrgMembership() {
2626

2727
// Check if user has org-level admin/owner role (not platform admin)
2828
const hasOrgAdminRole =
29-
membership?.role_slug === "admin" || membership?.role_slug === "owner"
29+
membership?.role === "admin" || membership?.role === "owner"
3030

3131
// Check if user can administer the org (platform admin OR org admin/owner)
3232
const canAdministerOrg = user?.isPlatformAdmin() || hasOrgAdminRole

packages/tracecat-ee/tracecat_ee/admin/organizations/service.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from sqlalchemy.orm import selectinload
1212

1313
from tracecat.auth.types import AccessLevel, Role
14-
from tracecat.authz.seeding import seed_system_roles_for_org
1514
from tracecat.db.models import (
1615
Organization,
1716
RegistryRepository,
@@ -48,7 +47,6 @@ async def create_organization(self, params: OrgCreate) -> OrgRead:
4847
name=params.name,
4948
slug=params.slug,
5049
)
51-
await seed_system_roles_for_org(self.session, org.id)
5250
return OrgRead.model_validate(org)
5351

5452
async def get_organization(self, org_id: uuid.UUID) -> OrgRead:

tests/unit/api/test_api_workspaces.py

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

1212
from tracecat.auth.types import Role
13+
from tracecat.authz.enums import WorkspaceRole
1314
from tracecat.authz.service import MembershipWithOrg
1415
from tracecat.db.models import Workspace
1516
from tracecat.logger import logger
@@ -174,6 +175,7 @@ async def test_get_workspace_success(
174175
mock_membership = AsyncMock()
175176
mock_membership.user_id = test_admin_role.user_id
176177
mock_membership.workspace_id = mock_workspace_data.id
178+
mock_membership.role = WorkspaceRole.ADMIN
177179
mock_membership_svc.get_membership.return_value = MembershipWithOrg(
178180
membership=mock_membership, org_id=mock_workspace_data.organization_id
179181
)

0 commit comments

Comments
 (0)