Skip to content

Commit dc37a00

Browse files
committed
feat(auth): add apiKey resource and permissions to roles and decorators
1 parent 8f5b93c commit dc37a00

8 files changed

Lines changed: 4528 additions & 2808 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ yarn-error.log*
4040
# turbo
4141
.turbo
4242

43+
# claude code - personal settings and memory (commands/ is shared)
44+
.claude/settings.local.json
45+
.claude/projects/
46+
4347
# react-email
4448
.react-email
4549
packages/email/public

apps/api/src/auth/auth.server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const statement = {
3939
finding: ['create', 'read', 'update', 'delete'],
4040
questionnaire: ['create', 'read', 'update', 'delete', 'respond'],
4141
integration: ['create', 'read', 'update', 'delete'],
42+
apiKey: ['create', 'read', 'delete'],
4243
app: ['read'],
4344
trust: ['read', 'update'],
4445
} as const;
@@ -59,6 +60,7 @@ const owner = ac.newRole({
5960
finding: ['create', 'read', 'update', 'delete'],
6061
questionnaire: ['create', 'read', 'update', 'delete', 'respond'],
6162
integration: ['create', 'read', 'update', 'delete'],
63+
apiKey: ['create', 'read', 'delete'],
6264
app: ['read'],
6365
trust: ['read', 'update'],
6466
});
@@ -77,6 +79,7 @@ const admin = ac.newRole({
7779
finding: ['create', 'read', 'update', 'delete'],
7880
questionnaire: ['create', 'read', 'update', 'delete', 'respond'],
7981
integration: ['create', 'read', 'update', 'delete'],
82+
apiKey: ['create', 'read', 'delete'],
8083
app: ['read'],
8184
trust: ['read', 'update'],
8285
});

apps/api/src/auth/require-permission.decorator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export type GRCResource =
6565
| 'finding'
6666
| 'questionnaire'
6767
| 'integration'
68+
| 'apiKey'
6869
| 'cloud-security'
6970
| 'training'
7071
| 'app'

apps/api/src/auth/service-token.config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ export const SERVICE_DEFINITIONS: Record<string, ServiceDefinition> = {
2929
name: 'Portal App',
3030
permissions: ['training:read', 'training:update'],
3131
},
32+
trust: {
33+
envVar: 'SERVICE_TOKEN_TRUST',
34+
name: 'Trust Portal',
35+
permissions: [
36+
'trust:read',
37+
'organization:read',
38+
'questionnaire:read',
39+
'questionnaire:respond',
40+
],
41+
},
3242
};
3343

3444
/**

apps/api/src/organization/organization.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ export class OrganizationController {
285285
}
286286

287287
@Get('primary-color')
288-
@RequirePermission('organization', 'read')
288+
@UseGuards() // Override class-level guards — public endpoint for trust portal (uses token or auth)
289289
@ApiOperation(ORGANIZATION_OPERATIONS.getPrimaryColor)
290290
@ApiQuery({
291291
name: 'token',

apps/api/src/roles/roles.service.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const VALID_RESOURCES: Record<string, string[]> = {
1919
finding: ['create', 'read', 'update', 'delete'],
2020
questionnaire: ['create', 'read', 'update', 'delete', 'respond'],
2121
integration: ['create', 'read', 'update', 'delete'],
22+
apiKey: ['create', 'read', 'delete'],
2223
app: ['read'],
2324
trust: ['read', 'update'],
2425
};

apps/app/src/app/(app)/[orgId]/settings/roles/components/PermissionMatrix.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
* These map to the permission resources defined in @auth/permissions.ts
1212
*/
1313
const RESOURCES = [
14+
{ key: 'organization', label: 'Organization', description: 'Manage organization settings' },
15+
{ key: 'member', label: 'Members', description: 'Manage team members and roles' },
1416
{ key: 'control', label: 'Controls', description: 'Manage security controls' },
1517
{ key: 'evidence', label: 'Evidence', description: 'Manage compliance evidence' },
1618
{ key: 'policy', label: 'Policies', description: 'Manage organizational policies' },
@@ -22,6 +24,8 @@ const RESOURCES = [
2224
{ key: 'finding', label: 'Findings', description: 'Manage audit findings' },
2325
{ key: 'questionnaire', label: 'Questionnaires', description: 'Manage security questionnaires' },
2426
{ key: 'integration', label: 'Integrations', description: 'Manage third-party integrations' },
27+
{ key: 'apiKey', label: 'API Keys', description: 'Manage API keys for programmatic access' },
28+
{ key: 'trust', label: 'Trust Center', description: 'Manage trust portal and access requests' },
2529
] as const;
2630

2731
type ResourceKey = (typeof RESOURCES)[number]['key'];
@@ -38,6 +42,14 @@ type AccessLevel = 'none' | 'view' | 'edit';
3842
* Maps access levels to the actual permission actions for each resource
3943
*/
4044
const ACCESS_LEVEL_MAPPING: Record<ResourceKey, Record<Exclude<AccessLevel, 'none'>, string[]>> = {
45+
organization: {
46+
view: ['read'],
47+
edit: ['read', 'update'],
48+
},
49+
member: {
50+
view: ['read'],
51+
edit: ['create', 'read', 'update', 'delete'],
52+
},
4153
control: {
4254
view: ['read', 'export'],
4355
edit: ['create', 'read', 'update', 'delete', 'assign', 'export'],
@@ -82,6 +94,14 @@ const ACCESS_LEVEL_MAPPING: Record<ResourceKey, Record<Exclude<AccessLevel, 'non
8294
view: ['read'],
8395
edit: ['create', 'read', 'update', 'delete'],
8496
},
97+
apiKey: {
98+
view: ['read'],
99+
edit: ['create', 'read', 'delete'],
100+
},
101+
trust: {
102+
view: ['read'],
103+
edit: ['read', 'update'],
104+
},
85105
};
86106

87107
interface PermissionMatrixProps {

0 commit comments

Comments
 (0)