Ignore permissions for admin users

This commit is contained in:
rijkvanzanten
2020-07-15 16:56:55 -04:00
parent 046345c1e8
commit ca1152b176
17 changed files with 142 additions and 28 deletions

View File

@@ -13,6 +13,7 @@ router.get(
asyncHandler(async (req, res) => {
const records = await ActivityService.readActivities(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({
@@ -28,6 +29,7 @@ router.get(
asyncHandler(async (req, res) => {
const record = await ActivityService.readActivity(req.params.pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({
@@ -51,6 +53,7 @@ router.post(
const record = await ActivityService.readActivity(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({
@@ -66,6 +69,7 @@ router.patch(
asyncHandler(async (req, res) => {
const primaryKey = await ActivityService.updateActivity(req.params.pk, req.body, {
role: req.role,
admin: req.admin,
user: req.user,
ip: req.ip,
userAgent: req.get('user-agent'),
@@ -73,6 +77,7 @@ router.patch(
const record = await ActivityService.readActivity(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({
@@ -87,6 +92,7 @@ router.delete(
asyncHandler(async (req, res) => {
await ActivityService.deleteActivity(req.params.pk, {
role: req.role,
admin: req.admin,
user: req.user,
ip: req.ip,
userAgent: req.get('user-agent'),

View File

@@ -32,6 +32,7 @@ router.post(
const createdCollection = await CollectionsService.create(req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -48,6 +49,7 @@ router.get(
asyncHandler(async (req, res) => {
const collections = await CollectionsService.readAll(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
res.json({ data: collections || null });
})
@@ -65,7 +67,7 @@ router.get(
const collection = await CollectionsService.readOne(
req.params.collection,
req.sanitizedQuery,
{ role: req.role }
{ role: req.role, admin: req.admin }
);
res.json({ data: collection || null });
})
@@ -81,6 +83,7 @@ router.delete(
await CollectionsService.deleteCollection(req.params.collection, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -74,6 +74,7 @@ router.post(
const createdField = await FieldsService.createField(req.collection, field, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -57,12 +57,14 @@ const multipartHandler = (operation: 'create' | 'update') =>
if (operation === 'create') {
const pk = await FilesService.createFile(payload, fileStream, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const file = await FilesService.readFile(pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
savedFiles.push(file);
@@ -72,6 +74,7 @@ const multipartHandler = (operation: 'create' | 'update') =>
payload,
{
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -80,6 +83,7 @@ const multipartHandler = (operation: 'create' | 'update') =>
);
const file = await FilesService.readFile(pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
savedFiles.push(file);
@@ -106,7 +110,10 @@ router.get(
'/',
sanitizeQuery,
asyncHandler(async (req, res) => {
const records = await FilesService.readFiles(req.sanitizedQuery, { role: req.role });
const records = await FilesService.readFiles(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: records || null });
})
);
@@ -117,6 +124,7 @@ router.get(
asyncHandler(async (req, res) => {
const record = await FilesService.readFile(req.params.pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: record || null });
})
@@ -133,11 +141,15 @@ router.patch(
} else {
const pk = await FilesService.updateFile(req.params.pk, req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
file = await FilesService.readFile(pk, req.sanitizedQuery, { role: req.role });
file = await FilesService.readFile(pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
}
return res.status(200).json({ data: file || null });
@@ -149,6 +161,7 @@ router.delete(
asyncHandler(async (req, res) => {
await FilesService.deleteFile(req.params.pk, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -13,6 +13,7 @@ router.post(
asyncHandler(async (req, res) => {
const primaryKey = await FoldersService.createFolder(req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -20,6 +21,7 @@ router.post(
const record = await FoldersService.readFolder(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: record || null });
})
@@ -29,7 +31,10 @@ router.get(
'/',
sanitizeQuery,
asyncHandler(async (req, res) => {
const records = await FoldersService.readFolders(req.sanitizedQuery, { role: req.role });
const records = await FoldersService.readFolders(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: records || null });
})
);
@@ -40,6 +45,7 @@ router.get(
asyncHandler(async (req, res) => {
const record = await FoldersService.readFolder(req.params.pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: record || null });
})
@@ -51,6 +57,7 @@ router.patch(
asyncHandler(async (req, res) => {
const primaryKey = await FoldersService.updateFolder(req.params.pk, req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -58,6 +65,7 @@ router.patch(
const record = await FoldersService.readFolder(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: record || null });
@@ -69,6 +77,7 @@ router.delete(
asyncHandler(async (req, res) => {
await FoldersService.deleteFolder(req.params.pk, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -20,12 +20,14 @@ router.post(
const primaryKey = await ItemsService.createItem(req.collection, req.body, {
user: req.user,
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
});
const item = await ItemsService.readItem(req.collection, primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
res.json({ data: item || null });
@@ -39,8 +41,14 @@ router.get(
asyncHandler(async (req, res) => {
const [records, meta] = await Promise.all([
req.single
? ItemsService.readSingleton(req.collection, req.sanitizedQuery, { role: req.role })
: ItemsService.readItems(req.collection, req.sanitizedQuery, { role: req.role }),
? ItemsService.readSingleton(req.collection, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
})
: ItemsService.readItems(req.collection, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
}),
MetaService.getMetaForQuery(req.collection, req.sanitizedQuery),
]);
@@ -64,7 +72,7 @@ router.get(
req.collection,
req.params.pk,
req.sanitizedQuery,
{ role: req.role }
{ role: req.role, admin: req.admin }
);
return res.json({
@@ -84,6 +92,7 @@ router.patch(
await ItemsService.upsertSingleton(req.collection, req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -91,6 +100,7 @@ router.patch(
const item = await ItemsService.readSingleton(req.collection, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
@@ -108,6 +118,7 @@ router.patch(
const primaryKey = await ItemsService.updateItem(req.collection, req.params.pk, req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -115,6 +126,7 @@ router.patch(
const item = await ItemsService.readItem(req.collection, primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
@@ -127,6 +139,7 @@ router.delete(
asyncHandler(async (req, res) => {
await ItemsService.deleteItem(req.collection, req.params.pk, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -13,6 +13,7 @@ router.post(
asyncHandler(async (req, res) => {
const primaryKey = await PermissionsService.createPermission(req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -20,6 +21,7 @@ router.post(
const item = await PermissionsService.readPermission(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
@@ -32,6 +34,7 @@ router.get(
asyncHandler(async (req, res) => {
const item = await PermissionsService.readPermissions(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
@@ -44,7 +47,7 @@ router.get(
const record = await PermissionsService.readPermission(
Number(req.params.pk),
req.sanitizedQuery,
{ role: req.role }
{ role: req.role, admin: req.admin }
);
return res.json({ data: record || null });
})
@@ -58,6 +61,7 @@ router.patch(
req.body,
{
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -66,6 +70,7 @@ router.patch(
const item = await PermissionsService.readPermission(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
@@ -77,6 +82,7 @@ router.delete(
asyncHandler(async (req, res) => {
await PermissionsService.deletePermission(Number(req.params.pk), {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -13,6 +13,7 @@ router.post(
asyncHandler(async (req, res) => {
const primaryKey = await CollectionPresetsService.createCollectionPreset(req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -21,7 +22,7 @@ router.post(
const record = await CollectionPresetsService.readCollectionPreset(
primaryKey,
req.sanitizedQuery,
{ role: req.role }
{ role: req.role, admin: req.admin }
);
return res.json({ data: record || null });
})
@@ -33,6 +34,7 @@ router.get(
asyncHandler(async (req, res) => {
const records = await CollectionPresetsService.readCollectionPresets(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: records || null });
})
@@ -45,7 +47,7 @@ router.get(
const record = await CollectionPresetsService.readCollectionPreset(
req.params.pk,
req.sanitizedQuery,
{ role: req.role }
{ role: req.role, admin: req.admin }
);
return res.json({ data: record || null });
})
@@ -60,6 +62,7 @@ router.patch(
req.body,
{
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -69,7 +72,7 @@ router.patch(
const record = await CollectionPresetsService.readCollectionPreset(
primaryKey,
req.sanitizedQuery,
{ role: req.role }
{ role: req.role, admin: req.admin }
);
return res.json({ data: record || null });
})
@@ -80,6 +83,7 @@ router.delete(
asyncHandler(async (req, res) => {
await CollectionPresetsService.deleteCollectionPreset(req.params.pk, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -14,12 +14,14 @@ router.post(
asyncHandler(async (req, res) => {
const primaryKey = await RelationsService.createRelation(req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const item = await RelationsService.readRelation(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
@@ -31,6 +33,7 @@ router.get(
asyncHandler(async (req, res) => {
const records = await RelationsService.readRelations(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: records || null });
})
@@ -42,6 +45,7 @@ router.get(
asyncHandler(async (req, res) => {
const record = await RelationsService.readRelation(req.params.pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: record || null });
})
@@ -53,12 +57,14 @@ router.patch(
asyncHandler(async (req, res) => {
const primaryKey = await RelationsService.updateRelation(req.params.pk, req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const item = await RelationsService.readRelation(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
@@ -69,6 +75,7 @@ router.delete(
asyncHandler(async (req, res) => {
await RelationsService.deleteRelation(Number(req.params.pk), {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -14,6 +14,7 @@ router.get(
asyncHandler(async (req, res) => {
const records = await RevisionsService.readRevisions(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: records || null });
})
@@ -25,6 +26,7 @@ router.get(
asyncHandler(async (req, res) => {
const record = await RevisionsService.readRevision(req.params.pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: record || null });
})

View File

@@ -14,12 +14,14 @@ router.post(
asyncHandler(async (req, res) => {
const primaryKey = await RolesService.createRole(req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const item = await RolesService.readRole(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
@@ -29,7 +31,10 @@ router.get(
'/',
sanitizeQuery,
asyncHandler(async (req, res) => {
const records = await RolesService.readRoles(req.sanitizedQuery, { role: req.role });
const records = await RolesService.readRoles(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: records || null });
})
);
@@ -40,6 +45,7 @@ router.get(
asyncHandler(async (req, res) => {
const record = await RolesService.readRole(req.params.pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: record || null });
})
@@ -51,12 +57,14 @@ router.patch(
asyncHandler(async (req, res) => {
const primaryKey = await RolesService.updateRole(req.params.pk, req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const item = await RolesService.readRole(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
@@ -67,6 +75,7 @@ router.delete(
asyncHandler(async (req, res) => {
await RolesService.deleteRole(req.params.pk, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -11,7 +11,10 @@ router.get(
useCollection('directus_settings'),
sanitizeQuery,
asyncHandler(async (req, res) => {
const records = await SettingsService.readSettings(req.sanitizedQuery, { role: req.role });
const records = await SettingsService.readSettings(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: records || null });
})
);
@@ -23,12 +26,16 @@ router.patch(
asyncHandler(async (req, res) => {
await SettingsService.updateSettings(req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const record = await SettingsService.readSettings(req.sanitizedQuery, { role: req.role });
const record = await SettingsService.readSettings(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: record || null });
})

View File

@@ -16,12 +16,14 @@ router.post(
asyncHandler(async (req, res) => {
const primaryKey = await UsersService.createUser(req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const item = await UsersService.readUser(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
@@ -31,7 +33,10 @@ router.get(
'/',
sanitizeQuery,
asyncHandler(async (req, res) => {
const item = await UsersService.readUsers(req.sanitizedQuery, { role: req.role });
const item = await UsersService.readUsers(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
);
@@ -44,7 +49,10 @@ router.get(
throw new InvalidCredentialsException();
}
const item = await UsersService.readUser(req.user, req.sanitizedQuery, { role: req.role });
const item = await UsersService.readUser(req.user, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
);
@@ -55,6 +63,7 @@ router.get(
asyncHandler(async (req, res) => {
const items = await UsersService.readUser(req.params.pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: items || null });
})
@@ -70,6 +79,7 @@ router.patch(
const primaryKey = await UsersService.updateUser(req.user, req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -77,6 +87,7 @@ router.patch(
const item = await UsersService.readUser(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
@@ -88,12 +99,14 @@ router.patch(
asyncHandler(async (req, res) => {
const primaryKey = await UsersService.updateUser(req.params.pk, req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const item = await UsersService.readUser(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
@@ -104,6 +117,7 @@ router.delete(
asyncHandler(async (req, res) => {
await UsersService.deleteUser(req.params.pk, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -125,6 +139,7 @@ router.post(
if (error) throw new InvalidPayloadException(error.message);
await UsersService.inviteUser(req.body.email, req.body.role, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -13,6 +13,7 @@ router.post(
asyncHandler(async (req, res) => {
const primaryKey = await WebhooksService.createWebhook(req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
@@ -20,6 +21,7 @@ router.post(
const item = await WebhooksService.readWebhook(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
@@ -30,7 +32,10 @@ router.get(
'/',
sanitizeQuery,
asyncHandler(async (req, res) => {
const records = await WebhooksService.readWebhooks(req.sanitizedQuery, { role: req.role });
const records = await WebhooksService.readWebhooks(req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: records || null });
})
);
@@ -41,6 +46,7 @@ router.get(
asyncHandler(async (req, res) => {
const record = await WebhooksService.readWebhook(req.params.pk, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: record || null });
})
@@ -51,12 +57,14 @@ router.patch(
asyncHandler(async (req, res) => {
const primaryKey = await WebhooksService.updateWebhook(req.params.pk, req.body, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,
});
const item = await WebhooksService.readWebhook(primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
return res.json({ data: item || null });
})
@@ -67,6 +75,7 @@ router.delete(
asyncHandler(async (req, res) => {
await WebhooksService.deleteWebhook(req.params.pk, {
role: req.role,
admin: req.admin,
ip: req.ip,
userAgent: req.get('user-agent'),
user: req.user,

View File

@@ -48,7 +48,7 @@ export const createItem = async (
): Promise<string | number> => {
let payload = data;
if (accountability) {
if (accountability && accountability.admin === false) {
payload = await PermissionsService.processValues(
'create',
collection,
@@ -97,9 +97,9 @@ export const readItems = async <T = Record<string, any>>(
query: Query,
accountability?: Accountability
): Promise<T[]> => {
let ast = await getASTFromQuery(collection, query, accountability?.role);
let ast = await getASTFromQuery(collection, query, accountability);
if (accountability) {
if (accountability && accountability.admin === false) {
ast = await PermissionsService.processAST(ast, accountability.role);
}
@@ -130,9 +130,9 @@ export const readItem = async <T = any>(
},
};
let ast = await getASTFromQuery(collection, query, accountability?.role, operation);
let ast = await getASTFromQuery(collection, query, accountability, operation);
if (accountability) {
if (accountability && accountability.admin === false) {
ast = await PermissionsService.processAST(ast, accountability.role, operation);
}
@@ -148,7 +148,7 @@ export const updateItem = async (
): Promise<string | number> => {
let payload = data;
if (accountability) {
if (accountability && accountability.admin === false) {
await PermissionsService.checkAccess('update', collection, pk, accountability.role);
payload = await PermissionsService.processValues(
@@ -197,7 +197,7 @@ export const deleteItem = async (
) => {
const primaryKeyField = await schemaInspector.primary(collection);
if (accountability) {
if (accountability && accountability.admin === false) {
await PermissionsService.checkAccess('delete', collection, pk, accountability.role);
// Don't await this. It can run async in the background

View File

@@ -1,6 +1,8 @@
export type Accountability = {
role: string;
user?: string;
admin?: boolean;
ip?: string;
userAgent?: string;

View File

@@ -2,13 +2,21 @@
* Generate an AST based on a given collection and query
*/
import { AST, NestedCollectionAST, FieldAST, Query, Relation, Operation } from '../types';
import {
AST,
NestedCollectionAST,
FieldAST,
Query,
Relation,
Operation,
Accountability,
} from '../types';
import database from '../database';
export default async function getASTFromQuery(
collection: string,
query: Query,
role?: string | null,
accountability: Accountability | null,
operation?: Operation
): Promise<AST> {
/**
@@ -18,11 +26,11 @@ export default async function getASTFromQuery(
const relations = await database.select<Relation[]>('*').from('directus_relations');
const permissions =
role !== undefined
accountability && accountability.admin !== true
? await database
.select<{ collection: string; fields: string }[]>('collection', 'fields')
.from('directus_permissions')
.where({ role, operation: 'read' })
.where({ role: accountability.role, operation: operation || 'read' })
: null;
const ast: AST = {