UNPKG

@crazyrabbitltc/railway-mcp

Version:

Railway MCP Server - 146+ tools with 100% Railway API coverage, comprehensive MCP testing framework, and real infrastructure management through AI assistants. Enhanced version with enterprise features, based on original work by Jason Tan.

272 lines (271 loc) 12.2 kB
import { BaseService } from "./base.service.js"; import { createSuccessResponse, createErrorResponse, formatError } from "../utils/responses.js"; export class SecurityService extends BaseService { constructor() { super(); } async getAuditLogs(projectId, startDate, endDate, limit = 100) { try { const logs = await this.client.security.getAuditLogs(projectId, startDate, endDate, limit); const successCount = logs.filter(log => log.success).length; const failureCount = logs.length - successCount; const actionTypes = logs.reduce((acc, log) => { acc[log.action] = (acc[log.action] || 0) + 1; return acc; }, {}); const topActions = Object.entries(actionTypes) .sort(([, a], [, b]) => b - a) .slice(0, 5); return createSuccessResponse({ text: `Found ${logs.length} audit log entries (${successCount} successful, ${failureCount} failed)`, data: { summary: { totalLogs: logs.length, successCount, failureCount, dateRange: { from: startDate || 'N/A', to: endDate || 'N/A' } }, topActions: topActions.map(([action, count]) => ({ action, count })), logs: logs.map(log => ({ id: log.id, timestamp: log.timestamp, user: log.userEmail, action: log.action, resource: `${log.resourceType}:${log.resourceId}`, success: log.success, ipAddress: log.ipAddress, userAgent: log.userAgent?.substring(0, 50) + '...' || 'N/A' })) } }); } catch (error) { return createErrorResponse(`Failed to get audit logs: ${formatError(error)}`); } } async getVulnerabilities(projectId) { try { const vulnerabilities = await this.client.security.getVulnerabilities(projectId); const criticalCount = vulnerabilities.filter(v => v.severity === 'CRITICAL').length; const highCount = vulnerabilities.filter(v => v.severity === 'HIGH').length; const mediumCount = vulnerabilities.filter(v => v.severity === 'MEDIUM').length; const lowCount = vulnerabilities.filter(v => v.severity === 'LOW').length; const openCount = vulnerabilities.filter(v => v.status === 'OPEN').length; const byCategory = vulnerabilities.reduce((acc, vuln) => { if (!acc[vuln.category]) acc[vuln.category] = []; acc[vuln.category].push(vuln); return acc; }, {}); return createSuccessResponse({ text: `Found ${vulnerabilities.length} vulnerabilities (${openCount} open, ${criticalCount} critical)`, data: { projectId, summary: { totalCount: vulnerabilities.length, openCount, bySeverity: { critical: criticalCount, high: highCount, medium: mediumCount, low: lowCount } }, byCategory: Object.entries(byCategory).map(([category, categoryVulns]) => ({ category, count: categoryVulns.length, openCount: categoryVulns.filter(v => v.status === 'OPEN').length })), vulnerabilities: vulnerabilities.map(vuln => ({ id: vuln.id, severity: vuln.severity, category: vuln.category, title: vuln.title, cve: vuln.cve || 'N/A', status: vuln.status, affectedComponent: vuln.affectedComponent, discoveredAt: vuln.discoveredAt, serviceId: vuln.serviceId })) } }); } catch (error) { return createErrorResponse(`Failed to get vulnerabilities: ${formatError(error)}`); } } async triggerSecurityScan(projectId, serviceId) { try { const scan = await this.client.security.triggerSecurityScan(projectId, serviceId); return createSuccessResponse({ text: `Security scan initiated`, data: { scanId: scan.scanId, status: scan.status, projectId, serviceId: serviceId || 'All services', message: 'Scan will complete in 5-15 minutes. Use security-vulnerabilities to check results.' } }); } catch (error) { return createErrorResponse(`Failed to trigger security scan: ${formatError(error)}`); } } async listAccessTokens() { try { const tokens = await this.client.security.listAccessTokens(); const activeCount = tokens.filter(t => t.isActive).length; const expiredCount = tokens.filter(t => t.expiresAt && new Date(t.expiresAt) < new Date()).length; return createSuccessResponse({ text: `Found ${tokens.length} access tokens (${activeCount} active, ${expiredCount} expired)`, data: { summary: { totalCount: tokens.length, activeCount, expiredCount }, tokens: tokens.map(token => ({ id: token.id, name: token.name, permissions: token.permissions, isActive: token.isActive, lastUsed: token.lastUsed || 'Never', expiresAt: token.expiresAt || 'Never', createdAt: token.createdAt })) } }); } catch (error) { return createErrorResponse(`Failed to list access tokens: ${formatError(error)}`); } } async createAccessToken(name, permissions, expiresAt) { try { const result = await this.client.security.createAccessToken(name, permissions, expiresAt); return createSuccessResponse({ text: `Access token "${name}" created successfully`, data: { token: { id: result.token.id, name: result.token.name, permissions: result.token.permissions, expiresAt: result.token.expiresAt || 'Never', createdAt: result.token.createdAt }, secret: result.secret, warning: 'Store this secret securely - it will not be shown again!' } }); } catch (error) { return createErrorResponse(`Failed to create access token: ${formatError(error)}`); } } async revokeAccessToken(tokenId) { try { const success = await this.client.security.revokeAccessToken(tokenId); if (success) { return createSuccessResponse({ text: "Access token revoked successfully" }); } else { return createErrorResponse("Failed to revoke access token"); } } catch (error) { return createErrorResponse(`Failed to revoke access token: ${formatError(error)}`); } } async listIPAllowLists(projectId) { try { const allowLists = await this.client.security.listIPAllowLists(projectId); const activeCount = allowLists.filter(list => list.isActive).length; const totalIPs = allowLists.reduce((sum, list) => sum + list.ipRanges.length, 0); return createSuccessResponse({ text: `Found ${allowLists.length} IP allow lists (${activeCount} active, ${totalIPs} total IPs)`, data: { projectId, summary: { totalLists: allowLists.length, activeCount, totalIPs }, allowLists: allowLists.map(list => ({ id: list.id, name: list.name, description: list.description || 'No description', ipCount: list.ipRanges.length, isActive: list.isActive, ipRanges: list.ipRanges, createdAt: list.createdAt, updatedAt: list.updatedAt })) } }); } catch (error) { return createErrorResponse(`Failed to list IP allow lists: ${formatError(error)}`); } } async createIPAllowList(projectId, name, ipRanges, description) { try { const allowList = await this.client.security.createIPAllowList(projectId, name, ipRanges, description); return createSuccessResponse({ text: `IP allow list "${name}" created with ${ipRanges.length} IP ranges`, data: { id: allowList.id, name: allowList.name, description: allowList.description, ipRanges: allowList.ipRanges, isActive: allowList.isActive, createdAt: allowList.createdAt } }); } catch (error) { return createErrorResponse(`Failed to create IP allow list: ${formatError(error)}`); } } async generateComplianceReport(projectId, framework) { try { const report = await this.client.security.generateComplianceReport(projectId, framework); const passCount = report.findings.filter(f => f.status === 'PASS').length; const failCount = report.findings.filter(f => f.status === 'FAIL').length; const warningCount = report.findings.filter(f => f.status === 'WARNING').length; return createSuccessResponse({ text: `${framework} compliance report generated - Score: ${report.score}% (${passCount} pass, ${failCount} fail, ${warningCount} warnings)`, data: { id: report.id, projectId: report.projectId, framework: report.framework, status: report.status, score: `${report.score}%`, summary: { totalControls: report.findings.length, passCount, failCount, warningCount }, findings: report.findings.map(finding => ({ control: finding.control, status: finding.status, description: finding.description, recommendation: finding.recommendation || 'No specific recommendation' })), generatedAt: report.generatedAt, expiresAt: report.expiresAt } }); } catch (error) { return createErrorResponse(`Failed to generate compliance report: ${formatError(error)}`); } } } export const securityService = new SecurityService();