Skip to content

Commit 51ef5cd

Browse files
committed
feat: add alias permissions to RBAC
1 parent 98fe65b commit 51ef5cd

File tree

4 files changed

+87
-5
lines changed

4 files changed

+87
-5
lines changed

src/roles/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Role as WeaviateRole,
66
} from '../openapi/types.js';
77
import {
8+
AliasPermission,
89
BackupsPermission,
910
ClusterPermission,
1011
CollectionsPermission,
@@ -150,6 +151,32 @@ const roles = (connection: ConnectionREST): Roles => {
150151
};
151152

152153
export const permissions = {
154+
/**
155+
* Create a set of permissions specific to Weaviate's collection aliasing functionality.
156+
*
157+
* For all collections, provide the `collection` argument as `'*'`.
158+
*
159+
* @param {string | string[]} [args.alias] Aliases to create permissions for.
160+
* @returns {BackupsPermission[]} The permissions for the specified collections.
161+
*/
162+
aliases: (args: {
163+
alias: string | string[];
164+
create?: boolean;
165+
read?: boolean;
166+
update?: boolean;
167+
delete?: boolean;
168+
}): AliasPermission[] => {
169+
const aliases = Array.isArray(args.alias) ? args.alias : [args.alias];
170+
return aliases.flatMap((alias) => {
171+
const out: AliasPermission = { alias, actions: [] };
172+
if (args.create) out.actions.push('create_aliases');
173+
if (args.read) out.actions.push('read_aliases');
174+
if (args.update) out.actions.push('update_aliases');
175+
if (args.delete) out.actions.push('delete_aliases');
176+
return out;
177+
});
178+
},
179+
153180
/**
154181
* Create a set of permissions specific to Weaviate's backup functionality.
155182
*

src/roles/integration.test.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ type TestCase = {
1616
roleName: string;
1717
permissions: Permission[];
1818
expected: Role;
19+
requireVersion?: [number, number, number];
1920
};
2021

2122
const emptyPermissions = {
23+
aliasPermissions: [],
2224
backupsPermissions: [],
2325
clusterPermissions: [],
2426
collectionsPermissions: [],
@@ -277,6 +279,20 @@ const testCases: TestCase[] = [
277279
usersPermissions: [{ users: 'some-user', actions: ['assign_and_revoke_users', 'read_users'] }],
278280
},
279281
},
282+
{
283+
roleName: 'aliases',
284+
requireVersion: [1, 32, 0],
285+
permissions: weaviate.permissions.aliases({
286+
alias: 'SomeAlias',
287+
create: true,
288+
delete: true,
289+
}),
290+
expected: {
291+
name: 'aliases',
292+
...emptyPermissions,
293+
aliasPermissions: [{ alias: 'SomeAlias', actions: ['create_aliases', 'delete_aliases'] }],
294+
}
295+
},
280296
];
281297

282298
requireAtLeast(1, 29, 0).describe('Integration testing of the roles namespace', () => {
@@ -345,11 +361,13 @@ requireAtLeast(1, 29, 0).describe('Integration testing of the roles namespace',
345361

346362
describe('should be able to create roles using the permissions factory', () => {
347363
testCases.forEach((testCase) => {
348-
it(`with ${testCase.roleName} permissions`, async () => {
349-
await client.roles.create(testCase.roleName, testCase.permissions);
350-
const role = await client.roles.byName(testCase.roleName);
351-
expect(role).toEqual(testCase.expected);
352-
});
364+
(testCase.requireVersion !== undefined
365+
? requireAtLeast(...testCase.requireVersion).it
366+
: it)(`with ${testCase.roleName} permissions`, async () => {
367+
await client.roles.create(testCase.roleName, testCase.permissions);
368+
const role = await client.roles.byName(testCase.roleName);
369+
expect(role).toEqual(testCase.expected);
370+
});
353371
});
354372
});
355373

src/roles/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Action, WeaviateUserType } from '../openapi/types.js';
22

3+
export type AliasAction = Extract<Action, 'create_aliases' | 'read_aliases' | 'update_aliases' | 'delete_aliases'>;
34
export type BackupsAction = Extract<Action, 'manage_backups'>;
45
export type ClusterAction = Extract<Action, 'read_cluster'>;
56
export type CollectionsAction = Extract<
@@ -27,6 +28,11 @@ export type UserAssignment = {
2728
userType: WeaviateUserType;
2829
};
2930

31+
export type AliasPermission = {
32+
alias: string;
33+
actions: AliasAction[];
34+
}
35+
3036
export type BackupsPermission = {
3137
collection: string;
3238
actions: BackupsAction[];
@@ -71,6 +77,7 @@ export type UsersPermission = {
7177

7278
export type Role = {
7379
name: string;
80+
aliasPermissions: AliasPermission[];
7481
backupsPermissions: BackupsPermission[];
7582
clusterPermissions: ClusterPermission[];
7683
collectionsPermissions: CollectionsPermission[];
@@ -82,6 +89,7 @@ export type Role = {
8289
};
8390

8491
export type Permission =
92+
| AliasPermission
8593
| BackupsPermission
8694
| ClusterPermission
8795
| CollectionsPermission

src/roles/util.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
} from '../openapi/types.js';
88
import { User, UserDB } from '../users/types.js';
99
import {
10+
AliasAction,
11+
AliasPermission,
1012
BackupsAction,
1113
BackupsPermission,
1214
ClusterAction,
@@ -35,6 +37,14 @@ const ZERO_TIME = '0001-01-01T00:00:00.000Z';
3537
export class PermissionGuards {
3638
private static includes = <A extends string>(permission: Permission, ...actions: A[]): boolean =>
3739
actions.filter((a) => Array.from<string>(permission.actions).includes(a)).length > 0;
40+
static isAlias = (permission: Permission): permission is AliasPermission =>
41+
PermissionGuards.includes<AliasAction>(
42+
permission,
43+
'create_aliases',
44+
'read_aliases',
45+
'update_aliases',
46+
'delete_aliases',
47+
);
3848
static isBackups = (permission: Permission): permission is BackupsPermission =>
3949
PermissionGuards.includes<BackupsAction>(permission, 'manage_backups');
4050
static isCluster = (permission: Permission): permission is ClusterPermission =>
@@ -94,6 +104,12 @@ export class Map {
94104
!Array.isArray(permissions) ? [permissions] : permissions.flat(2);
95105

96106
static permissionToWeaviate = (permission: Permission): WeaviatePermission[] => {
107+
if (PermissionGuards.isAlias(permission)) {
108+
return Array.from(permission.actions).map((action) => ({
109+
aliases: permission,
110+
action,
111+
}));
112+
}
97113
if (PermissionGuards.isBackups(permission)) {
98114
return Array.from(permission.actions).map((action) => ({
99115
backups: permission,
@@ -178,6 +194,7 @@ class PermissionsMapping {
178194

179195
private constructor(role: WeaviateRole) {
180196
this.mappings = {
197+
aliases: {},
181198
backups: {},
182199
cluster: {},
183200
collections: {},
@@ -200,6 +217,7 @@ class PermissionsMapping {
200217
}
201218
return {
202219
name: this.role.name,
220+
aliasPermissions: Object.values(this.mappings.aliases),
203221
backupsPermissions: Object.values(this.mappings.backups),
204222
clusterPermissions: Object.values(this.mappings.cluster),
205223
collectionsPermissions: Object.values(this.mappings.collections),
@@ -211,6 +229,15 @@ class PermissionsMapping {
211229
};
212230
};
213231

232+
private aliases = (permission: WeaviatePermission) => {
233+
if (permission.aliases !== undefined) {
234+
const key = permission.aliases.alias;
235+
if (key === undefined) throw new Error('Alias permission missing an alias');
236+
if (this.mappings.aliases[key] === undefined) this.mappings.aliases[key] = { alias: key, actions: [] };
237+
this.mappings.aliases[key].actions.push(permission.action as AliasAction);
238+
}
239+
}
240+
214241
private backups = (permission: WeaviatePermission) => {
215242
if (permission.backups !== undefined) {
216243
const key = permission.backups.collection;
@@ -295,6 +322,7 @@ class PermissionsMapping {
295322
};
296323

297324
private permissionFromWeaviate = (permission: WeaviatePermission) => {
325+
this.aliases(permission);
298326
this.backups(permission);
299327
this.cluster(permission);
300328
this.collections(permission);
@@ -307,6 +335,7 @@ class PermissionsMapping {
307335
}
308336

309337
type PermissionMappings = {
338+
aliases: Record<string, AliasPermission>;
310339
backups: Record<string, BackupsPermission>;
311340
cluster: Record<string, ClusterPermission>;
312341
collections: Record<string, CollectionsPermission>;

0 commit comments

Comments
 (0)