mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 12:58:13 +00:00
88 lines
3.2 KiB
TypeScript
88 lines
3.2 KiB
TypeScript
import { EDR_FREIGHT_PERMISSIONS } from './edr-freight.seed';
|
|
import {
|
|
NOTIFICATION_PERMISSIONS,
|
|
NOTIFICATION_PERMISSION_ANCHORS,
|
|
readTwinOf,
|
|
} from './freight-permissions.registry';
|
|
|
|
describe('EDR_FREIGHT_PERMISSIONS', () => {
|
|
// The seeder inserts the whole catalog in one ON CONFLICT (key) DO UPDATE
|
|
// statement — a duplicated key there is a Postgres 21000 at boot, not a
|
|
// silent no-op.
|
|
it('has no duplicate keys', () => {
|
|
const keys = EDR_FREIGHT_PERMISSIONS.map((permission) => permission.key);
|
|
const duplicates = [...new Set(keys.filter((key, i) => keys.indexOf(key) !== i))];
|
|
|
|
expect(duplicates).toEqual([]);
|
|
});
|
|
|
|
// The `:read` ids are derived rather than hand-written, so a collision
|
|
// would surface here instead of as a primary-key violation on a fresh
|
|
// database.
|
|
it('has no duplicate ids', () => {
|
|
const ids = EDR_FREIGHT_PERMISSIONS.map((permission) => permission.id);
|
|
const duplicates = [...new Set(ids.filter((id, i) => ids.indexOf(id) !== i))];
|
|
|
|
expect(duplicates).toEqual([]);
|
|
});
|
|
|
|
// `:read` grants a module's GET routes without putting it in the backoffice
|
|
// sidebar. Every `:view` needs its twin or that module has no way to be
|
|
// granted API-only access.
|
|
it('gives every :view key a :read twin', () => {
|
|
const keys = new Set(EDR_FREIGHT_PERMISSIONS.map((p) => p.key));
|
|
const missing = [...keys]
|
|
.filter((key) => key.endsWith(':view'))
|
|
.map((key) => readTwinOf(key))
|
|
.filter((twin): twin is string => twin !== null && !keys.has(twin));
|
|
|
|
expect(missing).toEqual([]);
|
|
});
|
|
|
|
it('mints every :read id in the v5 block', () => {
|
|
const reads = EDR_FREIGHT_PERMISSIONS.filter((p) => p.key.endsWith(':read'));
|
|
|
|
expect(reads.length).toBeGreaterThan(0);
|
|
// Version nibble 5 — the source `:view` ids are all v4, so the two sets
|
|
// cannot overlap however many keys are added.
|
|
for (const read of reads) {
|
|
expect(read.id).toMatch(
|
|
/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/,
|
|
);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('NOTIFICATION_PERMISSION_ANCHORS', () => {
|
|
const catalog = new Set(EDR_FREIGHT_PERMISSIONS.map((p) => p.key));
|
|
|
|
// FreightNotificationPermissionsSeeder backfills each get_notification key
|
|
// onto whoever holds its anchor. A typo'd anchor matches no permission row,
|
|
// so the key is granted to nobody and every notification on that desk
|
|
// silently resolves to zero recipients — notify() logs that at debug level.
|
|
it('anchors every notification key on keys that exist', () => {
|
|
const missing = Object.values(NOTIFICATION_PERMISSION_ANCHORS)
|
|
.flat()
|
|
.filter((key) => !catalog.has(key));
|
|
|
|
expect(missing).toEqual([]);
|
|
});
|
|
|
|
it('seeds every notification key into the catalog', () => {
|
|
const missing = NOTIFICATION_PERMISSIONS.map((p) => p.key).filter(
|
|
(key) => !catalog.has(key),
|
|
);
|
|
|
|
expect(missing).toEqual([]);
|
|
});
|
|
|
|
it('gives every notification key an anchor to backfill from', () => {
|
|
const anchored = new Set(Object.keys(NOTIFICATION_PERMISSION_ANCHORS));
|
|
const unanchored = NOTIFICATION_PERMISSIONS.map((p) => p.key).filter(
|
|
(key) => !anchored.has(key),
|
|
);
|
|
|
|
expect(unanchored).toEqual([]);
|
|
});
|
|
});
|