-
Notifications
You must be signed in to change notification settings - Fork 25
floconsole frontend user management #202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Caution Review failedThe pull request is closed. 📝 WalkthroughWalkthroughThis PR introduces a complete user management system to the Wavefront application. It adds CRUD API endpoints to UserService, implements React Query hooks for data fetching and mutations with validation schemas, and provides a full-featured UI page with user table, create/edit dialogs, and delete confirmation flow. The system integrates with existing notification and permission infrastructure. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant UI as UsersPage UI
participant Dialog as CreateUserDialog
participant MutationHook as useCreateUser Hook
participant API as UserService API
participant Backend as Backend API
participant QueryCache as React Query Cache
User->>UI: Clicks "Create User"
UI->>Dialog: Opens with isOpen=true
User->>Dialog: Fills form & submits
Dialog->>MutationHook: Calls mutate(userData)
MutationHook->>API: userService.createUser(data)
API->>Backend: POST /v1/users
Backend-->>API: { user: IUser }
MutationHook->>UI: Shows success notification
MutationHook->>QueryCache: Invalidate getUsersKey()
QueryCache-->>UI: Refetch users list
MutationHook->>Dialog: Calls onSuccess callback
Dialog->>UI: Closes dialog
sequenceDiagram
participant User as User
participant UI as UsersPage UI
participant ConfirmDialog as Delete Confirmation
participant MutationHook as useDeleteUser Hook
participant API as UserService API
participant Backend as Backend API
participant QueryCache as React Query Cache
User->>UI: Clicks delete icon on user row
UI->>ConfirmDialog: Opens confirmation dialog
User->>ConfirmDialog: Confirms deletion
ConfirmDialog->>MutationHook: Calls mutate(userId)
MutationHook->>API: userService.deleteUser(userId)
API->>Backend: DELETE /v1/users/{userId}
Backend-->>API: { message: string }
MutationHook->>UI: Shows success notification
MutationHook->>QueryCache: Invalidate getUsersKey()
QueryCache-->>UI: Refetch users list
ConfirmDialog->>UI: Closes dialog
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (9)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
Fix all issues with AI Agents 🤖
In @wavefront/client/src/api/user-service.ts:
- Around line 27-54: Add a runtime guard in user-service.ts to ensure the HTTP
client uses HTTPS in production: detect the runtime environment (e.g., NODE_ENV
=== "production") and validate the axios/baseURL used by this.http before
sending sensitive requests from createUser and updateUser; if the baseURL is not
HTTPS, throw or reject with a clear error (or fail-fast during service
initialization) so passwords are never sent over plain HTTP in production.
Ensure the check references the existing this.http or its configured baseURL and
runs at service construction or at the start of createUser/updateUser to prevent
accidental insecure transmissions.
In @wavefront/client/src/hooks/data/fetch-hooks.ts:
- Around line 414-416: The cache key includes appId via getUsersKey(appId || '')
but getUsersQueryFn ignores it and calls
floConsoleService.userService.listUsers(), causing cache inconsistency; either
remove appId from the key if users are global, or update
useGetUsers/getUsersQueryFn to pass the appId into the query function (use
getUsersKey to extract it) and call the app-scoped API (e.g.,
floConsoleService.userService.listUsersForApp or /v1/apps/{appId}/users) so the
request matches the cache scope; update the useQueryInit invocation and the
getUsersQueryFn signature accordingly.
In @wavefront/client/src/pages/apps/[appId]/users/CreateUserDialog.tsx:
- Around line 40-44: Remove the `form` object from the useEffect dependency
array so the effect only runs when `isOpen` changes; update the useEffect
wrapping the `form.reset()` call in CreateUserDialog to depend solely on
`isOpen` (or, alternatively, call `form.reset` via a stable callback provided by
react-hook-form v7+ so no changing `form` reference is required).
In @wavefront/client/src/pages/apps/[appId]/users/index.tsx:
- Around line 34-40: The backend lacks authorization on create_user (POST
/users) and list_users (GET /users) and whoami doesn't return role info; update
the create_user and list_users handlers to require super-admin privileges (add
or call existing auth middleware/guard that checks is_super_admin on the request
user) and ensure they return 403 for unauthorized callers, modify the whoami
handler to include role/super_admin flags in its response, update the frontend
IUser interface to include role/superAdmin (or equivalent) fields, and replace
the hardcoded isSuperAdmin useMemo in users/index.tsx with a real check against
currentUser.role/currentUser.superAdmin from whoami; ensure both frontend UI
controls and backend endpoints consistently enforce the same super-admin rule.
In @wavefront/client/src/types/user.ts:
- Around line 21-41: The updateUserSchema currently permits empty strings and
the controller only filters None, so empty strings get written and even hashed;
update the controller (the handler that currently uses "if v is not None") to
also treat empty strings as omitted (e.g., skip keys where value === ''), ensure
the service code that calls find_one_and_update does not receive '' values, and
add a guard in the password-hashing logic (the service password hashing path) to
only hash/update when password is non-empty and meets length/validation (min 8)
before passing to find_one_and_update.
🧹 Nitpick comments (3)
wavefront/client/src/types/user.ts (1)
1-9: Unconventional import placement.The import statements (lines 8-9) appear after the
IUserinterface definition. By convention, all imports should be placed at the top of the file before any other code.🔎 Suggested fix
+import { emailRegex, passwordRegex } from '@app/utils/regex'; +import { z } from 'zod'; + export interface IUser { id: string; email: string; first_name: string; last_name: string; } - -import { emailRegex, passwordRegex } from '@app/utils/regex'; -import { z } from 'zod';wavefront/client/src/hooks/data/query-functions.ts (1)
16-16: Consider consolidating duplicate IUser type definitions.The
IUserinterface appears to be defined in bothwavefront/client/src/types/user.tsandwavefront/client/src/pages/types.ts. This code duplication could lead to inconsistencies if one definition is updated without the other.📋 Recommendation
Keep the type definition only in
wavefront/client/src/types/user.tsand updatewavefront/client/src/pages/types.tsto import it from there. This ensures a single source of truth for theIUsertype.wavefront/client/src/pages/apps/[appId]/users/index.tsx (1)
100-107: Consider server-side search for better scalability.The current client-side filtering works well for small-to-medium user lists. For applications with hundreds or thousands of users, consider adding server-side search capabilities to the
listUsersendpoint with query parameters.Example enhancement to the API service:
async listUsers(searchQuery?: string): Promise<IApiResponse<{ users: IUser[] }>> { return this.http.get('/v1/users', { params: searchQuery ? { search: searchQuery } : undefined }); }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
wavefront/client/src/api/user-service.tswavefront/client/src/hooks/data/fetch-hooks.tswavefront/client/src/hooks/data/mutation-functions.tswavefront/client/src/hooks/data/mutation-hooks.tswavefront/client/src/hooks/data/query-functions.tswavefront/client/src/hooks/data/query-keys.tswavefront/client/src/pages/apps/[appId]/users/CreateUserDialog.tsxwavefront/client/src/pages/apps/[appId]/users/EditUserDialog.tsxwavefront/client/src/pages/apps/[appId]/users/index.tsxwavefront/client/src/pages/apps/layout.tsxwavefront/client/src/router/routes.tsxwavefront/client/src/types/user.tswavefront/server/apps/floconsole/floconsole/services/user_service.py
🧰 Additional context used
🧬 Code graph analysis (7)
wavefront/client/src/hooks/data/fetch-hooks.ts (3)
wavefront/client/src/types/user.ts (1)
IUser(1-6)wavefront/client/src/hooks/data/query-keys.ts (1)
getUsersKey(110-110)wavefront/client/src/hooks/data/query-functions.ts (1)
getUsersQueryFn(422-422)
wavefront/client/src/pages/apps/[appId]/users/index.tsx (5)
wavefront/client/src/store/notification-store.ts (1)
useNotifyStore(32-32)wavefront/client/src/types/user.ts (1)
IUser(1-6)wavefront/client/src/hooks/data/fetch-hooks.ts (1)
useGetUsers(414-416)wavefront/client/src/hooks/data/query-keys.ts (1)
getUsersKey(110-110)wavefront/client/src/lib/utils.ts (1)
extractErrorMessage(21-66)
wavefront/client/src/pages/apps/[appId]/users/CreateUserDialog.tsx (6)
wavefront/client/src/store/notification-store.ts (1)
useNotifyStore(32-32)wavefront/client/src/types/user.ts (2)
CreateUserInput(43-43)createUserSchema(11-19)wavefront/server/modules/api_services_module/api_services_module/models/service.py (1)
error(131-143)wavefront/client/src/lib/utils.ts (1)
extractErrorMessage(21-66)wavefront/client/src/components/ui/dialog.tsx (6)
Dialog(111-111)DialogContent(113-113)DialogHeader(116-116)DialogTitle(119-119)DialogDescription(114-114)DialogFooter(115-115)wavefront/client/src/components/ui/input.tsx (1)
Input(22-22)
wavefront/client/src/hooks/data/query-functions.ts (2)
wavefront/client/src/types/user.ts (1)
IUser(1-6)wavefront/client/src/pages/types.ts (1)
IUser(73-78)
wavefront/client/src/hooks/data/mutation-functions.ts (1)
wavefront/client/src/types/user.ts (1)
IUser(1-6)
wavefront/client/src/types/user.ts (1)
wavefront/client/src/utils/regex.ts (2)
emailRegex(2-2)passwordRegex(1-1)
wavefront/client/src/api/user-service.ts (2)
wavefront/client/src/lib/axios.ts (1)
IApiResponse(16-16)wavefront/client/src/types/user.ts (1)
IUser(1-6)
🔇 Additional comments (16)
wavefront/server/apps/floconsole/floconsole/services/user_service.py (1)
32-35: LGTM! Good consistency improvement.Adding
refresh=Trueensures the returned user object reflects the updated state after soft deletion, aligning with the pattern already used inupdate_user(line 25) and supporting client-side data refresh requirements.wavefront/client/src/router/routes.tsx (1)
28-28: LGTM! Standard routing setup.The new Users route follows the established pattern for resource management pages and is properly nested under the app layout.
Also applies to: 193-196
wavefront/client/src/pages/apps/layout.tsx (1)
7-7: LGTM! Navigation setup is consistent.The Users navigation item follows the established pattern and appropriately reuses the PermissionIcon component.
Also applies to: 81-87
wavefront/client/src/hooks/data/query-keys.ts (1)
65-66: LGTM! Query key functions follow established patterns.The new
getUsersKeyandgetUserKeyfunctions are consistent with existing query key builders in this file and follow the correct naming conventions.wavefront/client/src/hooks/data/query-functions.ts (1)
374-380: LGTM! Query function follows established patterns.The
getUsersQueryFnimplementation is consistent with other query functions in this file, properly validates the response structure, and provides a safe fallback.wavefront/client/src/pages/apps/[appId]/users/CreateUserDialog.tsx (2)
46-56: LGTM! Proper error handling and user feedback.The submit handler correctly uses
extractErrorMessagefor consistent error handling and provides appropriate user feedback via notifications. The success flow properly triggers callbacks and closes the dialog.
68-130: Well-structured form with proper validation.The form fields are properly configured with:
- Clear labels and required field indicators
- Appropriate input types (email, password)
- React Hook Form integration
- Zod validation via the schema
wavefront/client/src/hooks/data/mutation-hooks.ts (3)
85-103: LGTM! Well-implemented create user hook.The
useCreateUserhook follows the established pattern with proper:
- Query invalidation on success
- Error extraction and user-friendly messaging
- Success notifications
105-126: LGTM! Proper cache invalidation for both list and detail queries.The
useUpdateUserhook correctly invalidates both the users list (getUsersKey) and the specific user (getUserKey) to ensure the UI reflects the updated data.
128-146: LGTM! Consistent delete implementation.The
useDeleteUserhook follows the same solid pattern as the other mutation hooks with appropriate invalidation and error handling.wavefront/client/src/hooks/data/mutation-functions.ts (3)
71-73: LGTM! Straightforward delete implementation.The delete function is simple and doesn't assume a specific response structure, which is appropriate for delete operations.
39-50: The response structure in the code is correct. ThecreateUsermethod returnsPromise<IApiResponse<{ user: IUser }>>, whereIApiResponse<T>resolves toAxiosResponse<ApiResponse<T>>andApiResponse<T>is{ meta: Meta; data?: T }. This meansresponse.data.data.usercorrectly accesses the user object. No changes needed.
52-69: No changes needed. The API response structure is correctly accessed.The
updateUserAPI is correctly typed asPromise<IApiResponse<{ user: IUser }>>, whereIApiResponse<T>isAxiosResponse<ApiResponse<T>>. This creates the nested structure:response.data(theApiResponsewrapper) →response.data.data(the payload{ user: IUser }) →response.data.data.user(theIUserobject). The code correctly accesses this structure and is consistent withcreateUserand other mutation functions.wavefront/client/src/pages/apps/[appId]/users/EditUserDialog.tsx (1)
35-96: LGTM! Well-structured edit dialog with proper change detection.The component correctly:
- Resets the form when the dialog opens with new user data
- Detects changes by comparing each field to the original values
- Only sends modified fields to the API
- Prevents empty updates with a user-friendly error message
- Delegates cache invalidation to the parent via
onSuccesscallbackThe password handling is secure (empty by default) and the trimming logic correctly filters out whitespace-only passwords.
wavefront/client/src/pages/apps/[appId]/users/index.tsx (2)
42-53: Permission logic is well-designed but currently ineffective.The permission functions correctly implement:
- Self-editing capability for all users
- Admin-only deletion with self-deletion prevention (avoiding accidental lockout)
However, these checks are currently compromised by the hardcoded
isSuperAdmin = trueon line 36-39. Once the critical security issue is resolved, this logic will function correctly.
70-85: LGTM! Proper async operation handling.The delete handler correctly:
- Manages loading state throughout the operation
- Invalidates the query cache after successful deletion
- Extracts user-friendly error messages
- Cleans up state in the finally block
| async listUsers(): Promise<IApiResponse<{ users: IUser[] }>> { | ||
| return this.http.get('/v1/users'); | ||
| } | ||
|
|
||
| async createUser(data: { | ||
| email: string; | ||
| password: string; | ||
| first_name: string; | ||
| last_name: string; | ||
| }): Promise<IApiResponse<{ user: IUser }>> { | ||
| return this.http.post('/v1/users', data); | ||
| } | ||
|
|
||
| async updateUser( | ||
| userId: string, | ||
| data: { | ||
| email?: string; | ||
| password?: string; | ||
| first_name?: string; | ||
| last_name?: string; | ||
| } | ||
| ): Promise<IApiResponse<{ user: IUser }>> { | ||
| return this.http.patch(`/v1/users/${userId}`, data); | ||
| } | ||
|
|
||
| async deleteUser(userId: string): Promise<IApiResponse<{ message: string }>> { | ||
| return this.http.delete(`/v1/users/${userId}`); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
find wavefront/client -type f -name "*.ts" -o -name "*.js" | grep -E "(http|client|axios|api)" | head -20Repository: rootflo/wavefront
Length of output: 965
🏁 Script executed:
git ls-files wavefront/client/src/api/ | head -20Repository: rootflo/wavefront
Length of output: 996
🏁 Script executed:
cat -n wavefront/client/src/api/user-service.ts | head -30Repository: rootflo/wavefront
Length of output: 1047
🏁 Script executed:
find wavefront/client -type f -name "axios*" -o -name "*http*" | grep -E "\.(ts|js)$" | head -20Repository: rootflo/wavefront
Length of output: 94
🏁 Script executed:
find wavefront/client/src -type d -name "lib"Repository: rootflo/wavefront
Length of output: 85
🏁 Script executed:
cat -n wavefront/client/src/lib/axios.ts 2>/dev/null || find wavefront/client -name "axios.ts" -exec cat -n {} \;Repository: rootflo/wavefront
Length of output: 2331
🏁 Script executed:
cat -n wavefront/client/src/config/env.ts 2>/dev/null || find wavefront/client -name "env.ts" -exec cat -n {} \;Repository: rootflo/wavefront
Length of output: 709
🏁 Script executed:
rg "VITE_BASE_URL|baseURL" wavefront/client --type ts --type js -A 2 -B 2 | head -50Repository: rootflo/wavefront
Length of output: 1297
🏁 Script executed:
find wavefront/client -name "*.env*" -o -name ".env" | head -10Repository: rootflo/wavefront
Length of output: 89
🏁 Script executed:
cat -n wavefront/client/src/main.ts 2>/dev/null || find wavefront/client/src -name "main.ts" -exec cat -n {} \;Repository: rootflo/wavefront
Length of output: 43
🏁 Script executed:
cat -n wavefront/client/.env.sampleRepository: rootflo/wavefront
Length of output: 282
🏁 Script executed:
find wavefront/client -name "*.env*" -type f -exec cat -n {} \;Repository: rootflo/wavefront
Length of output: 282
🏁 Script executed:
find wavefront/client -name "*prod*" -o -name "*production*" | grep -E "\.(env|config|ts|js)$"Repository: rootflo/wavefront
Length of output: 43
🏁 Script executed:
cat -n wavefront/client/vite.config.ts 2>/dev/null || find wavefront/client -name "vite.config.*" -exec cat -n {} \;Repository: rootflo/wavefront
Length of output: 549
🏁 Script executed:
find wavefront -name "docker*" -o -name "*compose*" | head -10Repository: rootflo/wavefront
Length of output: 120
🏁 Script executed:
cat -n wavefront/server/docker-compose.yml | head -100Repository: rootflo/wavefront
Length of output: 933
🏁 Script executed:
find wavefront/server/docker -type f -name "*.env*" -o -name "*.sh" | head -10Repository: rootflo/wavefront
Length of output: 43
🏁 Script executed:
rg "https://" wavefront/client --type ts --type js | head -20Repository: rootflo/wavefront
Length of output: 2192
🏁 Script executed:
rg "protocol|https|http" wavefront/client/src/lib/axios.tsRepository: rootflo/wavefront
Length of output: 43
🏁 Script executed:
find wavefront -name "README*" -o -name "DEPLOYMENT*" | xargs grep -l "HTTPS\|https" 2>/dev/null | head -5Repository: rootflo/wavefront
Length of output: 156
🏁 Script executed:
grep -i "https\|security\|password" wavefront/README.md | head -20Repository: rootflo/wavefront
Length of output: 500
🏁 Script executed:
cat -n wavefront/client/public/config.jsRepository: rootflo/wavefront
Length of output: 200
HTTPS is environment-configured but not code-enforced; consider adding runtime validation in production.
The axios instance relies on environment configuration for HTTPS enforcement rather than explicit code-level validation. Local development uses http://localhost:8002 while staging uses https://console.staging.rootflo.ai, but there is no runtime check preventing misconfiguration. Since passwords are transmitted in request bodies for the createUser and updateUser methods, consider adding a guard to validate that the baseURL uses HTTPS in production environments, or document this as an operational requirement.
🤖 Prompt for AI Agents
In @wavefront/client/src/api/user-service.ts around lines 27-54, Add a runtime
guard in user-service.ts to ensure the HTTP client uses HTTPS in production:
detect the runtime environment (e.g., NODE_ENV === "production") and validate
the axios/baseURL used by this.http before sending sensitive requests from
createUser and updateUser; if the baseURL is not HTTPS, throw or reject with a
clear error (or fail-fast during service initialization) so passwords are never
sent over plain HTTP in production. Ensure the check references the existing
this.http or its configured baseURL and runs at service construction or at the
start of createUser/updateUser to prevent accidental insecure transmissions.
| useEffect(() => { | ||
| if (!isOpen) { | ||
| form.reset(); | ||
| } | ||
| }, [isOpen, form]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Remove form from the useEffect dependency array.
Including the form object in the dependency array can cause the effect to run on every render since the form object reference may change. The effect should only run when isOpen changes.
🔎 Proposed fix
useEffect(() => {
if (!isOpen) {
form.reset();
}
- }, [isOpen, form]);
+ }, [isOpen, form.reset]);Even better, use the callback form to avoid the dependency entirely:
useEffect(() => {
if (!isOpen) {
form.reset();
}
- }, [isOpen, form]);
+ }, [isOpen]); // eslint-disable-line react-hooks/exhaustive-depsThe second approach is safer since form.reset is stable across renders in react-hook-form v7+.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| useEffect(() => { | |
| if (!isOpen) { | |
| form.reset(); | |
| } | |
| }, [isOpen, form]); | |
| useEffect(() => { | |
| if (!isOpen) { | |
| form.reset(); | |
| } | |
| }, [isOpen, form.reset]); |
🤖 Prompt for AI Agents
In @wavefront/client/src/pages/apps/[appId]/users/CreateUserDialog.tsx around
lines 40-44, Remove the `form` object from the useEffect dependency array so the
effect only runs when `isOpen` changes; update the useEffect wrapping the
`form.reset()` call in CreateUserDialog to depend solely on `isOpen` (or,
alternatively, call `form.reset` via a stable callback provided by
react-hook-form v7+ so no changing `form` reference is required).
| // Determine permissions - placeholder for super admin check | ||
| // In a real implementation, this should come from the backend | ||
| const isSuperAdmin = useMemo(() => { | ||
| // Placeholder: assume all users with access to this page are super admins | ||
| // In production, add a dedicated endpoint or include this in whoami response | ||
| return true; | ||
| }, [currentUser]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, locate and read the affected file
find . -type f -name "index.tsx" -path "*/users/*" | head -20Repository: rootflo/wavefront
Length of output: 118
🏁 Script executed:
# Search for files in the apps directory structure
fd -t f "users" | grep -E "index.tsx|users\.tsx" | head -20Repository: rootflo/wavefront
Length of output: 43
🏁 Script executed:
# List the directory structure to understand the path
find . -type d -name "apps" 2>/dev/null | head -5Repository: rootflo/wavefront
Length of output: 118
🏁 Script executed:
# Read the file to see the actual implementation
cat -n ./wavefront/client/src/pages/apps/[appId]/users/index.tsx | head -80Repository: rootflo/wavefront
Length of output: 3793
🏁 Script executed:
# Check authorization in backend - find user management endpoints
find ./wavefront/server -type f \( -name "*.py" -o -name "*.js" -o -name "*.ts" \) | grep -E "(user|auth)" | head -20Repository: rootflo/wavefront
Length of output: 1665
🏁 Script executed:
# Read the user controller to check authorization
cat -n ./wavefront/server/apps/floconsole/floconsole/controllers/user_controller.pyRepository: rootflo/wavefront
Length of output: 12069
🏁 Script executed:
# Read user service to check authorization logic
cat -n ./wavefront/server/apps/floconsole/floconsole/services/user_service.pyRepository: rootflo/wavefront
Length of output: 1913
🏁 Script executed:
# Check the authorization requirement decorator
cat -n ./wavefront/server/apps/floconsole/floconsole/authorization/require_auth.pyRepository: rootflo/wavefront
Length of output: 6039
🚨 CRITICAL: Multiple authorization bypass vulnerabilities in user management API.
The frontend's hardcoded isSuperAdmin = true allows all users to see edit/delete UI controls, but the actual critical issues are in the backend:
- POST /users (create_user) has NO authorization checks—anyone can create users
- GET /users (list_users) has NO authorization checks—anyone can list all users
- GET /whoami does not return role/super admin status, preventing the frontend from making informed permission decisions
While the PATCH and DELETE endpoints enforce proper backend authorization (users can only edit themselves or super admins can edit anyone), the unprotected create and list operations allow unauthorized access to sensitive user data and account creation.
Required fixes:
- Add authorization checks to POST /users and GET /users endpoints to restrict access to super admins only
- Include role/super admin status in the whoami endpoint response
- Update the frontend's IUser interface to include role information
- Replace the hardcoded
isSuperAdmin = truewith actual role data from the backend - Ensure all user management operations enforce authorization at both frontend and backend levels
🤖 Prompt for AI Agents
In @wavefront/client/src/pages/apps/[appId]/users/index.tsx around lines 34-40,
The backend lacks authorization on create_user (POST /users) and list_users (GET
/users) and whoami doesn't return role info; update the create_user and
list_users handlers to require super-admin privileges (add or call existing auth
middleware/guard that checks is_super_admin on the request user) and ensure they
return 403 for unauthorized callers, modify the whoami handler to include
role/super_admin flags in its response, update the frontend IUser interface to
include role/superAdmin (or equivalent) fields, and replace the hardcoded
isSuperAdmin useMemo in users/index.tsx with a real check against
currentUser.role/currentUser.superAdmin from whoami; ensure both frontend UI
controls and backend endpoints consistently enforce the same super-admin rule.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.