@things-factory/auth-base 10.1.44 → 10.1.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-server/service/index.d.ts +1 -1
- package/dist-server/service/role-template/index.d.ts +2 -1
- package/dist-server/service/role-template/index.js +2 -1
- package/dist-server/service/role-template/index.js.map +1 -1
- package/dist-server/service/role-template/role-template-gap-resolver.d.ts +10 -0
- package/dist-server/service/role-template/role-template-gap-resolver.js +41 -0
- package/dist-server/service/role-template/role-template-gap-resolver.js.map +1 -0
- package/dist-server/service/role-template/role-template-types.d.ts +10 -0
- package/dist-server/service/role-template/role-template-types.js +41 -1
- package/dist-server/service/role-template/role-template-types.js.map +1 -1
- package/dist-server/service/role-template/role-template.d.ts +25 -0
- package/dist-server/service/role-template/role-template.js +32 -0
- package/dist-server/service/role-template/role-template.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/tests/role-template-gap-db.test.ts +125 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/auth-base",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.46",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "dist-client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"@reduxjs/toolkit": "^2.2.5",
|
|
35
35
|
"@simplewebauthn/browser": "^13.0.0",
|
|
36
36
|
"@simplewebauthn/server": "^13.0.0",
|
|
37
|
-
"@things-factory/email-base": "^10.1.
|
|
37
|
+
"@things-factory/email-base": "^10.1.46",
|
|
38
38
|
"@things-factory/env": "^10.1.20",
|
|
39
|
-
"@things-factory/shell": "^10.1.
|
|
39
|
+
"@things-factory/shell": "^10.1.46",
|
|
40
40
|
"@things-factory/utils": "^10.1.20",
|
|
41
41
|
"@types/webappsec-credential-management": "^0.6.9",
|
|
42
42
|
"jsonwebtoken": "^9.0.0",
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"passport-jwt": "^4.0.0",
|
|
49
49
|
"passport-local": "^1.0.0"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "d3467cde550453f3348fed0ed6c79a12a6ba0db4"
|
|
52
52
|
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a role lacks against the template of its name - against a real database (ADR-0075 decision 1).
|
|
3
|
+
*
|
|
4
|
+
* A template is a seed and nothing pushes its later grants into roles already standing. When
|
|
5
|
+
* operato-plant's templates gained ai-assistant, the roles in miratek stayed without it and only
|
|
6
|
+
* plant's security runner noticed. The role screen now shows the gap and the administrator adds
|
|
7
|
+
* it; these are the facts that screen stands on.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { closeAuthDatabase, Domain, getRepository, openAuthDatabase, resetAuthDatabase, authDataSource } from './db'
|
|
11
|
+
import { loadCompiled } from './compiled'
|
|
12
|
+
|
|
13
|
+
const { Role } = loadCompiled('service/role/role')
|
|
14
|
+
const { Privilege } = loadCompiled('service/privilege/privilege')
|
|
15
|
+
const { User } = loadCompiled('service/user/user')
|
|
16
|
+
const { RoleTemplateMutation } = loadCompiled('service/role-template/role-template-mutation')
|
|
17
|
+
const { RoleTemplateGapResolver } = loadCompiled('service/role-template/role-template-gap-resolver')
|
|
18
|
+
const { registerRoleTemplate } = loadCompiled('service/role-template/role-template')
|
|
19
|
+
|
|
20
|
+
const mutation = new RoleTemplateMutation()
|
|
21
|
+
const gapOf = (role: any) => new RoleTemplateGapResolver().templateGap(role)
|
|
22
|
+
|
|
23
|
+
let domain: any
|
|
24
|
+
let actor: any
|
|
25
|
+
|
|
26
|
+
const context = () => ({ state: { domain, user: actor, tx: authDataSource().manager } }) as any
|
|
27
|
+
|
|
28
|
+
/** The template as it stood when the role was made, then as it stands after it gained a door. */
|
|
29
|
+
function declareTemplate(axes: string[], extra: { category: string; axes: string[] }[] = []) {
|
|
30
|
+
;(process as any)['ROLE_TEMPLATES'] = {}
|
|
31
|
+
registerRoleTemplate({ id: 'plant.qi', name: 'QUALITY-INSPECTOR', grants: [{ category: 'board', axes }, ...extra] })
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
beforeAll(async () => {
|
|
35
|
+
await openAuthDatabase()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
afterAll(async () => {
|
|
39
|
+
await closeAuthDatabase()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
beforeEach(async () => {
|
|
43
|
+
await resetAuthDatabase()
|
|
44
|
+
|
|
45
|
+
const saved = await getRepository(Domain).save({ name: 'Plant A', subdomain: 'plant-a' })
|
|
46
|
+
domain = await getRepository(Domain).findOneBy({ id: saved.id })
|
|
47
|
+
|
|
48
|
+
await getRepository(Privilege).save({ name: 'query', category: 'board' })
|
|
49
|
+
await getRepository(Privilege).save({ name: 'mutation', category: 'board' })
|
|
50
|
+
;(process as any).PRIVILEGES = {
|
|
51
|
+
'board query': ['board', 'query'],
|
|
52
|
+
'board mutation': ['board', 'mutation']
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
actor = await getRepository(User).save({
|
|
56
|
+
username: 'admin',
|
|
57
|
+
email: 'admin@example.com',
|
|
58
|
+
name: 'Admin',
|
|
59
|
+
salt: User.generateSalt(),
|
|
60
|
+
status: 'activated',
|
|
61
|
+
domains: [domain]
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
describe('the gap between a role and its template', () => {
|
|
66
|
+
it('is zero for a role made from the template as it stands', async () => {
|
|
67
|
+
declareTemplate(['query'])
|
|
68
|
+
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
69
|
+
|
|
70
|
+
expect(await gapOf(role)).toEqual({
|
|
71
|
+
templateId: 'plant.qi',
|
|
72
|
+
templateName: 'QUALITY-INSPECTOR',
|
|
73
|
+
missing: [],
|
|
74
|
+
missingCount: 0
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('★ names what the template gained after the role was made', async () => {
|
|
79
|
+
declareTemplate(['query'])
|
|
80
|
+
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
81
|
+
|
|
82
|
+
declareTemplate(['query', 'mutation'])
|
|
83
|
+
|
|
84
|
+
const gap = await gapOf(role)
|
|
85
|
+
expect(gap.missingCount).toBe(1)
|
|
86
|
+
expect(gap.missing).toEqual([{ category: 'board', axes: ['mutation'] }])
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('★ closes when the administrator adds it - the same top-up the template button runs', async () => {
|
|
90
|
+
declareTemplate(['query'])
|
|
91
|
+
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
92
|
+
declareTemplate(['query', 'mutation'])
|
|
93
|
+
|
|
94
|
+
await mutation.createRoleFromTemplate('plant.qi', 'QUALITY-INSPECTOR', context())
|
|
95
|
+
|
|
96
|
+
expect((await gapOf(role)).missingCount).toBe(0)
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('★ does not count what this installation does not declare', async () => {
|
|
100
|
+
declareTemplate(['query'], [{ category: 'order', axes: ['query'] }])
|
|
101
|
+
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
102
|
+
|
|
103
|
+
expect((await gapOf(role)).missingCount).toBe(0)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('★ is null for a role no template names - a renamed role belongs to its administrator', async () => {
|
|
107
|
+
declareTemplate(['query'])
|
|
108
|
+
const role = await mutation.createRoleFromTemplate('plant.qi', 'NIGHT-INSPECTOR', context())
|
|
109
|
+
|
|
110
|
+
expect(await gapOf(role)).toBeNull()
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
it('does not take away what the administrator added beyond the template', async () => {
|
|
114
|
+
declareTemplate(['query'])
|
|
115
|
+
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
116
|
+
const stored = await getRepository(Role).findOne({ where: { id: role.id }, relations: ['privileges'] })
|
|
117
|
+
stored.privileges = [
|
|
118
|
+
...stored.privileges,
|
|
119
|
+
await getRepository(Privilege).findOneBy({ category: 'board', name: 'mutation' })
|
|
120
|
+
]
|
|
121
|
+
await getRepository(Role).save(stored)
|
|
122
|
+
|
|
123
|
+
expect((await gapOf(role)).missingCount).toBe(0)
|
|
124
|
+
})
|
|
125
|
+
})
|