import { describe, it, expect, vi } from 'vitest' import { randomUUID } from 'node:crypto' import type { HostRecord, HostStatus } from 'control-plane/src/model/records.js' import { createStoreRouteResolver, type HostSubdomainLookup, } from '../../src/wiring/route-resolver.js' const NOW_ISO = '2026-07-06T00:00:00.000Z' /** Build a full §4.2 HostRecord fixture keyed by its subdomain label. */ function makeHost(subdomain: string, status: HostStatus = 'online'): HostRecord { return { hostId: randomUUID(), accountId: randomUUID(), subdomain, agentPubkey: new Uint8Array([1, 2, 3]), enrollFpr: 'fpr:' + subdomain, status, lastSeen: NOW_ISO, createdAt: NOW_ISO, revokedAt: status === 'revoked' ? NOW_ISO : null, } } /** A minimal HostStore lookup fake: exact-match subdomain → record, else null (matches pg.ts). */ function fakeHosts(records: readonly HostRecord[]): HostSubdomainLookup { const bySub = new Map(records.map((r) => [r.subdomain, r])) return { getBySubdomain: vi.fn(async (subdomain: string) => bySub.get(subdomain) ?? null), } } describe('createStoreRouteResolver', () => { it('resolves a known online host to {hostId, accountId, subdomain}', async () => { // Arrange const host = makeHost('alice') const resolver = createStoreRouteResolver({ hosts: fakeHosts([host]) }) // Act const resolved = await resolver.resolveSubdomain('alice') // Assert expect(resolved).toEqual({ hostId: host.hostId, accountId: host.accountId, subdomain: 'alice', }) }) it('returns null (fail-closed) for an unknown subdomain', async () => { // Arrange const resolver = createStoreRouteResolver({ hosts: fakeHosts([makeHost('alice')]) }) // Act const resolved = await resolver.resolveSubdomain('nobody') // Assert expect(resolved).toBeNull() }) it('fails closed (returns null) for a revoked host even though the row still exists', async () => { // Arrange const resolver = createStoreRouteResolver({ hosts: fakeHosts([makeHost('alice', 'revoked')]) }) // Act const resolved = await resolver.resolveSubdomain('alice') // Assert expect(resolved).toBeNull() }) it('resolves offline and draining hosts (only revoked fails closed)', async () => { // Arrange const offline = makeHost('bob', 'offline') const draining = makeHost('carol', 'draining') const resolver = createStoreRouteResolver({ hosts: fakeHosts([offline, draining]) }) // Act + Assert expect(await resolver.resolveSubdomain('bob')).toEqual({ hostId: offline.hostId, accountId: offline.accountId, subdomain: 'bob', }) expect(await resolver.resolveSubdomain('carol')).toEqual({ hostId: draining.hostId, accountId: draining.accountId, subdomain: 'carol', }) }) it('derives identity only from the store record, not the caller (INV3)', async () => { // Arrange: the stored record carries the authoritative accountId/hostId. const host = makeHost('alice') const resolver = createStoreRouteResolver({ hosts: fakeHosts([host]) }) // Act const resolved = await resolver.resolveSubdomain('alice') // Assert: values come from the record, never fabricated from the input label. expect(resolved?.accountId).toBe(host.accountId) expect(resolved?.hostId).toBe(host.hostId) }) it('passes the exact subdomain label through to getBySubdomain', async () => { // Arrange const hosts = fakeHosts([makeHost('alice')]) const resolver = createStoreRouteResolver({ hosts }) // Act await resolver.resolveSubdomain('alice') // Assert expect(hosts.getBySubdomain).toHaveBeenCalledWith('alice') expect(hosts.getBySubdomain).toHaveBeenCalledTimes(1) }) it('propagates store errors (no silent swallow)', async () => { // Arrange: a store that throws (e.g. DB unavailable) must NOT be masked as a null resolve. const boom = new Error('db down') const resolver = createStoreRouteResolver({ hosts: { getBySubdomain: vi.fn(async () => { throw boom }) }, }) // Act + Assert await expect(resolver.resolveSubdomain('alice')).rejects.toThrow('db down') }) })