Skip to content

Commit 89ed5ac

Browse files
committed
refactor(access-control): Remove legacy role aliases and normalize role handling
1 parent 4b9d2ca commit 89ed5ac

4 files changed

Lines changed: 41 additions & 69 deletions

File tree

src/providers/authentik-provider.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,11 @@ export interface AuthentikIdentity {
4646

4747
export type AuthentikPermissions = string[]
4848
const TEST_AUTH_GROUPS: AuthentikPermissions = [
49-
'Viewer',
50-
'Editor',
51-
'AMPViewer',
52-
'AMPEditor',
53-
'LexiconEditor',
54-
'LexiconAdmin',
55-
'OcotilloAdmin',
49+
'AMP.Viewer',
50+
'AMP.Editor',
51+
'AMP.Admin',
52+
'Geothermal.Viewer',
53+
'Geothermal.Editor',
5654
]
5755
const PKCE_LOCAL_FALLBACK_TTL_MS = 5 * 60 * 1000
5856

src/test/providers/authentik-provider.access-control.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,13 @@ describe('authentik provider access-control normalization', () => {
5151

5252
it('normalizes token groups from the ID token when testing auth is disabled', async () => {
5353
vi.doMock('@/config', async () => {
54-
const actual = await vi.importActual<typeof import('@/config')>('@/config')
54+
const actual =
55+
await vi.importActual<typeof import('@/config')>('@/config')
5556
return { ...actual, IS_TESTING_AUTH: false }
5657
})
5758
vi.doMock('jwt-decode', () => ({
5859
jwtDecode: vi.fn().mockReturnValue({
59-
groups: ['Viewer', 'Geothermal.Editor', 'OcotilloAdmin'],
60+
groups: ['AMP.Viewer', 'Geothermal.Editor', 'AMP.Admin'],
6061
}),
6162
}))
6263
vi.doUnmock('@/providers/authentik-provider')
@@ -79,7 +80,8 @@ describe('authentik provider access-control normalization', () => {
7980

8081
it('returns null when there is no ID token', async () => {
8182
vi.doMock('@/config', async () => {
82-
const actual = await vi.importActual<typeof import('@/config')>('@/config')
83+
const actual =
84+
await vi.importActual<typeof import('@/config')>('@/config')
8385
return { ...actual, IS_TESTING_AUTH: false }
8486
})
8587
vi.doMock('jwt-decode', () => ({

src/test/utils/accessControl.test.ts

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ const actions: Action[] = ['list', 'show']
2424
const isRoutableResource = (
2525
resource: (typeof resources)[number]
2626
): resource is ResourceWithRoutes =>
27-
'list' in resource || 'show' in resource || 'edit' in resource || 'create' in resource
27+
'list' in resource ||
28+
'show' in resource ||
29+
'edit' in resource ||
30+
'create' in resource
2831

2932
const routableResources = resources.filter(isRoutableResource)
30-
const routableResourceNames = routableResources.map((resource) => resource.name).sort()
33+
const routableResourceNames = routableResources
34+
.map((resource) => resource.name)
35+
.sort()
3136
const expectedRegisteredRoutableResources = [
3237
'ocotillo.collections',
3338
'ocotillo.contact',
@@ -219,23 +224,13 @@ const specialResourceExpectations: Array<{
219224
]
220225

221226
describe('accessControl helpers', () => {
222-
it('normalizes legacy aliases and expands role hierarchies', () => {
223-
expect(normalizeAccessControlGroups(['Viewer'])).toEqual(['AMP.Viewer'])
224-
expect(normalizeAccessControlGroups(['Editor'])).toEqual([
227+
it('normalizes canonical roles and expands hierarchies', () => {
228+
expect(normalizeAccessControlGroups(['AMP.Viewer'])).toEqual(['AMP.Viewer'])
229+
expect(normalizeAccessControlGroups(['AMP.Editor'])).toEqual([
225230
'AMP.Viewer',
226231
'AMP.Editor',
227232
])
228-
expect(normalizeAccessControlGroups(['Admin'])).toEqual([
229-
'AMP.Viewer',
230-
'AMP.Editor',
231-
'AMP.Admin',
232-
])
233-
expect(normalizeAccessControlGroups(['AMPViewer'])).toEqual(['AMP.Viewer'])
234-
expect(normalizeAccessControlGroups(['AMPEditor'])).toEqual([
235-
'AMP.Viewer',
236-
'AMP.Editor',
237-
])
238-
expect(normalizeAccessControlGroups(['OcotilloAdmin'])).toEqual([
233+
expect(normalizeAccessControlGroups(['AMP.Admin'])).toEqual([
239234
'AMP.Viewer',
240235
'AMP.Editor',
241236
'AMP.Admin',
@@ -246,12 +241,8 @@ describe('accessControl helpers', () => {
246241
'Geothermal.Admin',
247242
])
248243
expect(
249-
normalizeAccessControlGroups(['Viewer', 'Geothermal.Editor'])
250-
).toEqual([
251-
'AMP.Viewer',
252-
'Geothermal.Viewer',
253-
'Geothermal.Editor',
254-
])
244+
normalizeAccessControlGroups(['AMP.Viewer', 'Geothermal.Editor'])
245+
).toEqual(['AMP.Viewer', 'Geothermal.Viewer', 'Geothermal.Editor'])
255246
})
256247

257248
it('derives capability flags from normalized roles', () => {
@@ -294,22 +285,22 @@ describe('accessControl helpers', () => {
294285
canViewLexicon: true,
295286
})
296287

297-
expect(getAccessCapabilities(['AMP.Admin', 'Geothermal.Editor'])).toMatchObject(
298-
{
299-
roles: [
300-
'AMP.Viewer',
301-
'AMP.Editor',
302-
'AMP.Admin',
303-
'Geothermal.Viewer',
304-
'Geothermal.Editor',
305-
],
306-
primaryRole: 'Geothermal.Editor',
307-
canManageAmp: true,
308-
canViewUnfinished: true,
309-
canEditGeothermal: true,
310-
canManageGeothermal: false,
311-
}
312-
)
288+
expect(
289+
getAccessCapabilities(['AMP.Admin', 'Geothermal.Editor'])
290+
).toMatchObject({
291+
roles: [
292+
'AMP.Viewer',
293+
'AMP.Editor',
294+
'AMP.Admin',
295+
'Geothermal.Viewer',
296+
'Geothermal.Editor',
297+
],
298+
primaryRole: 'Geothermal.Editor',
299+
canManageAmp: true,
300+
canViewUnfinished: true,
301+
canEditGeothermal: true,
302+
canManageGeothermal: false,
303+
})
313304
})
314305
})
315306

src/utils/accessControl.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,6 @@ export type GeothermalRole =
1212
| 'Geothermal.Admin'
1313
export type PortalRole = AmpRole | GeothermalRole
1414

15-
// Temporary compatibility shim for pre-v1 Authentik group names.
16-
// Remove these legacy aliases before the v1 release once all users/groups
17-
// have been migrated to AMP.Viewer / AMP.Editor / AMP.Admin.
18-
const legacyRoleMap: Record<string, PortalRole> = {
19-
Viewer: 'AMP.Viewer',
20-
Editor: 'AMP.Editor',
21-
Admin: 'AMP.Admin',
22-
AMPViewer: 'AMP.Viewer',
23-
AMPEditor: 'AMP.Editor',
24-
OcotilloAdmin: 'AMP.Admin',
25-
'AMP.Viewer': 'AMP.Viewer',
26-
'AMP.Editor': 'AMP.Editor',
27-
'AMP.Admin': 'AMP.Admin',
28-
'Geothermal.Viewer': 'Geothermal.Viewer',
29-
'Geothermal.Editor': 'Geothermal.Editor',
30-
'Geothermal.Admin': 'Geothermal.Admin',
31-
}
32-
3315
const roleOrder: PortalRole[] = [
3416
'AMP.Viewer',
3517
'AMP.Editor',
@@ -148,9 +130,8 @@ export const normalizeAccessControlGroups = (
148130
const normalized = new Set<PortalRole>()
149131

150132
for (const group of groups ?? []) {
151-
const mapped = legacyRoleMap[group]
152-
if (mapped) {
153-
normalized.add(mapped)
133+
if (roleOrder.includes(group as PortalRole)) {
134+
normalized.add(group as PortalRole)
154135
}
155136
}
156137

0 commit comments

Comments
 (0)