@@ -5,18 +5,50 @@ export interface CedarPolicyItem {
55 tableName ?: string ;
66}
77
8- export const POLICY_ACTIONS = [
9- { value : '*' , label : 'Full access (all permissions)' , needsTable : false } ,
10- { value : 'connection:read' , label : 'Connection: Read' , needsTable : false } ,
11- { value : 'connection:edit' , label : 'Connection: Full access' , needsTable : false } ,
12- { value : 'group:read' , label : 'Group: Read' , needsTable : false } ,
13- { value : 'group:edit' , label : 'Group: Manage' , needsTable : false } ,
14- { value : 'table:read' , label : 'Table: Read' , needsTable : true } ,
15- { value : 'table:add' , label : 'Table: Add' , needsTable : true } ,
16- { value : 'table:edit' , label : 'Table: Edit' , needsTable : true } ,
17- { value : 'table:delete' , label : 'Table: Delete' , needsTable : true } ,
8+ export interface PolicyAction {
9+ value : string ;
10+ label : string ;
11+ needsTable : boolean ;
12+ }
13+
14+ export interface PolicyActionGroup {
15+ group : string ;
16+ actions : PolicyAction [ ] ;
17+ }
18+
19+ export const POLICY_ACTION_GROUPS : PolicyActionGroup [ ] = [
20+ {
21+ group : 'General' ,
22+ actions : [ { value : '*' , label : 'Full access (all permissions)' , needsTable : false } ] ,
23+ } ,
24+ {
25+ group : 'Connection' ,
26+ actions : [
27+ { value : 'connection:read' , label : 'Read' , needsTable : false } ,
28+ { value : 'connection:edit' , label : 'Full access' , needsTable : false } ,
29+ ] ,
30+ } ,
31+ {
32+ group : 'Group' ,
33+ actions : [
34+ { value : 'group:read' , label : 'Read' , needsTable : false } ,
35+ { value : 'group:edit' , label : 'Manage' , needsTable : false } ,
36+ ] ,
37+ } ,
38+ {
39+ group : 'Table' ,
40+ actions : [
41+ { value : 'table:*' , label : 'Full access' , needsTable : true } ,
42+ { value : 'table:read' , label : 'Read' , needsTable : true } ,
43+ { value : 'table:add' , label : 'Add' , needsTable : true } ,
44+ { value : 'table:edit' , label : 'Edit' , needsTable : true } ,
45+ { value : 'table:delete' , label : 'Delete' , needsTable : true } ,
46+ ] ,
47+ } ,
1848] ;
1949
50+ export const POLICY_ACTIONS : PolicyAction [ ] = POLICY_ACTION_GROUPS . flatMap ( ( g ) => g . actions ) ;
51+
2052export function permissionsToPolicyItems ( permissions : Permissions ) : CedarPolicyItem [ ] {
2153 const items : CedarPolicyItem [ ] = [ ] ;
2254
@@ -47,11 +79,7 @@ export function permissionsToPolicyItems(permissions: Permissions): CedarPolicyI
4779 const anyTableAccess = allRead || allAdd || allEdit || allDelete ;
4880
4981 if ( anyTableAccess && allRead && allAdd && allEdit && allDelete ) {
50- // All tables have full access — single wildcard per action
51- items . push ( { action : 'table:read' , tableName : '*' } ) ;
52- items . push ( { action : 'table:add' , tableName : '*' } ) ;
53- items . push ( { action : 'table:edit' , tableName : '*' } ) ;
54- items . push ( { action : 'table:delete' , tableName : '*' } ) ;
82+ items . push ( { action : 'table:*' , tableName : '*' } ) ;
5583 } else if ( anyTableAccess && ( allRead || allAdd || allEdit || allDelete ) ) {
5684 // Some actions apply to all tables, others are per-table
5785 if ( allRead ) items . push ( { action : 'table:read' , tableName : '*' } ) ;
@@ -68,10 +96,14 @@ export function permissionsToPolicyItems(permissions: Permissions): CedarPolicyI
6896 } else {
6997 for ( const table of tables ) {
7098 const access = table . accessLevel ;
71- if ( access . visibility ) items . push ( { action : 'table:read' , tableName : table . tableName } ) ;
72- if ( access . add ) items . push ( { action : 'table:add' , tableName : table . tableName } ) ;
73- if ( access . edit ) items . push ( { action : 'table:edit' , tableName : table . tableName } ) ;
74- if ( access . delete ) items . push ( { action : 'table:delete' , tableName : table . tableName } ) ;
99+ if ( access . visibility && access . add && access . edit && access . delete ) {
100+ items . push ( { action : 'table:*' , tableName : table . tableName } ) ;
101+ } else {
102+ if ( access . visibility ) items . push ( { action : 'table:read' , tableName : table . tableName } ) ;
103+ if ( access . add ) items . push ( { action : 'table:add' , tableName : table . tableName } ) ;
104+ if ( access . edit ) items . push ( { action : 'table:edit' , tableName : table . tableName } ) ;
105+ if ( access . delete ) items . push ( { action : 'table:delete' , tableName : table . tableName } ) ;
106+ }
75107 }
76108 }
77109 }
@@ -88,6 +120,19 @@ export function policyItemsToCedarPolicy(items: CedarPolicyItem[], connectionId:
88120 return policies . join ( '\n\n' ) ;
89121 }
90122
123+ // table:* expands to 4 individual table action permits
124+ if ( item . action === 'table:*' ) {
125+ const tableResource =
126+ item . tableName === '*'
127+ ? `resource like RocketAdmin::Table::"${ connectionId } /*"`
128+ : `resource == RocketAdmin::Table::"${ connectionId } /${ item . tableName } "` ;
129+ for ( const subAction of [ 'table:read' , 'table:add' , 'table:edit' , 'table:delete' ] ) {
130+ const ref = `RocketAdmin::Action::"${ subAction } "` ;
131+ policies . push ( `permit(\n principal,\n action == ${ ref } ,\n ${ tableResource } \n);` ) ;
132+ }
133+ continue ;
134+ }
135+
91136 const actionRef = `RocketAdmin::Action::"${ item . action } "` ;
92137 let resource : string ;
93138
@@ -151,6 +196,7 @@ export function policyItemsToPermissions(
151196 case 'group:edit' :
152197 result . group . accessLevel = AccessLevel . Edit ;
153198 break ;
199+ case 'table:*' :
154200 case 'table:read' :
155201 case 'table:add' :
156202 case 'table:edit' :
@@ -161,6 +207,12 @@ export function policyItemsToPermissions(
161207 for ( const table of targets ) {
162208 table . accessLevel . visibility = true ;
163209 switch ( item . action ) {
210+ case 'table:*' :
211+ table . accessLevel . readonly = true ;
212+ table . accessLevel . add = true ;
213+ table . accessLevel . edit = true ;
214+ table . accessLevel . delete = true ;
215+ break ;
164216 case 'table:read' :
165217 table . accessLevel . readonly = true ;
166218 break ;
0 commit comments