import type { Database } from 'bun:sqlite'; import { describe, expect, test } from 'bun:test'; import type { ModuleManifest } from '../manifest/schema'; import { checkCapabilitySecretAccess, getCapabilitySecret, isCapabilityFieldSecret, } from './secrets'; describe('Capability Secret Access', () => { describe('isCapabilityFieldSecret', () => { test('should return true when field is marked as secret', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'dns-external', name: 'DNS External', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'dns_external', version: '1.0.0', data: {}, secrets: [ { name: 'tsig', type: 'string', description: 'TSIG secret', readable_by: ['public_web'], }, { name: 'api_key', type: 'string', }, ], }, ], }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: () => ({ get: () => ({ manifest_data: JSON.stringify(providerManifest), }), }), } as unknown as Database; const result = isCapabilityFieldSecret('dns_external', 'tsig', mockDb); expect(result).toBe(true); }); test('should return true for any secret in the list', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'provider', name: 'Provider', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'test_capability', version: '1.0.0', data: {}, secrets: [ { name: 'api_key', type: 'string', }, { name: 'db_password', type: 'string', }, ], }, ], }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: () => ({ get: () => ({ manifest_data: JSON.stringify(providerManifest), }), }), } as unknown as Database; expect(isCapabilityFieldSecret('test_capability', 'api_key', mockDb)).toBe(true); expect(isCapabilityFieldSecret('test_capability', 'db_password', mockDb)).toBe(true); }); test('should return false when field is not in secrets list', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'dns-external', name: 'DNS External', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'dns_external', version: '1.0.0', data: {}, secrets: [ { name: 'tsig', type: 'string', }, ], }, ], }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: () => ({ get: () => ({ manifest_data: JSON.stringify(providerManifest), }), }), } as unknown as Database; const result = isCapabilityFieldSecret('dns_external', 'nameserver', mockDb); expect(result).toBe(false); }); test('should return false when capability has no secrets', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'provider', name: 'Provider', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'monitoring', version: '1.0.0', data: {}, // No secrets defined }, ], }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: () => ({ get: () => ({ manifest_data: JSON.stringify(providerManifest), }), }), } as unknown as Database; const result = isCapabilityFieldSecret('monitoring', 'any_field', mockDb); expect(result).toBe(false); }); test('should return false when provider manifest not found', () => { const mockDb = { prepare: () => ({ get: () => undefined, }), } as unknown as Database; const result = isCapabilityFieldSecret('unknown_capability', 'any_field', mockDb); expect(result).toBe(false); }); test('should match exact secret name', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'provider', name: 'Provider', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'test_capability', version: '1.0.0', data: {}, secrets: [ { name: 'api_key', type: 'string', }, ], }, ], }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: () => ({ get: () => ({ manifest_data: JSON.stringify(providerManifest), }), }), } as unknown as Database; // Exact match expect(isCapabilityFieldSecret('test_capability', 'api_key', mockDb)).toBe(true); // Substring should not match expect(isCapabilityFieldSecret('test_capability', 'api', mockDb)).toBe(false); expect(isCapabilityFieldSecret('test_capability', 'api_key_v2', mockDb)).toBe(false); }); }); describe('checkCapabilitySecretAccess', () => { test('should return true when consumer matches allowlist', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'dns-external', name: 'DNS External', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'dns_external', version: '1.0.0', data: {}, secrets: [ { name: 'tsig', type: 'string', readable_by: ['public_web'], }, ], }, ], }, variables: { owns: [], imports: [] }, }; const consumerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'caddy', name: 'Caddy', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'public_web', version: '1.0.0', data: {}, }, ], }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: (query: string) => ({ get: (_param: string) => { // Provider manifest query if (query.includes('JOIN capabilities')) { return { manifest_data: JSON.stringify(providerManifest), }; } // Consumer manifest query if (query.includes('WHERE id = ?')) { return { manifest_data: JSON.stringify(consumerManifest), }; } return undefined; }, }), } as unknown as Database; const result = checkCapabilitySecretAccess('caddy', 'dns_external', 'tsig', mockDb); expect(result).toBe(true); }); test('should return false when consumer does not match allowlist', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'dns-external', name: 'DNS External', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'dns_external', version: '1.0.0', data: {}, secrets: [ { name: 'tsig', type: 'string', readable_by: ['public_web'], }, ], }, ], }, variables: { owns: [], imports: [] }, }; const consumerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'some-app', name: 'Some App', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'monitoring', version: '1.0.0', data: {}, }, ], }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: (query: string) => ({ get: () => { if (query.includes('JOIN capabilities')) { return { manifest_data: JSON.stringify(providerManifest), }; } if (query.includes('WHERE id = ?')) { return { manifest_data: JSON.stringify(consumerManifest), }; } return undefined; }, }), } as unknown as Database; const result = checkCapabilitySecretAccess('some-app', 'dns_external', 'tsig', mockDb); expect(result).toBe(false); }); test('should return true when secret has no readable_by restriction', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'provider', name: 'Provider', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'test_capability', version: '1.0.0', data: {}, secrets: [ { name: 'api_key', type: 'string', // No readable_by - accessible to all }, ], }, ], }, variables: { owns: [], imports: [] }, }; const consumerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'consumer', name: 'Consumer', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [] }, variables: { owns: [], imports: [] }, // No capabilities provided }; const mockDb = { prepare: (query: string) => ({ get: () => { if (query.includes('JOIN capabilities')) { return { manifest_data: JSON.stringify(providerManifest), }; } if (query.includes('WHERE id = ?')) { return { manifest_data: JSON.stringify(consumerManifest), }; } return undefined; }, }), } as unknown as Database; const result = checkCapabilitySecretAccess('consumer', 'test_capability', 'api_key', mockDb); expect(result).toBe(true); }); test('should return true when readable_by is empty array', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'provider', name: 'Provider', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'test_capability', version: '1.0.0', data: {}, secrets: [ { name: 'api_key', type: 'string', readable_by: [], // Empty array - no restrictions }, ], }, ], }, variables: { owns: [], imports: [] }, }; const consumerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'consumer', name: 'Consumer', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [] }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: (query: string) => ({ get: () => { if (query.includes('JOIN capabilities')) { return { manifest_data: JSON.stringify(providerManifest), }; } if (query.includes('WHERE id = ?')) { return { manifest_data: JSON.stringify(consumerManifest), }; } return undefined; }, }), } as unknown as Database; const result = checkCapabilitySecretAccess('consumer', 'test_capability', 'api_key', mockDb); expect(result).toBe(true); }); test('should return false when provider not found', () => { const mockDb = { prepare: (_query: string) => ({ get: () => undefined, }), } as unknown as Database; const result = checkCapabilitySecretAccess( 'consumer', 'unknown_capability', 'secret', mockDb, ); expect(result).toBe(false); }); test('should return false when consumer not found', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'provider', name: 'Provider', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'test_capability', version: '1.0.0', data: {}, secrets: [ { name: 'secret', type: 'string', readable_by: ['public_web'], }, ], }, ], }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: (query: string) => ({ get: () => { if (query.includes('JOIN capabilities')) { return { manifest_data: JSON.stringify(providerManifest), }; } // Consumer not found return undefined; }, }), } as unknown as Database; const result = checkCapabilitySecretAccess( 'unknown_consumer', 'test_capability', 'secret', mockDb, ); expect(result).toBe(false); }); test('should return false when secret not found in capability', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'provider', name: 'Provider', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'test_capability', version: '1.0.0', data: {}, secrets: [ { name: 'api_key', type: 'string', }, ], }, ], }, variables: { owns: [], imports: [] }, }; const consumerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'consumer', name: 'Consumer', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [] }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: (query: string) => ({ get: () => { if (query.includes('JOIN capabilities')) { return { manifest_data: JSON.stringify(providerManifest), }; } if (query.includes('WHERE id = ?')) { return { manifest_data: JSON.stringify(consumerManifest), }; } return undefined; }, }), } as unknown as Database; const result = checkCapabilitySecretAccess( 'consumer', 'test_capability', 'unknown_secret', mockDb, ); expect(result).toBe(false); }); test('should return false when capability has no secrets', () => { const providerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'provider', name: 'Provider', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [ { name: 'test_capability', version: '1.0.0', data: {}, // No secrets }, ], }, variables: { owns: [], imports: [] }, }; const consumerManifest: ModuleManifest = { celilo_contract: '1.0', id: 'consumer', name: 'Consumer', version: '1.0.0', description: 'Test', requires: { capabilities: [] }, provides: { capabilities: [] }, variables: { owns: [], imports: [] }, }; const mockDb = { prepare: (query: string) => ({ get: () => { if (query.includes('JOIN capabilities')) { return { manifest_data: JSON.stringify(providerManifest), }; } if (query.includes('WHERE id = ?')) { return { manifest_data: JSON.stringify(consumerManifest), }; } return undefined; }, }), } as unknown as Database; const result = checkCapabilitySecretAccess('consumer', 'test_capability', 'api_key', mockDb); expect(result).toBe(false); }); }); describe('getCapabilitySecret', () => { test('should throw error when capability not found', async () => { const mockDb = { prepare: () => ({ get: () => undefined, }), } as unknown as Database; await expect(getCapabilitySecret('unknown_capability', 'secret', mockDb)).rejects.toThrow( "Provider manifest not found for capability 'unknown_capability'", ); }); test('should throw error when secret not found', async () => { // Mock manifest with capability but without the requested secret const manifest = { provides: { capabilities: [ { name: 'dns_external', version: '1.0.0', secrets: [{ name: 'tsig_key', description: 'TSIG key' }], }, ], }, }; const mockDb = { prepare: (query: string) => ({ get: (_param?: unknown) => { // Return manifest data for getProviderManifest if (query.includes('SELECT p.manifest_data')) { return { manifest_data: JSON.stringify(manifest) }; } return undefined; }, }), } as unknown as Database; await expect(getCapabilitySecret('dns_external', 'unknown_secret', mockDb)).rejects.toThrow( "Secret 'unknown_secret' not defined in capability 'dns_external'", ); }); test('should decrypt and return secret when found', async () => { // Note: This test would require mocking the encryption module // For now, we test that it queries correctly and attempts decryption const mockDb = { prepare: (query: string) => ({ get: (_param1?: unknown, _param2?: unknown) => { if (query.includes('SELECT id FROM capabilities')) { return { id: 1 }; } if (query.includes('SELECT encrypted_value')) { return { encrypted_value: 'encrypted_data', iv: 'initialization_vector', auth_tag: 'auth_tag', }; } return undefined; }, }), } as unknown as Database; // This will fail at decryption with actual master key // but proves the query logic works await expect(getCapabilitySecret('dns_external', 'tsig', mockDb)).rejects.toThrow(); }); }); });