Skip to main content
Glama
intecrel

Industrial MCP Server

by intecrel
audit-queries.ts14.2 kB
/** * Audit Query Utilities * Provides helper functions for querying and analyzing audit data */ import { getGlobalDatabaseManager } from './index' // Query interfaces export interface AuditQueryOptions { startDate?: Date | string endDate?: Date | string eventTypes?: string[] userIds?: string[] userEmails?: string[] riskLevels?: ('low' | 'medium' | 'high' | 'critical')[] results?: ('success' | 'failure' | 'warning')[] databaseTypes?: ('neo4j' | 'mysql')[] operationTypes?: ('CREATE' | 'MERGE' | 'SET' | 'READ')[] limit?: number offset?: number } export interface AuditSummary { totalEvents: number riskDistribution: Record<string, number> resultDistribution: Record<string, number> databaseOperations: Record<string, number> topUsers: Array<{ userEmail: string; eventCount: number }> recentHighRiskEvents: any[] } export interface DatabasePerformanceMetrics { databaseType: 'neo4j' | 'mysql' operationType: string avgExecutionTime: number maxExecutionTime: number totalOperations: number avgComplexity: number errorRate: number } export interface ComplianceReport { reportDate: string timeRange: { start: string; end: string } totalAuditEvents: number criticalEvents: number failedOperations: number unauthorizedAttempts: number dataChangeEvents: number retentionCompliance: { totalRetained: number oldestEvent: string complianceStatus: 'compliant' | 'warning' | 'violation' } } /** * Query audit events with filtering */ export async function queryAuditEvents(options: AuditQueryOptions = {}) { const dbManager = await getGlobalDatabaseManager() const mysql = dbManager.getConnection() // Use default connection (environment-based MySQL) if (!mysql.isConnected) { await mysql.connect() } let sql = ` SELECT ae.id, ae.timestamp, ae.event_type, ae.user_id, ae.user_email, ae.client_id, ae.ip_address, ae.session_id, ae.resource, ae.action, ae.result, ae.risk_level, ae.details, ae.created_at, dae.database_type, dae.operation_type, dae.query_hash, dae.affected_nodes, dae.affected_relationships, dae.execution_time_ms, dae.complexity_score, dae.transaction_id FROM audit_events ae LEFT JOIN database_audit_events dae ON ae.id = dae.audit_event_id WHERE 1=1 ` const values: any[] = [] // Build dynamic WHERE clauses if (options.startDate) { sql += ` AND ae.timestamp >= ?` values.push(options.startDate) } if (options.endDate) { sql += ` AND ae.timestamp <= ?` values.push(options.endDate) } if (options.eventTypes && options.eventTypes.length > 0) { const placeholders = options.eventTypes.map(() => '?').join(',') sql += ` AND ae.event_type IN (${placeholders})` values.push(...options.eventTypes) } if (options.userEmails && options.userEmails.length > 0) { const placeholders = options.userEmails.map(() => '?').join(',') sql += ` AND ae.user_email IN (${placeholders})` values.push(...options.userEmails) } if (options.riskLevels && options.riskLevels.length > 0) { const placeholders = options.riskLevels.map(() => '?').join(',') sql += ` AND ae.risk_level IN (${placeholders})` values.push(...options.riskLevels) } if (options.results && options.results.length > 0) { const placeholders = options.results.map(() => '?').join(',') sql += ` AND ae.result IN (${placeholders})` values.push(...options.results) } if (options.databaseTypes && options.databaseTypes.length > 0) { const placeholders = options.databaseTypes.map(() => '?').join(',') sql += ` AND dae.database_type IN (${placeholders})` values.push(...options.databaseTypes) } if (options.operationTypes && options.operationTypes.length > 0) { const placeholders = options.operationTypes.map(() => '?').join(',') sql += ` AND dae.operation_type IN (${placeholders})` values.push(...options.operationTypes) } sql += ` ORDER BY ae.timestamp DESC` if (options.limit) { sql += ` LIMIT ?` values.push(options.limit) if (options.offset) { sql += ` OFFSET ?` values.push(options.offset) } } const result = await mysql.query(sql, values) return result.data || [] } /** * Get audit summary statistics */ export async function getAuditSummary( startDate?: Date | string, endDate?: Date | string ): Promise<AuditSummary> { const dbManager = await getGlobalDatabaseManager() const mysql = dbManager.getConnection() // Use default connection (environment-based MySQL) if (!mysql.isConnected) { await mysql.connect() } const dateFilter = startDate && endDate ? `WHERE timestamp BETWEEN '${startDate.toString()}' AND '${endDate.toString()}'` : startDate ? `WHERE timestamp >= '${startDate.toString()}'` : endDate ? `WHERE timestamp <= '${endDate.toString()}'` : '' // Total events const totalResult = await mysql.query(` SELECT COUNT(*) as total FROM audit_events ${dateFilter} `) const totalEvents = totalResult.data?.[0]?.total || 0 // Risk distribution const riskResult = await mysql.query(` SELECT risk_level, COUNT(*) as count FROM audit_events ${dateFilter} GROUP BY risk_level `) const riskDistribution = (riskResult.data || []).reduce((acc: any, row: any) => { acc[row.risk_level] = row.count return acc }, {}) // Result distribution const resultResult = await mysql.query(` SELECT result, COUNT(*) as count FROM audit_events ${dateFilter} GROUP BY result `) const resultDistribution = (resultResult.data || []).reduce((acc: any, row: any) => { acc[row.result] = row.count return acc }, {}) // Database operations const dbResult = await mysql.query(` SELECT dae.database_type, dae.operation_type, COUNT(*) as count FROM database_audit_events dae JOIN audit_events ae ON dae.audit_event_id = ae.id ${dateFilter} GROUP BY dae.database_type, dae.operation_type `) const databaseOperations = (dbResult.data || []).reduce((acc: any, row: any) => { const key = `${row.database_type}.${row.operation_type}` acc[key] = row.count return acc }, {}) // Top users const userResult = await mysql.query(` SELECT user_email, COUNT(*) as event_count FROM audit_events ${dateFilter} AND user_email IS NOT NULL GROUP BY user_email ORDER BY event_count DESC LIMIT 10 `) const topUsers = userResult.data || [] // Recent high-risk events const highRiskResult = await mysql.query(` SELECT * FROM audit_events WHERE risk_level IN ('high', 'critical') ${dateFilter ? dateFilter : ''} ORDER BY timestamp DESC LIMIT 20 `) const recentHighRiskEvents = highRiskResult.data || [] return { totalEvents, riskDistribution, resultDistribution, databaseOperations, topUsers, recentHighRiskEvents } } /** * Get database performance metrics */ export async function getDatabasePerformanceMetrics( timeframe: string = '24h' ): Promise<DatabasePerformanceMetrics[]> { const dbManager = await getGlobalDatabaseManager() const mysql = dbManager.getConnection() // Use default connection (environment-based MySQL) if (!mysql.isConnected) { await mysql.connect() } const interval = timeframe === '24h' ? '24 HOUR' : timeframe === '7d' ? '7 DAY' : timeframe === '30d' ? '30 DAY' : '24 HOUR' const result = await mysql.query(` SELECT dae.database_type, dae.operation_type, AVG(dae.execution_time_ms) as avg_execution_time, MAX(dae.execution_time_ms) as max_execution_time, COUNT(*) as total_operations, AVG(dae.complexity_score) as avg_complexity, (COUNT(CASE WHEN ae.result = 'failure' THEN 1 END) * 100.0 / COUNT(*)) as error_rate FROM database_audit_events dae JOIN audit_events ae ON dae.audit_event_id = ae.id WHERE ae.timestamp >= DATE_SUB(NOW(), INTERVAL ${interval}) GROUP BY dae.database_type, dae.operation_type ORDER BY total_operations DESC `) return result.data || [] } /** * Generate compliance report */ export async function generateComplianceReport( startDate: Date | string, endDate: Date | string ): Promise<ComplianceReport> { const dbManager = await getGlobalDatabaseManager() const mysql = dbManager.getConnection() // Use default connection (environment-based MySQL) if (!mysql.isConnected) { await mysql.connect() } const dateFilter = `WHERE timestamp BETWEEN '${startDate}' AND '${endDate}'` // Total audit events in time range const totalResult = await mysql.query(` SELECT COUNT(*) as total FROM audit_events ${dateFilter} `) const totalAuditEvents = totalResult.data?.[0]?.total || 0 // Critical events const criticalResult = await mysql.query(` SELECT COUNT(*) as total FROM audit_events ${dateFilter} AND risk_level = 'critical' `) const criticalEvents = criticalResult.data?.[0]?.total || 0 // Failed operations const failureResult = await mysql.query(` SELECT COUNT(*) as total FROM audit_events ${dateFilter} AND result = 'failure' `) const failedOperations = failureResult.data?.[0]?.total || 0 // Unauthorized access attempts const unauthorizedResult = await mysql.query(` SELECT COUNT(*) as total FROM audit_events ${dateFilter} AND event_type LIKE 'security.unauthorized%' `) const unauthorizedAttempts = unauthorizedResult.data?.[0]?.total || 0 // Data change events (CREATE, MERGE, SET operations) const dataChangeResult = await mysql.query(` SELECT COUNT(*) as total FROM database_audit_events dae JOIN audit_events ae ON dae.audit_event_id = ae.id ${dateFilter.replace('WHERE', 'WHERE ae.')} AND dae.operation_type IN ('CREATE', 'MERGE', 'SET') `) const dataChangeEvents = dataChangeResult.data?.[0]?.total || 0 // Retention compliance check const retentionResult = await mysql.query(` SELECT COUNT(*) as total_retained, MIN(timestamp) as oldest_event FROM audit_events `) const retentionData = retentionResult.data?.[0] || {} const oldestEventDate = retentionData.oldest_event ? new Date(retentionData.oldest_event) : new Date() const daysSinceOldest = Math.floor((Date.now() - oldestEventDate.getTime()) / (1000 * 60 * 60 * 24)) // Determine compliance status (example: 7 years = 2555 days) const maxRetentionDays = 2555 let complianceStatus: 'compliant' | 'warning' | 'violation' = 'compliant' if (daysSinceOldest > maxRetentionDays + 30) { complianceStatus = 'violation' } else if (daysSinceOldest > maxRetentionDays) { complianceStatus = 'warning' } return { reportDate: new Date().toISOString(), timeRange: { start: startDate.toString(), end: endDate.toString() }, totalAuditEvents, criticalEvents, failedOperations, unauthorizedAttempts, dataChangeEvents, retentionCompliance: { totalRetained: retentionData.total_retained || 0, oldestEvent: retentionData.oldest_event || '', complianceStatus } } } /** * Search audit events by text */ export async function searchAuditEvents( searchTerm: string, options: Omit<AuditQueryOptions, 'eventTypes'> = {} ) { const searchOptions = { ...options, eventTypes: undefined // Clear event types for text search } const dbManager = await getGlobalDatabaseManager() const mysql = dbManager.getConnection() // Use default connection (environment-based MySQL) if (!mysql.isConnected) { await mysql.connect() } let sql = ` SELECT ae.id, ae.timestamp, ae.event_type, ae.user_email, ae.action, ae.result, ae.risk_level, ae.details, dae.database_type, dae.operation_type FROM audit_events ae LEFT JOIN database_audit_events dae ON ae.id = dae.audit_event_id WHERE ( ae.action LIKE ? OR ae.event_type LIKE ? OR ae.user_email LIKE ? OR JSON_EXTRACT(ae.details, '$') LIKE ? ) ` const values = [`%${searchTerm}%`, `%${searchTerm}%`, `%${searchTerm}%`, `%${searchTerm}%`] // Add additional filters if (searchOptions.startDate) { sql += ` AND ae.timestamp >= ?` values.push(searchOptions.startDate.toString()) } if (searchOptions.endDate) { sql += ` AND ae.timestamp <= ?` values.push(searchOptions.endDate.toString()) } if (searchOptions.riskLevels && searchOptions.riskLevels.length > 0) { const placeholders = searchOptions.riskLevels.map(() => '?').join(',') sql += ` AND ae.risk_level IN (${placeholders})` values.push(...searchOptions.riskLevels) } sql += ` ORDER BY ae.timestamp DESC` if (searchOptions.limit) { sql += ` LIMIT ?` values.push(searchOptions.limit.toString()) if (searchOptions.offset) { sql += ` OFFSET ?` values.push(searchOptions.offset.toString()) } } const result = await mysql.query(sql, values) return result.data || [] } /** * Get audit event timeline data for visualization */ export async function getAuditTimeline( timeframe: '24h' | '7d' | '30d' = '24h', groupBy: 'hour' | 'day' = 'hour' ) { const dbManager = await getGlobalDatabaseManager() const mysql = dbManager.getConnection() // Use default connection (environment-based MySQL) if (!mysql.isConnected) { await mysql.connect() } const interval = timeframe === '24h' ? '24 HOUR' : timeframe === '7d' ? '7 DAY' : '30 DAY' const dateFormat = groupBy === 'hour' ? '%Y-%m-%d %H:00:00' : '%Y-%m-%d' const result = await mysql.query(` SELECT DATE_FORMAT(timestamp, '${dateFormat}') as time_bucket, COUNT(*) as total_events, COUNT(CASE WHEN risk_level = 'critical' THEN 1 END) as critical_events, COUNT(CASE WHEN risk_level = 'high' THEN 1 END) as high_risk_events, COUNT(CASE WHEN result = 'failure' THEN 1 END) as failed_events FROM audit_events WHERE timestamp >= DATE_SUB(NOW(), INTERVAL ${interval}) GROUP BY time_bucket ORDER BY time_bucket `) return result.data || [] }

Latest Blog Posts

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/intecrel/industrial-mcp'

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