Skip to content

Commit 3eee21f

Browse files
committed
refactor(rbac): remove role-dropping changes from scope-seeding branch
1 parent 18d19dd commit 3eee21f

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
@@ -9974,37 +9974,15 @@ export const $OrgInvitationCreate = {
99749974
format: "email",
99759975
title: "Email",
99769976
},
9977-
role_id: {
9978-
anyOf: [
9979-
{
9980-
type: "string",
9981-
format: "uuid",
9982-
},
9983-
{
9984-
type: "null",
9985-
},
9986-
],
9987-
title: "Role Id",
9988-
},
9989-
role_slug: {
9990-
anyOf: [
9991-
{
9992-
type: "string",
9993-
},
9994-
{
9995-
type: "null",
9996-
},
9997-
],
9998-
title: "Role Slug",
9977+
role: {
9978+
$ref: "#/components/schemas/OrgRole",
9979+
default: "member",
99999980
},
100009981
},
100019982
type: "object",
100029983
required: ["email"],
100039984
title: "OrgInvitationCreate",
10004-
description: `Request body for creating an organization invitation.
10005-
10006-
Either role_id or role_slug must be provided to specify the role to grant.
10007-
If both are provided, role_id takes precedence.`,
9985+
description: "Request body for creating an organization invitation.",
100089986
} as const
100099987

100109988
export const $OrgInvitationRead = {
@@ -10024,25 +10002,8 @@ export const $OrgInvitationRead = {
1002410002
format: "email",
1002510003
title: "Email",
1002610004
},
10027-
role_id: {
10028-
type: "string",
10029-
format: "uuid",
10030-
title: "Role Id",
10031-
},
10032-
role_slug: {
10033-
anyOf: [
10034-
{
10035-
type: "string",
10036-
},
10037-
{
10038-
type: "null",
10039-
},
10040-
],
10041-
title: "Role Slug",
10042-
},
10043-
role_name: {
10044-
type: "string",
10045-
title: "Role Name",
10005+
role: {
10006+
$ref: "#/components/schemas/OrgRole",
1004610007
},
1004710008
status: {
1004810009
$ref: "#/components/schemas/InvitationStatus",
@@ -10087,9 +10048,7 @@ export const $OrgInvitationRead = {
1008710048
"id",
1008810049
"organization_id",
1008910050
"email",
10090-
"role_id",
10091-
"role_slug",
10092-
"role_name",
10051+
"role",
1009310052
"status",
1009410053
"invited_by",
1009510054
"expires_at",
@@ -10133,20 +10092,8 @@ export const $OrgInvitationReadMinimal = {
1013310092
],
1013410093
title: "Inviter Email",
1013510094
},
10136-
role_slug: {
10137-
anyOf: [
10138-
{
10139-
type: "string",
10140-
},
10141-
{
10142-
type: "null",
10143-
},
10144-
],
10145-
title: "Role Slug",
10146-
},
10147-
role_name: {
10148-
type: "string",
10149-
title: "Role Name",
10095+
role: {
10096+
$ref: "#/components/schemas/OrgRole",
1015010097
},
1015110098
status: {
1015210099
$ref: "#/components/schemas/InvitationStatus",
@@ -10174,8 +10121,7 @@ export const $OrgInvitationReadMinimal = {
1017410121
"organization_name",
1017510122
"inviter_name",
1017610123
"inviter_email",
10177-
"role_slug",
10178-
"role_name",
10124+
"role",
1017910125
"status",
1018010126
"expires_at",
1018110127
],
@@ -10220,28 +10166,8 @@ export const $OrgMemberRead = {
1022010166
format: "email",
1022110167
title: "Email",
1022210168
},
10223-
role_id: {
10224-
anyOf: [
10225-
{
10226-
type: "string",
10227-
format: "uuid",
10228-
},
10229-
{
10230-
type: "null",
10231-
},
10232-
],
10233-
title: "Role Id",
10234-
},
10235-
role_slug: {
10236-
anyOf: [
10237-
{
10238-
type: "string",
10239-
},
10240-
{
10241-
type: "null",
10242-
},
10243-
],
10244-
title: "Role Slug",
10169+
role: {
10170+
$ref: "#/components/schemas/OrgRole",
1024510171
},
1024610172
is_active: {
1024710173
type: "boolean",
@@ -10274,8 +10200,7 @@ export const $OrgMemberRead = {
1027410200
"first_name",
1027510201
"last_name",
1027610202
"email",
10277-
"role_id",
10278-
"role_slug",
10203+
"role",
1027910204
"is_active",
1028010205
"is_superuser",
1028110206
"is_verified",

frontend/src/client/types.gen.ts

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

32223222
/**
32233223
* Request body for creating an organization invitation.
3224-
*
3225-
* Either role_id or role_slug must be provided to specify the role to grant.
3226-
* If both are provided, role_id takes precedence.
32273224
*/
32283225
export type OrgInvitationCreate = {
32293226
email: string
3230-
role_id?: string | null
3231-
role_slug?: string | null
3227+
role?: OrgRole
32323228
}
32333229

32343230
/**
@@ -3238,9 +3234,7 @@ export type OrgInvitationRead = {
32383234
id: string
32393235
organization_id: string
32403236
email: string
3241-
role_id: string
3242-
role_slug: string | null
3243-
role_name: string
3237+
role: OrgRole
32443238
status: InvitationStatus
32453239
invited_by: string | null
32463240
expires_at: string
@@ -3259,8 +3253,7 @@ export type OrgInvitationReadMinimal = {
32593253
organization_name: string
32603254
inviter_name: string | null
32613255
inviter_email: string | null
3262-
role_slug: string | null
3263-
role_name: string
3256+
role: OrgRole
32643257
status: InvitationStatus
32653258
expires_at: string
32663259
email_matches?: boolean | null
@@ -3271,8 +3264,7 @@ export type OrgMemberRead = {
32713264
first_name: string | null
32723265
last_name: string | null
32733266
email: string
3274-
role_id: string | null
3275-
role_slug: string | null
3267+
role: OrgRole
32763268
is_active: boolean
32773269
is_superuser: boolean
32783270
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)