Skip to main content
Glama

DollhouseMCP

by DollhouseMCP
securityMonitor.test.tsโ€ข9.92 kB
/** * Tests for SecurityMonitor */ import { jest } from '@jest/globals'; import { SecurityMonitor } from '../../../src/security/securityMonitor.js'; describe('SecurityMonitor', () => { let consoleErrorSpy: jest.SpiedFunction<typeof console.error>; let consoleWarnSpy: jest.SpiedFunction<typeof console.warn>; let consoleLogSpy: jest.SpiedFunction<typeof console.log>; beforeEach(() => { consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {}); // Clear any existing events // Use splice to clear the events array without reassigning SecurityMonitor['events'].splice(0, SecurityMonitor['events'].length); SecurityMonitor['eventCount'] = 0; }); afterEach(() => { consoleErrorSpy.mockRestore(); consoleWarnSpy.mockRestore(); consoleLogSpy.mockRestore(); }); describe('logSecurityEvent', () => { it('should store critical events in memory', () => { SecurityMonitor.logSecurityEvent({ type: 'CONTENT_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'test', details: 'Critical injection detected' }); const events = SecurityMonitor.getRecentEvents(); expect(events).toHaveLength(1); expect(events[0].type).toBe('CONTENT_INJECTION_ATTEMPT'); expect(events[0].severity).toBe('CRITICAL'); expect(events[0].details).toBe('Critical injection detected'); // In test environment, console output is suppressed expect(consoleErrorSpy).not.toHaveBeenCalled(); }); it('should store high severity events in memory', () => { SecurityMonitor.logSecurityEvent({ type: 'PATH_TRAVERSAL_ATTEMPT', severity: 'HIGH', source: 'test', details: 'Path traversal detected' }); const events = SecurityMonitor.getRecentEvents(); expect(events).toHaveLength(1); expect(events[0].severity).toBe('HIGH'); // In test environment, console output is suppressed expect(consoleErrorSpy).not.toHaveBeenCalled(); expect(consoleWarnSpy).not.toHaveBeenCalled(); }); it('should store medium severity events in memory', () => { SecurityMonitor.logSecurityEvent({ type: 'RATE_LIMIT_EXCEEDED', severity: 'MEDIUM', source: 'test', details: 'Rate limit hit' }); const events = SecurityMonitor.getRecentEvents(); expect(events).toHaveLength(1); expect(events[0].severity).toBe('MEDIUM'); // In test environment, console output is suppressed expect(consoleWarnSpy).not.toHaveBeenCalled(); expect(consoleErrorSpy).not.toHaveBeenCalled(); }); it('should store low severity events in memory', () => { SecurityMonitor.logSecurityEvent({ type: 'TOKEN_VALIDATION_FAILURE', severity: 'LOW', source: 'test', details: 'Invalid token format' }); const events = SecurityMonitor.getRecentEvents(); expect(events).toHaveLength(1); expect(events[0].severity).toBe('LOW'); // In test environment, console output is suppressed expect(consoleLogSpy).not.toHaveBeenCalled(); expect(consoleErrorSpy).not.toHaveBeenCalled(); }); it('should store events in memory', () => { SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'test', details: 'YAML injection' }); const events = SecurityMonitor.getRecentEvents(); expect(events).toHaveLength(1); expect(events[0].type).toBe('YAML_INJECTION_ATTEMPT'); expect(events[0].timestamp).toBeDefined(); expect(events[0].id).toMatch(/^SEC-\d+-\d+$/); }); it('should maintain circular buffer of MAX_EVENTS', () => { // Add more than MAX_EVENTS (1000) for (let i = 0; i < 1005; i++) { SecurityMonitor.logSecurityEvent({ type: 'CONTENT_INJECTION_ATTEMPT', severity: 'LOW', source: 'test', details: `Event ${i}` }); } const events = SecurityMonitor.getRecentEvents(2000); expect(events).toHaveLength(1000); // Should be capped at MAX_EVENTS }); }); describe('getRecentEvents', () => { beforeEach(() => { // Add test events SecurityMonitor.logSecurityEvent({ type: 'CONTENT_INJECTION_ATTEMPT', severity: 'HIGH', source: 'test1', details: 'Event 1' }); SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'test2', details: 'Event 2' }); SecurityMonitor.logSecurityEvent({ type: 'PATH_TRAVERSAL_ATTEMPT', severity: 'MEDIUM', source: 'test3', details: 'Event 3' }); }); it('should return specified number of recent events', () => { const events = SecurityMonitor.getRecentEvents(2); expect(events).toHaveLength(2); expect(events[0].details).toBe('Event 2'); expect(events[1].details).toBe('Event 3'); }); it('should return all events if count exceeds total', () => { const events = SecurityMonitor.getRecentEvents(10); expect(events).toHaveLength(3); }); }); describe('getEventsBySeverity', () => { beforeEach(() => { SecurityMonitor.logSecurityEvent({ type: 'CONTENT_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'test', details: 'Critical 1' }); SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'test', details: 'Critical 2' }); SecurityMonitor.logSecurityEvent({ type: 'PATH_TRAVERSAL_ATTEMPT', severity: 'HIGH', source: 'test', details: 'High 1' }); }); it('should filter events by severity', () => { const criticalEvents = SecurityMonitor.getEventsBySeverity('CRITICAL'); expect(criticalEvents).toHaveLength(2); const highEvents = SecurityMonitor.getEventsBySeverity('HIGH'); expect(highEvents).toHaveLength(1); const lowEvents = SecurityMonitor.getEventsBySeverity('LOW'); expect(lowEvents).toHaveLength(0); }); }); describe('getEventsByType', () => { beforeEach(() => { SecurityMonitor.logSecurityEvent({ type: 'CONTENT_INJECTION_ATTEMPT', severity: 'HIGH', source: 'test', details: 'Injection 1' }); SecurityMonitor.logSecurityEvent({ type: 'CONTENT_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'test', details: 'Injection 2' }); SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'test', details: 'YAML 1' }); }); it('should filter events by type', () => { const contentEvents = SecurityMonitor.getEventsByType('CONTENT_INJECTION_ATTEMPT'); expect(contentEvents).toHaveLength(2); const yamlEvents = SecurityMonitor.getEventsByType('YAML_INJECTION_ATTEMPT'); expect(yamlEvents).toHaveLength(1); }); }); describe('generateSecurityReport', () => { beforeEach(() => { SecurityMonitor.logSecurityEvent({ type: 'CONTENT_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'test', details: 'Critical injection' }); SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'HIGH', source: 'test', details: 'YAML issue' }); SecurityMonitor.logSecurityEvent({ type: 'PATH_TRAVERSAL_ATTEMPT', severity: 'MEDIUM', source: 'test', details: 'Path issue' }); SecurityMonitor.logSecurityEvent({ type: 'RATE_LIMIT_EXCEEDED', severity: 'LOW', source: 'test', details: 'Rate limit' }); }); it('should generate comprehensive security report', () => { const report = SecurityMonitor.generateSecurityReport(); expect(report.totalEvents).toBe(4); expect(report.eventsBySeverity.CRITICAL).toBe(1); expect(report.eventsBySeverity.HIGH).toBe(1); expect(report.eventsBySeverity.MEDIUM).toBe(1); expect(report.eventsBySeverity.LOW).toBe(1); expect(report.eventsByType['CONTENT_INJECTION_ATTEMPT']).toBe(1); expect(report.eventsByType['YAML_INJECTION_ATTEMPT']).toBe(1); expect(report.eventsByType['PATH_TRAVERSAL_ATTEMPT']).toBe(1); expect(report.eventsByType['RATE_LIMIT_EXCEEDED']).toBe(1); expect(report.recentCriticalEvents).toHaveLength(1); }); }); describe('clearOldEvents', () => { it('should remove events older than specified days', () => { // Add an old event const oldEvent = { type: 'CONTENT_INJECTION_ATTEMPT' as const, severity: 'HIGH' as const, source: 'test', details: 'Old event', timestamp: new Date(Date.now() - 8 * 24 * 60 * 60 * 1000).toISOString(), // 8 days old id: 'SEC-old-1' }; SecurityMonitor['events'].unshift(oldEvent); // Add a recent event SecurityMonitor.logSecurityEvent({ type: 'YAML_INJECTION_ATTEMPT', severity: 'CRITICAL', source: 'test', details: 'Recent event' }); expect(SecurityMonitor.getRecentEvents()).toHaveLength(2); // Clear events older than 7 days SecurityMonitor.clearOldEvents(7); const remainingEvents = SecurityMonitor.getRecentEvents(); expect(remainingEvents).toHaveLength(1); expect(remainingEvents[0].details).toBe('Recent event'); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/DollhouseMCP/DollhouseMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server