Files
baiyue-firstleg/scripts/admin-test-env-modules/unified-pda-session-revocation-contract.test.mjs
T

69 lines
4.4 KiB
JavaScript
Raw Normal View History

import assert from 'node:assert/strict'
import test from 'node:test'
import { verifyPdaWarehouseRevocation, warehouseClaim } from './unified-pda-session-revocation.mjs'
import { pickerSessionHandoff } from './phase4-overseas-pda.mjs'
const token = warehouse => 'header.' + Buffer.from(JSON.stringify({ overseas_warehouse_id: warehouse })).toString('base64url') + '.signature'
test('signed binding identity retains 64-bit decimal precision for numeric and string claims', () => {
const make = raw => 'header.' + Buffer.from(raw).toString('base64url') + '.signature'
assert.equal(warehouseClaim(make('{"overseas_warehouse_id":193000000000200004}')), '193000000000200004')
assert.equal(warehouseClaim(token('193000000000200004')), '193000000000200004')
assert.equal(warehouseClaim(make('{"overseas_warehouse_id":null}')), '')
assert.equal(warehouseClaim(make('{"overseas_warehouse_id":22,"overseas_warehouse_id":23}')), '')
})
function fixture(wrongWarehouse = false) {
const checks = [], calls = []
let cleared = false
let isolatedRole
const picker = { membershipId: '7', username: 'offline-user', password: 'offline-password',
token: 'old-access', refreshToken: 'old-refresh', userUpdate: { displayName: 'offline', phone: '13900000001',
email: 'offline@example.invalid', tenantId: '0', roleIds: ['9'], overseasWarehouseId: '11', domesticWarehouseId: null } }
const response = (data, code = '200', http = 200) => ({ http, body: { code, data } })
const context = { assert: (_m, name, _r, passed, evidence) => checks.push({ name, passed, evidence }),
apiSuccess: (_m, _n, r) => r.body.code === '200' ? r.body.data : null,
request: async (method, path, body, bearer) => {
calls.push({ method, path, body, bearer })
if (path.includes('receiving-options')) return response({ records: [{ id: '11' }, { id: '22' }] })
if (path === '/api/platform/v1/iam/roles' && method === 'POST') {
isolatedRole = { ...body, id: '99', status: 'ACTIVE', permissionIds: [] }
return response(isolatedRole)
}
if (path === '/api/platform/v1/iam/roles') return response([isolatedRole])
if (path === '/api/platform/v1/iam/roles/99/status') return response({ status: 'DISABLED' })
if (method === 'PUT') {
assert.equal(body.phone, picker.userUpdate.phone)
assert.equal(body.email, picker.userUpdate.email)
assert.ok(body.roleIds.length > 0, 'IAM user edits require a role')
cleared = body.roleIds.includes('99')
return response({ ...body })
}
if (path === '/api/auth/login') return response({ accessToken: token(cleared ? null : wrongWarehouse ? '11' : '22'), refreshToken: 'new-refresh' })
if (path === '/api/auth/refresh') {
assert.equal(bearer, '')
return response(null, 'A0401')
}
if (bearer === 'old-access' || (cleared && bearer === token('22'))) return response(null, 'A0401', 401)
return cleared ? response(null, 'A0403', 403) : response(null, 'A0404')
} }
return { context, picker: pickerSessionHandoff(picker), checks, calls }
}
test('binding changes revoke both tokens and role/binding clearing prevents fresh PDA access', async () => {
const { context, picker, checks, calls } = fixture()
await verifyPdaWarehouseRevocation(context, picker)
for (const name of ['PDA仓绑定变更旧Access失效', 'PDA仓绑定变更旧Refresh不能恢复会话',
'新PDA会话只携带服务器签发的新仓绑定', 'PDA角色与仓绑定清空旧Access失效',
'PDA角色与仓绑定清空旧Refresh不能恢复会话', '无作业仓绑定的新会话不得进入PDA']) {
assert.equal(checks.find(row => row.name === name)?.passed, true, name)
}
assert.ok(checks.every(row => row.passed))
assert.ok(checks.every(row => !/offline-password|old-refresh|new-refresh/.test(row.evidence || '')))
assert.equal(calls.filter(row => row.method === 'PUT' && row.path.includes('/iam/users/')).length, 2)
assert.ok(calls.some(row => row.path === '/api/platform/v1/iam/roles/99/status'))
assert.ok(calls.some(row => row.path === '/api/auth/refresh' && row.body.refreshToken === 'old-refresh'))
})
test('fresh login retaining the original warehouse blocks instead of accepting token presence', async () => {
const { context, picker, checks } = fixture(true)
await assert.rejects(verifyPdaWarehouseRevocation(context, picker), /绑定漂移/)
assert.ok(checks.some(row => !row.passed))
})