@things-factory/auth-base 10.1.218 → 10.1.223
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/role/role-mutation.js +5 -0
- package/dist-server/service/role/role-mutation.js.map +1 -1
- package/dist-server/service/role/role-types.d.ts +1 -0
- package/dist-server/service/role/role-types.js +4 -0
- package/dist-server/service/role/role-types.js.map +1 -1
- package/dist-server/service/role/role.d.ts +10 -0
- package/dist-server/service/role/role.js +5 -0
- package/dist-server/service/role/role.js.map +1 -1
- package/dist-server/service/role-template/role-template-gap-resolver.d.ts +2 -2
- package/dist-server/service/role-template/role-template-gap-resolver.js +7 -13
- package/dist-server/service/role-template/role-template-gap-resolver.js.map +1 -1
- package/dist-server/service/role-template/role-template-mutation.d.ts +7 -4
- package/dist-server/service/role-template/role-template-mutation.js +15 -15
- package/dist-server/service/role-template/role-template-mutation.js.map +1 -1
- package/dist-server/service/role-template/role-template-types.d.ts +3 -3
- package/dist-server/service/role-template/role-template-types.js.map +1 -1
- package/dist-server/service/role-template/role-template.d.ts +14 -15
- package/dist-server/service/role-template/role-template.js +8 -8
- package/dist-server/service/role-template/role-template.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/tests/role-template-gap-db.test.ts +58 -7
- package/tests/role-template-seed-db.test.ts +5 -4
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.223",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "dist-client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"passport-jwt": "^4.0.0",
|
|
51
51
|
"passport-local": "^1.0.0"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "868f2026b8373371ad04f42b0a097964d0d0ed0f"
|
|
54
54
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What a role lacks against
|
|
2
|
+
* What a role lacks against its base template - against a real database (ADR-0075 decision 1, amended 2026-10-26:
|
|
3
|
+
* a role keeps one base template, `Role.templateId`, and is never paired by name).
|
|
3
4
|
*
|
|
4
5
|
* A template is a seed and nothing pushes its later grants into roles already standing. When
|
|
5
6
|
* operato-plant's templates gained ai-assistant, the roles in miratek stayed without it and only
|
|
@@ -14,12 +15,16 @@ const { Role } = loadCompiled('service/role/role')
|
|
|
14
15
|
const { Privilege } = loadCompiled('service/privilege/privilege')
|
|
15
16
|
const { User } = loadCompiled('service/user/user')
|
|
16
17
|
const { RoleTemplateMutation } = loadCompiled('service/role-template/role-template-mutation')
|
|
18
|
+
const { RoleMutation } = loadCompiled('service/role/role-mutation')
|
|
17
19
|
const { RoleTemplateGapResolver } = loadCompiled('service/role-template/role-template-gap-resolver')
|
|
18
20
|
const { registerRoleTemplate } = loadCompiled('service/role-template/role-template')
|
|
19
21
|
const { registerRoleTask } = loadCompiled('service/role-template/role-task')
|
|
20
22
|
|
|
21
23
|
const mutation = new RoleTemplateMutation()
|
|
22
|
-
const gapOf = (role: any
|
|
24
|
+
const gapOf = (role: any) => new RoleTemplateGapResolver().templateGap(role)
|
|
25
|
+
const reread = (role: any) => getRepository(Role).findOneBy({ id: role.id })
|
|
26
|
+
/* The role screen's base template field saves through `updateRole`. */
|
|
27
|
+
const baseOn = (role: any, templateId: string | null) => new RoleMutation().updateRole(role.id, { templateId } as any, { ...context(), t: (key: string) => key } as any)
|
|
23
28
|
const coverageOf = (role: any) => new RoleTemplateGapResolver().taskCoverage(role)
|
|
24
29
|
|
|
25
30
|
let domain: any
|
|
@@ -107,13 +112,52 @@ describe('the gap between a role and its template', () => {
|
|
|
107
112
|
expect((await gapOf(role)).missingCount).toBe(0)
|
|
108
113
|
})
|
|
109
114
|
|
|
110
|
-
it('★
|
|
115
|
+
it('★ a role made under a name of its own is still based on the template', async () => {
|
|
111
116
|
declareTemplate(['query'])
|
|
112
117
|
const role = await mutation.createRoleFromTemplate('plant.qi', 'NIGHT-INSPECTOR', context())
|
|
118
|
+
declareTemplate(['query', 'mutation'])
|
|
119
|
+
|
|
120
|
+
expect((await reread(role)).templateId).toBe('plant.qi')
|
|
121
|
+
expect(await gapOf(await reread(role))).toMatchObject({ templateId: 'plant.qi', missingCount: 1 })
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('★ is null for a role that is based on no template, even when a template carries its name', async () => {
|
|
125
|
+
declareTemplate(['query'])
|
|
126
|
+
const role = await getRepository(Role).save({ domain, name: 'QUALITY-INSPECTOR', privileges: [] })
|
|
113
127
|
|
|
114
128
|
expect(await gapOf(role)).toBeNull()
|
|
115
129
|
})
|
|
116
130
|
|
|
131
|
+
it('★ refuses to top up a role based on another template, and changes nothing', async () => {
|
|
132
|
+
declareTemplate(['query'])
|
|
133
|
+
registerRoleTemplate({ id: 'plant.qm', name: 'QUALITY-MANAGER', grants: [{ category: 'board', axes: ['query', 'mutation'] }] })
|
|
134
|
+
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
135
|
+
|
|
136
|
+
await expect(mutation.createRoleFromTemplate('plant.qm', 'QUALITY-INSPECTOR', context())).rejects.toThrow(/based on role template "plant.qi", not "plant.qm"/)
|
|
137
|
+
|
|
138
|
+
const stored = await getRepository(Role).findOne({ where: { id: role.id }, relations: ['privileges'] })
|
|
139
|
+
expect(stored.templateId).toBe('plant.qi')
|
|
140
|
+
expect(stored.privileges.map((p: any) => p.name)).toEqual(['query'])
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('★ tops up a standing role that has no base and makes the template its base', async () => {
|
|
144
|
+
declareTemplate(['query', 'mutation'])
|
|
145
|
+
const role = await getRepository(Role).save({ domain, name: 'QUALITY-INSPECTOR', privileges: [] })
|
|
146
|
+
|
|
147
|
+
await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
148
|
+
|
|
149
|
+
expect((await reread(role)).templateId).toBe('plant.qi')
|
|
150
|
+
expect((await gapOf(await reread(role))).missingCount).toBe(0)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('★ is null when the base is a template this installation no longer declares', async () => {
|
|
154
|
+
declareTemplate(['query'])
|
|
155
|
+
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
156
|
+
;(process as any)['ROLE_TEMPLATES'] = {}
|
|
157
|
+
|
|
158
|
+
expect(await gapOf(await reread(role))).toBeNull()
|
|
159
|
+
})
|
|
160
|
+
|
|
117
161
|
it('does not take away what the administrator added beyond the template', async () => {
|
|
118
162
|
declareTemplate(['query'])
|
|
119
163
|
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
@@ -131,19 +175,26 @@ describe('the gap between a role and its template', () => {
|
|
|
131
175
|
expect(gap.extraCount).toBe(1)
|
|
132
176
|
})
|
|
133
177
|
|
|
134
|
-
it('★ lays a role
|
|
178
|
+
it('★ lays a role named in the site\'s own words against the base the administrator gives it', async () => {
|
|
135
179
|
declareTemplate(['query', 'mutation'])
|
|
136
180
|
const role = await getRepository(Role).save({ domain, name: '품질검사', privileges: [await getRepository(Privilege).findOneBy({ category: 'board', name: 'query' })] })
|
|
137
181
|
|
|
138
182
|
expect(await gapOf(role)).toBeNull()
|
|
139
|
-
|
|
183
|
+
|
|
184
|
+
await baseOn(role, 'plant.qi')
|
|
185
|
+
expect(await gapOf(await reread(role))).toMatchObject({ templateId: 'plant.qi', missing: [{ category: 'board', axes: ['mutation'] }], extraCount: 0 })
|
|
186
|
+
|
|
187
|
+
await baseOn(role, null)
|
|
188
|
+
expect((await reread(role)).templateId).toBeNull()
|
|
189
|
+
expect(await gapOf(await reread(role))).toBeNull()
|
|
140
190
|
})
|
|
141
191
|
|
|
142
|
-
it('refuses a template id that does not exist rather than
|
|
192
|
+
it('refuses a base template id that does not exist rather than storing it', async () => {
|
|
143
193
|
declareTemplate(['query'])
|
|
144
194
|
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
145
195
|
|
|
146
|
-
await expect(
|
|
196
|
+
await expect(baseOn(role, 'plant.nobody')).rejects.toThrow(/no role template "plant.nobody"/)
|
|
197
|
+
expect((await reread(role)).templateId).toBe('plant.qi')
|
|
147
198
|
})
|
|
148
199
|
})
|
|
149
200
|
|
|
@@ -119,7 +119,8 @@ describe('seeding', () => {
|
|
|
119
119
|
expect(await getRepository(Role).count()).toBe(1)
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
/* A role has one base template (ADR-0075 decision 1, amended 2026-10-26) - two apps declaring one name no longer union. */
|
|
123
|
+
it('refuses a second template onto a role of the same name based on the first', async () => {
|
|
123
124
|
registerRoleTemplate({ id: 'plant.qi', name: 'QUALITY-INSPECTOR', grants: [{ category: 'board', axes: ['query'] }] })
|
|
124
125
|
registerRoleTemplate({
|
|
125
126
|
id: 'twin.qi',
|
|
@@ -127,10 +128,10 @@ describe('seeding', () => {
|
|
|
127
128
|
grants: [{ category: 'board', axes: ['mutation'] }]
|
|
128
129
|
})
|
|
129
130
|
|
|
130
|
-
await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
131
|
-
|
|
131
|
+
const role = await mutation.createRoleFromTemplate('plant.qi', undefined, context())
|
|
132
|
+
await expect(mutation.createRoleFromTemplate('twin.qi', undefined, context())).rejects.toThrow(/based on role template "plant.qi", not "twin.qi"/)
|
|
132
133
|
|
|
133
|
-
expect(await privilegesOf(role.id)).toEqual(['board:
|
|
134
|
+
expect(await privilegesOf(role.id)).toEqual(['board:query'])
|
|
134
135
|
expect(await getRepository(Role).count()).toBe(1)
|
|
135
136
|
})
|
|
136
137
|
|