UNPKG

mcp-sanitizer

Version:

Comprehensive security sanitization library for Model Context Protocol (MCP) servers with trusted security libraries

295 lines (246 loc) 9.54 kB
/** * Configuration System Tests * * Tests for the MCP Sanitizer configuration system including * default configurations, security policies, and configuration * validation. */ const { createConfig, createConfigFromPolicy, createConfigBuilder, mergeConfig, validateConfig, getDefaultConfig, getSecurityPolicy, POLICY_NAMES } = require('../../../src/config') const MCPSanitizer = require('../../../src/index') describe('Configuration System', () => { describe('Default Configuration', () => { test('should create default configuration', () => { const config = createConfig() expect(config).toHaveProperty('allowedProtocols') expect(config).toHaveProperty('maxStringLength') expect(config).toHaveProperty('blockedPatterns') expect(config).toHaveProperty('sqlKeywords') expect(Array.isArray(config.allowedProtocols)).toBe(true) expect(Array.isArray(config.blockedPatterns)).toBe(true) expect(config.blockedPatterns.every(p => p instanceof RegExp)).toBe(true) }) test('should merge custom options with defaults', () => { const config = createConfig({ maxStringLength: 15000, allowedProtocols: ['https', 'mcp'] }) expect(config.maxStringLength).toBe(15000) expect(config.allowedProtocols).toEqual(['https', 'mcp']) expect(config.maxDepth).toBe(10) // Should keep default }) test('should preserve RegExp objects in configuration', () => { const config = getDefaultConfig() expect(Array.isArray(config.blockedPatterns)).toBe(true) expect(config.blockedPatterns.every(p => p instanceof RegExp)).toBe(true) }) }) describe('Security Policies', () => { test('should have all expected policies', () => { expect(POLICY_NAMES).toContain('STRICT') expect(POLICY_NAMES).toContain('MODERATE') expect(POLICY_NAMES).toContain('PERMISSIVE') expect(POLICY_NAMES).toContain('DEVELOPMENT') expect(POLICY_NAMES).toContain('PRODUCTION') }) test('should get security policy by name', () => { const strictPolicy = getSecurityPolicy('STRICT') expect(strictPolicy.allowedProtocols).toEqual(['https']) expect(strictPolicy.maxStringLength).toBe(1000) expect(strictPolicy.strictMode).toBe(true) expect(strictPolicy.blockOnSeverity).toBe('medium') }) test('should throw error for invalid policy name', () => { expect(() => { getSecurityPolicy('INVALID') }).toThrow('Invalid security policy') }) test('should create configuration from policy', () => { const config = createConfigFromPolicy('MODERATE') expect(config.allowedProtocols).toContain('http') expect(config.allowedProtocols).toContain('https') expect(config.maxStringLength).toBe(5000) expect(config.blockOnSeverity).toBe('high') }) test('should merge policy with customizations', () => { const config = createConfigFromPolicy('STRICT', { maxStringLength: 2000, allowedProtocols: ['https', 'mcp'] }) expect(config.maxStringLength).toBe(2000) expect(config.allowedProtocols).toEqual(['https', 'mcp']) expect(config.strictMode).toBe(true) // Should keep from policy }) }) describe('Configuration Builder', () => { test('should build configuration with fluent API', () => { const config = createConfigBuilder() .usePolicy('MODERATE') .maxStringLength(20000) .allowProtocols(['https', 'mcp']) .strictMode(true) .blockOnSeverity('medium') .build() expect(config.maxStringLength).toBe(20000) expect(config.allowedProtocols).toEqual(['https', 'mcp']) expect(config.strictMode).toBe(true) expect(config.blockOnSeverity).toBe('medium') }) test('should support pattern detection configuration', () => { const config = createConfigBuilder() .usePolicy('MODERATE') .patternDetection({ enableCommandInjection: true, enableSQLInjection: false, enableTemplateInjection: false }) .build() expect(config.patternDetection.enableCommandInjection).toBe(true) expect(config.patternDetection.enableSQLInjection).toBe(false) expect(config.patternDetection.enableTemplateInjection).toBe(false) }) test('should support custom configuration merge', () => { const config = createConfigBuilder() .usePolicy('MODERATE') .custom({ performance: { timeoutMs: 10000, enableCaching: true } }) .build() expect(config.performance.timeoutMs).toBe(10000) expect(config.performance.enableCaching).toBe(true) }) }) describe('Configuration Validation', () => { test('should validate valid configuration', () => { const config = createConfig({ allowedProtocols: ['https'], maxStringLength: 5000, maxDepth: 10, strictMode: true }) expect(() => validateConfig(config)).not.toThrow() }) test('should throw error for invalid protocol format', () => { expect(() => { validateConfig({ allowedProtocols: 'https' // Should be array }) }).toThrow('allowedProtocols must be an array') }) test('should throw error for invalid string length', () => { expect(() => { validateConfig({ maxStringLength: -1 }) }).toThrow('maxStringLength must be a non-negative number') }) test('should throw error for invalid blocked patterns', () => { expect(() => { validateConfig({ blockedPatterns: ['not-a-regex'] }) }).toThrow('All blocked patterns must be RegExp objects') }) }) describe('MCPSanitizer Integration', () => { test('should create sanitizer with policy string', () => { const sanitizer = new MCPSanitizer('STRICT') const summary = sanitizer.getConfigSummary() expect(summary.security.allowedProtocols).toEqual(['https']) expect(summary.security.strictMode).toBe(true) expect(summary.limits.maxStringLength).toBe(1000) }) test('should create sanitizer with policy object', () => { const sanitizer = new MCPSanitizer({ policy: 'MODERATE', maxStringLength: 8000 }) const summary = sanitizer.getConfigSummary() expect(summary.limits.maxStringLength).toBe(8000) expect(summary.security.blockOnSeverity).toBe('high') }) test('should update configuration at runtime', () => { const sanitizer = new MCPSanitizer('MODERATE') sanitizer.updateConfig({ maxStringLength: 12000, allowedProtocols: ['https'] }) const summary = sanitizer.getConfigSummary() expect(summary.limits.maxStringLength).toBe(12000) expect(summary.security.allowedProtocols).toEqual(['https']) }) test('should apply policy at runtime', () => { const sanitizer = new MCPSanitizer('PERMISSIVE') expect(sanitizer.getConfigSummary().limits.maxStringLength).toBe(50000) sanitizer.applyPolicy('STRICT', { maxStringLength: 1500 }) expect(sanitizer.getConfigSummary().limits.maxStringLength).toBe(1500) expect(sanitizer.getConfigSummary().security.strictMode).toBe(true) }) test('should check environment compatibility', () => { const sanitizer = new MCPSanitizer('DEVELOPMENT') const compatibility = sanitizer.checkEnvironmentCompatibility('production') expect(compatibility).toHaveProperty('compatible') expect(compatibility).toHaveProperty('warnings') expect(compatibility).toHaveProperty('recommendations') expect(Array.isArray(compatibility.warnings)).toBe(true) expect(Array.isArray(compatibility.recommendations)).toBe(true) }) }) describe('Configuration Merge', () => { test('should merge configurations properly', () => { const base = { allowedProtocols: ['http', 'https'], maxStringLength: 5000, contextSettings: { url: { maxURLLength: 2048 } } } const custom = { allowedProtocols: ['https', 'mcp'], maxDepth: 15, contextSettings: { url: { allowPrivateIPs: true }, filePath: { allowAbsolutePaths: false } } } const merged = mergeConfig(base, custom) // Arrays are completely replaced by the custom config expect(merged.allowedProtocols).toEqual(['https', 'mcp']) expect(merged.maxStringLength).toBe(5000) // From base expect(merged.maxDepth).toBe(15) // From custom expect(merged.contextSettings.url.maxURLLength).toBe(2048) // From base expect(merged.contextSettings.url.allowPrivateIPs).toBe(true) // From custom expect(merged.contextSettings.filePath.allowAbsolutePaths).toBe(false) // From custom }) test('should preserve RegExp objects during merge', () => { const base = { blockedPatterns: [/test1/, /test2/] } const custom = { blockedPatterns: [/test3/, /test4/] } const merged = mergeConfig(base, custom) expect(merged.blockedPatterns).toHaveLength(2) expect(merged.blockedPatterns.every(p => p instanceof RegExp)).toBe(true) expect(merged.blockedPatterns[0].source).toBe('test3') expect(merged.blockedPatterns[1].source).toBe('test4') }) }) })