test(d28): lock module directory + portals (fieldSpec, login-only, no secret leak)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat/client-detail-redesign
Thomas Joise 3 days ago
parent 69c59815f0
commit 90864b7067

@ -0,0 +1,71 @@
// apps/hq/test/module-access.test.ts — D28: module directory + portals quick-list.
import { describe, it, expect } from 'vitest'
import { openDb } from '../src/db'
import { seedIfEmpty } from '../src/seed'
import { createClient } from '../src/repos-clients'
import { createModule, assignModule, setModuleFieldValues, setModulePassword, moduleDirectory, listPortals } from '../src/repos-modules'
const KEY = '0'.repeat(64) // valid 32-byte hex key for the test's encryption
describe('moduleDirectory (D28)', () => {
it('returns the fieldSpec and every active client with its values', async () => {
const db = openDb(':memory:'); await seedIfEmpty(db)
const m = await createModule(db, 'u1', {
code: 'RTGS', name: 'RTGS', sac: '998314', allowedKinds: ['yearly'],
fieldSpec: [
{ key: 'ip', label: 'IP', type: 'text' },
{ key: 'portal_url', label: 'Portal URL', type: 'text' },
{ key: 'admin_password', label: 'Admin password', type: 'secret' },
],
})
const a = await createClient(db, 'u1', { name: 'Alpha Bank', stateCode: '32' })
const b = await createClient(db, 'u1', { name: 'Beta Bank', stateCode: '32' })
const cmA = await assignModule(db, 'u1', { clientId: a.id, moduleId: m.id, kind: 'yearly' })
await assignModule(db, 'u1', { clientId: b.id, moduleId: m.id, kind: 'yearly' })
await setModuleFieldValues(db, 'u1', cmA.id, { ip: '10.0.0.1', portal_url: 'https://rtgs.example/login' })
const dir = await moduleDirectory(db, m.id)
expect(dir).not.toBeNull()
expect(dir!.code).toBe('RTGS')
expect(dir!.fieldSpec.length).toBe(3)
expect(dir!.total).toBe(2)
const rowA = dir!.rows.find((r) => r.clientName === 'Alpha Bank')!
expect(rowA.fieldValues.ip).toBe('10.0.0.1')
expect(rowA.fieldValues.portal_url).toBe('https://rtgs.example/login')
})
it('is null for an unknown module', async () => {
const db = openDb(':memory:'); await seedIfEmpty(db)
expect(await moduleDirectory(db, 'nope')).toBeNull()
})
})
describe('listPortals (D28)', () => {
it('lists only subscriptions with a login and surfaces URL fields (never the password)', async () => {
const db = openDb(':memory:'); await seedIfEmpty(db)
const m = await createModule(db, 'u1', {
code: 'RECOVERX', name: 'RecoverX', sac: '998314', allowedKinds: ['yearly'],
fieldSpec: [
{ key: 'portal_url', label: 'Portal URL', type: 'text' },
{ key: 'note', label: 'Note', type: 'text' },
],
})
const a = await createClient(db, 'u1', { name: 'Alpha', stateCode: '32' })
const b = await createClient(db, 'u1', { name: 'Beta', stateCode: '32' })
const cmA = await assignModule(db, 'u1', { clientId: a.id, moduleId: m.id, kind: 'yearly' })
const cmB = await assignModule(db, 'u1', { clientId: b.id, moduleId: m.id, kind: 'yearly' })
// Alpha has a URL + a stored password; Beta has only a note → no login → excluded.
await setModuleFieldValues(db, 'u1', cmA.id, { portal_url: 'https://recoverx.example' })
await setModulePassword(db, 'u1', cmA.id, 'secret', KEY)
await setModuleFieldValues(db, 'u1', cmB.id, { note: 'nothing here' })
const portals = await listPortals(db)
expect(portals.length).toBe(1)
const p = portals[0]!
expect(p.clientName).toBe('Alpha')
expect(p.hasPassword).toBe(true)
expect(p.links.map((l) => l.url)).toContain('https://recoverx.example')
// the password itself is never in the payload
expect(JSON.stringify(p)).not.toContain('secret')
})
})
Loading…
Cancel
Save