@things-factory/auth-base 10.1.113 → 10.1.121
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/auth-base",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.121",
|
|
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.121",
|
|
38
38
|
"@things-factory/env": "^10.1.20",
|
|
39
|
-
"@things-factory/shell": "^10.1.
|
|
39
|
+
"@things-factory/shell": "^10.1.121",
|
|
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": "23536a73b10f103048a2c893d3960b2a4e0f03dd"
|
|
52
52
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { parse } from 'graphql'
|
|
11
11
|
|
|
12
12
|
import { clearEntryTargets, declareEntryTarget } from '../../ai-assistant/server/service/data-entry/entry-target'
|
|
13
|
+
import { applyEntryProposal } from '../../ai-assistant/server/service/data-entry/entry-apply'
|
|
13
14
|
|
|
14
15
|
import { closeAuthDatabase, Domain, getRepository, openAuthDatabase, resetAuthDatabase } from './db'
|
|
15
16
|
import { loadCompiled } from './compiled'
|
|
@@ -22,6 +23,8 @@ const { Privilege } = loadCompiled('service/privilege/privilege')
|
|
|
22
23
|
const { User } = loadCompiled('service/user/user')
|
|
23
24
|
const access = loadCompiled('controllers/access-request')
|
|
24
25
|
const targets = loadCompiled('ai-entry/access-entry-targets')
|
|
26
|
+
const { judgePermission } = loadCompiled('utils/check-permission')
|
|
27
|
+
const { AccessRequest } = loadCompiled('service/access-request/access-request')
|
|
25
28
|
|
|
26
29
|
const rootFields = (document: string) =>
|
|
27
30
|
((parse(document).definitions[0] as any).selectionSet.selections as any[]).map(one => one.name.value)
|
|
@@ -31,6 +34,10 @@ const row = (values: Record<string, unknown>, index = 0) => ({ index, values, so
|
|
|
31
34
|
describe('the declarations', () => {
|
|
32
35
|
afterEach(() => clearEntryTargets())
|
|
33
36
|
|
|
37
|
+
it('the built public AUTH entry exports the same refusal formatter used by AI entry', () => {
|
|
38
|
+
expect(loadCompiled('index').privilegeRejection).toBe(loadCompiled('service/privilege/privilege-rejection').privilegeRejection)
|
|
39
|
+
})
|
|
40
|
+
|
|
34
41
|
it('are accepted by the assistant as declared', () => {
|
|
35
42
|
for (const target of targets.accessEntryTargets()) expect(() => declareEntryTarget(target)).not.toThrow()
|
|
36
43
|
})
|
|
@@ -110,6 +117,35 @@ describe('the card says what the screen says', () => {
|
|
|
110
117
|
|
|
111
118
|
const state = (user: any) => ({ domain, user })
|
|
112
119
|
|
|
120
|
+
it.each(['GRANT', 'DENY'])('a stored AI decision applies %s through the same controller and schedules the result after commit', async decision => {
|
|
121
|
+
const request = await access.requestAccess({ category: 'warehouse', privilege: 'mutation', reason: 'inbound' }, { state: { ...state(kim), afterCommit: [] } } as any)
|
|
122
|
+
const target = targets.accessDecisionEntryTarget()
|
|
123
|
+
const notify = jest.fn().mockResolvedValue(undefined)
|
|
124
|
+
const afterCommit: any[] = []
|
|
125
|
+
const context = { state: { ...state(park), notify, afterCommit }, t: (key: string) => key }
|
|
126
|
+
const execute = jest.fn(async (document, variables) => {
|
|
127
|
+
expect(document).toBe(target.mutation)
|
|
128
|
+
const decided = await access.decideAccessRequest(variables.decision, context)
|
|
129
|
+
return { data: { decideAccessRequest: decided } }
|
|
130
|
+
})
|
|
131
|
+
const proposal = { key: 'ai-decision', kind: 'entry', target: target.key, rows: [row({ request: { id: request.id }, decision, ...(decision === 'GRANT' ? { role: { id: inbound.id } } : { reason: 'IT only' }) })] }
|
|
132
|
+
const outcome = await applyEntryProposal(proposal.key, {
|
|
133
|
+
messages: [{ id: 'm', proposals: [proposal] }], answered: false, state: context.state,
|
|
134
|
+
passesDoor: async door => {
|
|
135
|
+
expect(door).toBe('Mutation.decideAccessRequest')
|
|
136
|
+
return (await judgePermission({ category: 'user', privilege: 'mutation', owner: true }, park, domain)).permitted
|
|
137
|
+
},
|
|
138
|
+
execute
|
|
139
|
+
}, key => key === target.key ? target : undefined)
|
|
140
|
+
expect(outcome).toMatchObject({ verdict: 'accepted', applied: 1, missed: 0 })
|
|
141
|
+
expect(execute).toHaveBeenCalledTimes(1)
|
|
142
|
+
expect(notify).not.toHaveBeenCalled()
|
|
143
|
+
for (const step of afterCommit) await step.run()
|
|
144
|
+
expect(notify).toHaveBeenCalledWith(expect.objectContaining({ receivers: [kim.id], url: 'my-access-requests', title: `access-request.notify.${decision === 'GRANT' ? 'granted' : 'denied'}.title` }))
|
|
145
|
+
expect((await getRepository(AccessRequest).findOneBy({ id: request.id })).state).toBe(decision === 'GRANT' ? 'GRANTED' : 'DENIED')
|
|
146
|
+
expect(await User.hasPrivilege('mutation', 'warehouse', domain, kim)).toBe(decision === 'GRANT')
|
|
147
|
+
})
|
|
148
|
+
|
|
113
149
|
it('★ the card\'s findings are reviewDecision\'s, for grant and for deny', async () => {
|
|
114
150
|
const request = await access.requestAccess({ category: 'warehouse', privilege: 'mutation', reason: 'inbound' }, { state: { ...state(kim), afterCommit: [] } } as any)
|
|
115
151
|
const rows = [
|