-
Notifications
You must be signed in to change notification settings - Fork 248
Feat/rbac v1 #2092
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
base: main
Are you sure you want to change the base?
Feat/rbac v1 #2092
Conversation
- Update permissions.ts to extend defaultStatements from better-auth - Add GRC resources: control, evidence, policy, risk, vendor, task, framework, audit, finding, questionnaire, integration - Add program_manager role with full GRC access but no member management - Update owner/admin roles to extend ownerAc/adminAc from better-auth - Update auditor role with read + export permissions - Keep employee/contractor roles minimal with assignment-based access - Add ROLE_HIERARCHY, RESTRICTED_ROLES, PRIVILEGED_ROLES exports - Add placeholder for dynamicAccessControl in auth.ts (Sprint 2) Part of ENG-138: Complete Permission System Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create PermissionGuard that calls better-auth's hasPermission API - Add fallback role-based check when better-auth is unavailable - Create @RequirePermission decorator for route-level permission checks - Create @RequirePermissions decorator for multi-resource permissions - Export GRCResource and GRCAction types for type safety - Add program_manager to Role enum in database schema - Update AuthModule to export PermissionGuard The guard: - Validates permissions via better-auth's hasPermission endpoint - Falls back to role-based check if API unavailable - Logs warnings for API key bypass (TODO: add API key scopes) - Provides static isRestrictedRole() helper for assignment filtering Part of ENG-138: Complete Permission System Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update portal permissions.ts to match app version - Fix security issue where employee/contractor had excessive permissions - Add program_manager role to portal - Extend defaultStatements from better-auth - Add RESTRICTED_ROLES and PRIVILEGED_ROLES exports BREAKING CHANGE: Employee and contractor roles in portal now have restricted permissions matching the app. Previously they had member management and organization update permissions. Part of ENG-138: Complete Permission System Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive tests for PermissionGuard covering: - Permission bypass when no permissions required - API key bypass behavior - Role-based access for privileged vs restricted roles - Fallback behavior when better-auth API unavailable - isRestrictedRole static method for all role types Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Migrate all API controllers to use the new better-auth permission system: - findings.controller.ts: finding create/update/delete permissions - task-management.controller.ts: task CRUD + assign permissions - people.controller.ts: member delete permission for removeHost - evidence-export.controller.ts: evidence export permission Also fix TypeScript errors in permission.guard.spec.ts for fetch mocking. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement assignment filtering to restrict employees/contractors to only see resources they are assigned to: - Add memberId to AuthContext for assignment checking - Create assignment-filter utility with filter builders and access checkers - Update tasks controller/service with assignment filtering on GET endpoints - Update risks controller/service with assignment filtering on GET endpoints - Add PermissionGuard and @RequirePermission to tasks and risks endpoints Employees/contractors now only see: - Tasks where they are the assignee - Risks where they are the assignee Privileged roles (owner, admin, program_manager, auditor) see all resources. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Allow admins to control which departments can see specific policies: Schema changes: - Add PolicyVisibility enum (ALL, DEPARTMENT) - Add visibility and visibleToDepartments fields to Policy model API changes: - Add memberDepartment to AuthContext for visibility filtering - Create department-visibility utility with filter builders - Update policies controller to filter by visibility for restricted roles - Update policies service to accept visibility filter Policies can now be: - Visible to ALL (default) - everyone in the organization sees them - Visible to specific DEPARTMENTS only - only members in those departments see them Privileged roles (owner, admin, program_manager, auditor) see all policies regardless of visibility settings. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move auth server to API, app now uses proxy to forward auth requests - Remove localStorage token storage (XSS prevention) - Add rate limiting to auth proxy (60/min general, 10/min sensitive) - Add redirect URL validation to prevent open redirects - Add AUTH_SECRET validation at startup - Make all debug logging conditional on NODE_ENV - Simplify root page routing (no activeOrganizationId dependency) - Use URL-based RBAC with direct DB member lookup Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add @comp/auth package with centralized permissions and role definitions - Update API auth module to integrate with better-auth server - Add 403 responses to policy and risk endpoints for Swagger - Add assignment filter and department visibility utilities with tests - Sync permissions across app and portal - Update tsconfig and nest-cli for proper module resolution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dynamicAccessControl config to organization plugin - Add OrganizationRole table for storing custom roles - Configure maximum 20 roles per organization - Add schema mapping for better-auth role table Resolves: ENG-145 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add roles module with CRUD endpoints for custom roles - Implement privilege escalation prevention - Add permission validation against valid resources/actions - Protect built-in roles (owner, admin, auditor, employee, contractor) - Add OrganizationRole table migration - Limit to 20 custom roles per organization - Require ac:create/read/update/delete permissions for role management Implements: ENG-146 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update roles service to accept array of roles instead of single role - Add getCombinedPermissions to merge permissions from all user roles - Update controller to pass full userRoles array - Users with multiple roles now get combined permissions for validation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add explicit jwks configuration with rotationInterval to prevent better-auth from creating new JWKS keys on each request. Without this, all existing JWTs become invalid when the API restarts because new signing keys are generated. - Set rotationInterval to 30 days for monthly key rotation - Set gracePeriod to 7 days so old keys remain valid after rotation Fixes: Session persistence across API restarts References: - better-auth/better-auth#6215 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add 18 tests for RolesService covering CRUD operations - Add 9 tests for RolesController - Test permission validation and privilege escalation prevention - Test multiple roles support for privilege checking - Test edge cases (duplicate names, max roles limit, reserved names) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update .cursorrules with testing requirements and conventions - Add apps/api/CLAUDE.md with API-specific development guidelines - Document when to write tests, how to run them, and test patterns - Include RBAC system documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove API-specific testing rules from root .cursorrules - Create apps/api/.cursorrules with API testing requirements - Keep root .cursorrules focused on commit message conventions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensures that users cannot escalate privileges when updating role permissions, not just when creating roles. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add roles settings pages (list, create, edit) with permission matrix - Add "Select all" feature to quickly set all permissions - Integrate custom roles into member management UI: - Role filter dropdown shows all roles dynamically - Invite modal supports custom role selection - Edit member role supports custom roles - Allow normal spelling for role names (spaces, capitalization) - Add loading skeletons with proper PageLayout wrappers - Add comprehensive tests for RolesTable, RoleForm, PermissionMatrix Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PR SummaryHigh Risk Overview Adds a new Expands auth context to include Written by Cursor Bugbot for commit 3a9e9f1. This will update automatically on new commits. Configure here. |
| this.betterAuthUrl = | ||
| this.configService.get<string>('BETTER_AUTH_URL') || | ||
| process.env.BETTER_AUTH_URL || | ||
| ''; |
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.
PermissionGuard ignores AUTH_BASE_URL config setting
Medium Severity
The PermissionGuard reads BETTER_AUTH_URL directly instead of using the betterAuth config namespace like HybridAuthGuard does. The better-auth.config.ts prioritizes AUTH_BASE_URL over BETTER_AUTH_URL, but PermissionGuard ignores this. If only AUTH_BASE_URL is configured, permission checks will silently fall back to basic role-based checks because betterAuthUrl will be empty.
| } | ||
|
|
||
| @Post('parse/upload/token') | ||
| @UseGuards() // Override class-level guards — this endpoint uses token-based auth |
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.
Empty UseGuards doesn't override class-level guards
High Severity
The @UseGuards() decorator with no arguments on the /parse/upload/token endpoint does not override the class-level @UseGuards(HybridAuthGuard, PermissionGuard). In NestJS, method-level guards are additive, not replacing. The endpoint is intended for token-based public access from the trust portal, but will still require JWT/API key authentication, breaking the trust portal questionnaire upload feature.
|
|
||
| // Check if all roles are restricted | ||
| return roles.every((role) => RESTRICTED_ROLES.includes(role)); | ||
| } |
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.
Static isRestrictedRole duplicates existing utility function
Medium Severity
PermissionGuard.isRestrictedRole duplicates the isRestrictedRole function already exported from apps/api/src/utils/assignment-filter.ts. Both implementations have identical logic. The guard should import and use the existing utility function instead.
| const request = ctx.switchToHttp().getRequest<AuthenticatedRequest>(); | ||
| return request.memberId; | ||
| }, | ||
| ); |
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.
| | 'approve' | ||
| | 'assess' | ||
| | 'complete' | ||
| | 'respond'; |
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.
…rotection - Add functions to resolve user permissions based on roles and organization - Implement route permission checks to guard access to various app sections - Introduce new layout components for route protection across multiple pages - Update existing components to utilize the new permissions system for access control
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.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| ); | ||
| } | ||
| } | ||
| } |
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.
Missing validation for permission value types causes crash
Medium Severity
The validatePermissions method iterates over permission values with for (const action of actions) without checking that actions is actually an array. The DTO only validates that permissions is an object via @IsObject(), not that nested values are arrays. If a client sends { "permissions": { "control": null } }, the iteration throws a TypeError (null is not iterable), causing a 500 error instead of a proper 400 validation error.
Additional Locations (1)
| integration: ['create', 'read', 'update', 'delete'], | ||
| app: ['read'], | ||
| portal: ['read', 'update'], | ||
| }; |
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.
Duplicated permission definitions across auth and roles
Medium Severity
VALID_RESOURCES in roles.service.ts duplicates the permission statement object defined in auth.server.ts. Both define the same resources and actions (control, evidence, policy, risk, etc.). If permissions change, both files must be updated separately, risking inconsistency.


What does this PR do?
Visual Demo (For contributors especially)
A visual demonstration is strongly recommended, for both the original and new change (video / image - any one).
Video Demo (if applicable):
Image Demo (if applicable):
Mandatory Tasks (DO NOT REMOVE)
How should this be tested?
Checklist