-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpst
More file actions
192 lines (125 loc) · 6.16 KB
/
pst
File metadata and controls
192 lines (125 loc) · 6.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
Frontend Authorization Tasks (Agent-Ready)
Task 0 — Inventory only (no code)
Do not change code.
List the following with file paths:
1. Router definition file(s) (router.tsx / router.ts / similar).
2. Where nav/menu items are defined (sidebar/topbar).
3. Where entity selection UI lives (entity dropdown in catalog/workspaces).
4. Where “source” selection is (even if currently fixed).
5. The shared API client (api() helper) and where React Query query keys/fetchers live.
Reply with the list grouped by “routing / nav / entity-source UI / data fetching”.
⸻
Task 1 — Define a single permission helper module
Create file: src/app/auth/permissions.ts
Add functions (no React here):
1. export function isAdmin(me: MeResponse | null | undefined): boolean
2. export function allowedEntities(me: MeResponse | null | undefined): Set<string> | null
• return null if me?.scopes.entities === "ALL"
• else return new Set(me.scopes.entities)
3. export function allowedSources(me: MeResponse | null | undefined): Set<string> | null
• same pattern
4. export function canAccessEntity(me, entityCode: string): boolean
5. export function canAccessSource(me, sourceCode: string): boolean
No other logic.
⸻
Task 2 — Add a ProtectedRoute wrapper component
Create file: src/app/auth/ProtectedRoute.tsx
Implement a component that:
• reads useAuth()
• if auth state is not "authenticated", render nothing (AuthGate will handle it)
• if requiresAdmin prop is true and user is not admin → render a simple “403 / Not allowed” page (Mantine-friendly)
• if requiredEntities prop exists → check canAccessEntity(...) for all; if any fail, show 403
• if requiredSources prop exists → check similarly
Export component:
• export function ProtectedRoute(props: { children: React.ReactNode; requiresAdmin?: boolean; requiredEntities?: string[]; requiredSources?: string[]; }): JSX.Element
No redirects here (keep it simple).
⸻
Task 3 — Gate admin-only routes in the router definition
Edit file: your router definition (from Task 0).
For each admin-only page route:
• Wrap its element with <ProtectedRoute requiresAdmin>...</ProtectedRoute>
Example pattern:
• element: <ProtectedRoute requiresAdmin><AdminPage /></ProtectedRoute>
Do not change paths.
⸻
Task 4 — Gate profile-only routes (non-admin) via role list (minimal)
Edit file: src/app/auth/permissions.ts
Add helper:
• export function hasRole(me: MeResponse | null | undefined, role: string): boolean (me?.roles.includes(role))
Then in router, for routes restricted to certain roles:
• wrap with <ProtectedRoute> but also add a small requiresRole?: string[] support OR do a custom wrapper locally.
Preferred (small change):
• Extend ProtectedRoute with requiredRoles?: string[]:
• allow if admin OR if any role matches.
Apply to routes that should only be accessible to some roles.
⸻
Task 5 — Hide nav items based on permissions (do not remove routes)
Edit file: nav/menu definition (from Task 0).
Rules:
• If item is admin-only: render only when isAdmin(me)
• If item is role-limited: render only when hasRole(me, "ROLE_NAME") OR admin
• If item depends on entity/source access: render only if allowed set is not empty (or ALL)
Do not delete routes; this is UI-only.
⸻
Task 6 — Filter entity dropdowns using scopes
Edit file: the component(s) that list entities (catalog filters, workspace selection, etc.).
Change behavior:
• When you load entity list from backend, it should already be filtered; still enforce in UI:
• If me.scopes.entities !== "ALL", filter options to that set (defensive)
• If entity list ends up empty:
• show a friendly message: “No entities assigned to your profile.”
Do not change backend calls here.
⸻
Task 7 — Add “source” awareness for future (even if only one source now)
Wherever source selection is (or if none exists):
• Introduce a getCurrentSource() function (temporary) returning "Chrome" or the selected source.
• Before showing a source option, filter by allowedSources(me) set.
• If the current source is not allowed:
• show a blocking message and disable screens that require data.
This is future-proofing with minimal code.
⸻
Task 8 — Centralize API error handling for 403
Edit file: your api() helper (src/app/api/http.ts).
When res.ok === false and status is 403:
• parse body as you already do
• throw the error object as today
(keep behavior)
But also: ensure callers can detect status===403 reliably (you already include status).
No UI here, just ensure consistent error shape.
⸻
Task 9 — Add a standard “NotAuthorized” component
Create file: src/app/components/NotAuthorized.tsx
Use Mantine:
• Show title “Access denied”
• Show small text: “You don’t have permission to access this page.”
• (Optional) show current user email if available
Use it in ProtectedRoute.
⸻
Task 10 — React Query: prevent fetching forbidden entity/source data
In the query hooks that fetch data by entity/source:
• Add enabled: boolean flag based on permission checks.
Example:
• If query requires entityCode and user cannot access it → enabled: false
Also show a UI message instead of spinners when disabled.
Do not change query keys, only add enabled.
⸻
Task 11 — React Query: invalidate caches on logout
Where logout happens (AuthContext.logout):
• after successful logout, call:
• queryClient.clear() (or remove relevant queries)
So the next user doesn’t see stale data.
(You have queryClient already.)
⸻
Task 12 — Smoke-check checklist (no code)
After Tasks 1–11:
1. Admin can open admin screens.
2. Normal user cannot open admin screens (403 page shown).
3. Entity dropdown only shows allowed entities.
4. Attempt to navigate directly to blocked route shows 403 page (no crash).
5. Queries requiring forbidden entity/source do not fire (React Query enabled=false).
Reply with which routes and which components were verified.
⸻
Notes for the agent (don’t violate these constraints)
• Do not remove routes; only gate and hide.
• Do not add complex permission DSL.
• Keep all checks based on /users/me fields only: roles, is_admin, scopes.entities, scopes.sources.