import { type Type } from '@nestjs/common'; import { Test, type TestingModule } from '@nestjs/testing'; import type { SlashCommandPayload } from '@mosaicstack/types'; import { describe, expect, it, vi } from 'vitest'; import { AgentService, type AgentSession } from '../agent/agent.service.js'; import { ProviderService } from '../agent/provider.service.js'; import { AppModule } from '../app.module.js'; import { CommandAuthorizationService } from '../commands/command-authorization.service.js'; import { CommandExecutorService } from '../commands/command-executor.service.js'; import { CommandsModule } from '../commands/commands.module.js'; import { CommandRuntimeApprovalVerifier } from '../commands/runtime-approval-verifier.js'; import { PreferencesModule } from '../preferences/preferences.module.js'; import { SystemOverrideService } from '../preferences/system-override.service.js'; const fakeDb = { $client: { exec: async (): Promise => {} }, execute: async (): Promise<{ rows: unknown[] }> => ({ rows: [] }), select: () => ({ from: () => ({ where: async (): Promise> => [{ count: 1 }], }), }), insert: () => ({ values: async (): Promise => {} }), }; const fakeProviderService = { onModuleInit: async (): Promise => {}, onModuleDestroy: (): void => {}, getRegistry: () => ({ getAvailable: () => [], getAll: () => [], find: () => undefined }), getDefaultModel: () => undefined, listAvailableModels: () => [], listProviders: () => [], getAdapter: () => undefined, getProvidersHealth: () => [], }; function compileRealAppGraph(): Promise { return Test.createTestingModule({ imports: [AppModule] }) .overrideProvider('DB_HANDLE') .useValue({ db: fakeDb, close: async (): Promise => {} }) .overrideProvider('DB') .useValue(fakeDb) .overrideProvider('STORAGE_ADAPTER') .useValue({ name: 'required-security-wiring-test', migrate: async (): Promise => {}, close: async (): Promise => {}, }) .overrideProvider('AUTH') .useValue({}) .overrideProvider('BRAIN') .useValue({ conversations: {}, agents: {} }) .overrideProvider('LOG_SERVICE') .useValue({}) .overrideProvider('MEMORY') .useValue({}) .overrideProvider('MEMORY_ADAPTER') .useValue({}) .overrideProvider(ProviderService) .useValue(fakeProviderService) .compile(); } function providerToken(provider: unknown): unknown { return typeof provider === 'function' ? provider : (provider as { provide?: unknown })?.provide; } interface MaskingConsumer { moduleType: Type; token: Type; useValue: object; } async function compileWithoutProvider( moduleType: Type, missingToken: Type, maskingConsumer: MaskingConsumer, ): Promise<{ error: unknown; moduleRef: TestingModule | undefined }> { const touchedModules = new Set([moduleType, maskingConsumer.moduleType]); const originals = Array.from(touchedModules, (touchedModule: Type) => ({ moduleType: touchedModule, providers: (Reflect.getMetadata('providers', touchedModule) ?? []) as unknown[], exports: (Reflect.getMetadata('exports', touchedModule) ?? []) as unknown[], })); for (const original of originals) { const providers = original.providers.flatMap((provider: unknown): unknown[] => { const token = providerToken(provider); if (original.moduleType === moduleType && token === missingToken) return []; if (original.moduleType === maskingConsumer.moduleType && token === maskingConsumer.token) { return [{ provide: maskingConsumer.token, useValue: maskingConsumer.useValue }]; } return [provider]; }); const exports = original.exports.filter( (exported: unknown): boolean => original.moduleType !== moduleType || providerToken(exported) !== missingToken, ); Reflect.defineMetadata('providers', providers, original.moduleType); Reflect.defineMetadata('exports', exports, original.moduleType); } let moduleRef: TestingModule | undefined; let error: unknown; try { moduleRef = await compileRealAppGraph(); } catch (caught: unknown) { error = caught; } finally { for (const original of originals) { Reflect.defineMetadata('providers', original.providers, original.moduleType); Reflect.defineMetadata('exports', original.exports, original.moduleType); } } return { error, moduleRef }; } async function closeIfCompiled(moduleRef: TestingModule | undefined): Promise { if (moduleRef) await moduleRef.close(); } describe('required security wiring — real AppModule startup refusal', () => { it('FL-01 positive control: the real graph compiles when CommandAuthorizationService is bound', async () => { const moduleRef = await compileRealAppGraph(); try { expect(moduleRef.get(CommandAuthorizationService, { strict: false })).toBeInstanceOf( CommandAuthorizationService, ); } finally { await moduleRef.close(); } }); it('FL-01 negative control: absence read as permission is refused at module compilation', async () => { const { error, moduleRef } = await compileWithoutProvider( CommandsModule, CommandAuthorizationService, { moduleType: CommandsModule, token: CommandRuntimeApprovalVerifier, useValue: {}, }, ); await closeIfCompiled(moduleRef); expect( error, 'absence read as permission: AppModule compilation accepted a missing CommandAuthorizationService binding', ).toBeInstanceOf(Error); if (!(error instanceof Error)) return; expect(error.message).toContain('CommandExecutorService'); expect(error.message).toContain('CommandAuthorizationService'); }); it('FL-11 positive control: the real graph compiles when SystemOverrideService is bound', async () => { const moduleRef = await compileRealAppGraph(); try { expect(moduleRef.get(SystemOverrideService, { strict: false })).toBeInstanceOf( SystemOverrideService, ); } finally { await moduleRef.close(); } }); it('FL-11 negative control: absence read as permission is refused at module compilation', async () => { const { error, moduleRef } = await compileWithoutProvider( PreferencesModule, SystemOverrideService, { moduleType: CommandsModule, token: CommandExecutorService, useValue: {}, }, ); await closeIfCompiled(moduleRef); expect( error, 'absence read as permission: AppModule compilation accepted a missing SystemOverrideService binding', ).toBeInstanceOf(Error); if (!(error instanceof Error)) return; expect(error.message).toContain('AgentService'); expect(error.message).toContain('SystemOverrideService'); }); }); const actorScope = { userId: 'security-user', tenantId: 'security-tenant' }; const conversationId = 'security-conversation'; function directExecutorWithoutAuthorization(systemOverrideSet: ReturnType) { const registry = { getManifest: vi.fn(() => ({ version: 1, commands: [ { name: 'system', aliases: [], description: 'Set instruction authority', scope: 'agent' as const, execution: 'socket' as const, available: true, }, ], skills: [], })), }; return new CommandExecutorService( registry as never, { getSession: vi.fn() } as never, { set: systemOverrideSet, clear: vi.fn() } as never, { collect: vi.fn() } as never, null, { agents: {} } as never, null, null, { getServerStatuses: vi.fn(() => []), getToolDefinitions: vi.fn(() => []) } as never, undefined as never, ); } function directAgentWithoutSystemOverride(piPrompt: ReturnType): { service: AgentService; session: AgentSession; } { const service = new AgentService( { getDefaultModel: vi.fn(() => null), getRegistry: vi.fn(() => ({})), findModel: vi.fn(), listAvailableModels: vi.fn(() => []), } as never, {} as never, {} as never, { available: false } as never, {} as never, { getToolDefinitions: vi.fn(() => []) } as never, { loadForSession: vi.fn(async () => ({ metaTools: [], promptAdditions: [] })) } as never, undefined as never, null, { collect: vi.fn().mockResolvedValue(undefined) } as never, null, ); const session = { id: conversationId, provider: 'test-provider', modelId: 'test-model', piSession: { prompt: piPrompt }, listeners: new Set(), unsubscribe: vi.fn(), createdAt: Date.now(), promptCount: 0, channels: new Set(), skillPromptAdditions: [], sandboxDir: process.cwd(), allowedTools: null, userId: actorScope.userId, tenantId: actorScope.tenantId, metrics: { tokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }, modelSwitches: 0, messageCount: 0, lastActivityAt: new Date(0).toISOString(), }, } as unknown as AgentSession; const internals = service as unknown as { sessions: Map }; internals.sessions.set(conversationId, session); return { service, session }; } describe('required security wiring — malformed direct absence has zero effects', () => { it('FL-01 refuses command execution before any command effect when authorization is absent', async () => { const systemOverrideSet = vi.fn().mockResolvedValue(undefined); const executor = directExecutorWithoutAuthorization(systemOverrideSet); const payload: SlashCommandPayload = { command: 'system', args: 'authority that must not be stored', conversationId, }; let error: unknown; try { await executor.execute(payload, actorScope); } catch (caught: unknown) { error = caught; } expect .soft( error, 'absence read as permission: direct executor accepted missing command authorization', ) .toBeInstanceOf(Error); expect .soft( systemOverrideSet, 'absence read as permission: command effect occurred without command authorization', ) .not.toHaveBeenCalled(); }); it('FL-11 refuses prompt execution before any provider or session effect when system override authority is absent', async () => { const piPrompt = vi.fn().mockResolvedValue(undefined); const { service, session } = directAgentWithoutSystemOverride(piPrompt); let error: unknown; try { await service.prompt(conversationId, 'must not reach provider', actorScope); } catch (caught: unknown) { error = caught; } expect .soft( error, 'absence read as permission: direct session accepted missing system override authority', ) .toBeInstanceOf(Error); expect .soft( piPrompt, 'absence read as permission: provider prompt occurred without system override authority', ) .not.toHaveBeenCalled(); expect .soft( session.promptCount, 'absence read as permission: session state changed without system override authority', ) .toBe(0); }); });