aws-security-mcp 0.4.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/dashboard.ts","../../src/commands/deploy-dashboard.ts","../../src/index.ts","../../src/version.ts","../../src/utils/aws-client.ts","../../src/utils/assume-role.ts","../../src/utils/org-accounts.ts","../../src/scanners/runner.ts","../../src/scanners/service-detection.ts","../../src/utils/risk-scoring.ts","../../src/scanners/secret-exposure.ts","../../src/scanners/ssl-certificate.ts","../../src/scanners/dns-dangling.ts","../../src/scanners/network-reachability.ts","../../src/scanners/iam-privilege-escalation.ts","../../src/scanners/public-access-verify.ts","../../src/scanners/tag-compliance.ts","../../src/scanners/idle-resources.ts","../../src/scanners/disaster-recovery.ts","../../src/scanners/security-hub-findings.ts","../../src/scanners/guardduty-findings.ts","../../src/scanners/inspector-findings.ts","../../src/scanners/trusted-advisor-findings.ts","../../src/scanners/config-rules-findings.ts","../../src/scanners/access-analyzer-findings.ts","../../src/scanners/patch-compliance-findings.ts","../../src/tools/report-tool.ts","../../src/tools/mlps-report.ts","../../src/tools/html-report.ts","../../src/tools/save-results.ts","../../src/tools/scan-groups.ts","../../src/resources/index.ts","../../bin/aws-security-mcp.ts"],"sourcesContent":["import { createServer } from \"node:http\";\nimport { readFile } from \"node:fs/promises\";\nimport { join, extname, resolve } from \"node:path\";\nimport { existsSync, copyFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { exec } from \"node:child_process\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = join(__filename, \"..\");\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html\",\n \".js\": \"text/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nexport function startDashboard(port = 3000): void {\n // dashboard/dist is two levels up from dist/src/commands/\n const dashboardDir = join(__dirname, \"../../dashboard/dist\");\n\n if (!existsSync(dashboardDir)) {\n console.error(\n `Dashboard not built. Run \"npm run build:dashboard\" first.\\n` +\n `Expected: ${dashboardDir}`,\n );\n process.exit(1);\n }\n\n // Copy real data.json if available\n const dataSource = join(\n process.env.HOME || process.env.USERPROFILE || \"~\",\n \".aws-security/dashboard/data.json\",\n );\n const dataDest = join(dashboardDir, \"data.json\");\n if (existsSync(dataSource)) {\n copyFileSync(dataSource, dataDest);\n console.log(`Loaded scan data from ${dataSource}`);\n } else {\n console.log(\n \"No scan data found at ~/.aws-security/dashboard/data.json — using bundled sample data\",\n );\n }\n\n const resolvedBase = resolve(dashboardDir);\n\n const server = createServer(async (req, res) => {\n const url = req.url?.split(\"?\")[0] ?? \"/\";\n let filePath = resolve(\n join(dashboardDir, url === \"/\" ? \"index.html\" : url),\n );\n\n // Ensure the resolved path is within dashboardDir\n if (!filePath.startsWith(resolvedBase + \"/\") && filePath !== resolvedBase) {\n res.writeHead(403);\n res.end(\"Forbidden\");\n return;\n }\n\n // SPA fallback: if file doesn't exist and isn't a static asset, serve index.html\n if (!existsSync(filePath)) {\n filePath = join(dashboardDir, \"index.html\");\n }\n\n try {\n const content = await readFile(filePath);\n const ext = extname(filePath);\n res.writeHead(200, {\n \"Content-Type\": MIME_TYPES[ext] || \"application/octet-stream\",\n });\n res.end(content);\n } catch {\n res.writeHead(404);\n res.end(\"Not found\");\n }\n });\n\n server.listen(port, () => {\n const url = `http://localhost:${port}`;\n console.log(`\\nAWS Security Dashboard: ${url}\\n`);\n console.log(\"Press Ctrl+C to stop.\\n\");\n\n // Try to open browser\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"start\"\n : \"xdg-open\";\n exec(`${cmd} ${url}`, () => {\n // ignore errors — browser open is best-effort\n });\n });\n\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n console.error(`Port ${port} is already in use. Try --port <other>`);\n process.exit(1);\n }\n throw err;\n });\n}\n","import { readdirSync, readFileSync, existsSync, copyFileSync } from \"node:fs\";\nimport { join, extname, relative } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n S3Client,\n PutObjectCommand,\n PutBucketWebsiteCommand,\n PutBucketPolicyCommand,\n} from \"@aws-sdk/client-s3\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = join(__filename, \"..\");\n\nconst CONTENT_TYPES: Record<string, string> = {\n \".html\": \"text/html\",\n \".js\": \"text/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nfunction collectFiles(dir: string): string[] {\n const files: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...collectFiles(full));\n } else {\n files.push(full);\n }\n }\n return files;\n}\n\nexport async function deployDashboard(\n bucket: string,\n region: string,\n): Promise<void> {\n const dashboardDir = join(__dirname, \"../../dashboard/dist\");\n\n if (!existsSync(dashboardDir)) {\n console.error(\n `Dashboard not built. Run \"npm run build:dashboard\" first.\\n` +\n `Expected: ${dashboardDir}`,\n );\n process.exit(1);\n }\n\n // Copy real data.json if available\n const dataSource = join(\n process.env.HOME || process.env.USERPROFILE || \"~\",\n \".aws-security/dashboard/data.json\",\n );\n const dataDest = join(dashboardDir, \"data.json\");\n if (existsSync(dataSource)) {\n copyFileSync(dataSource, dataDest);\n console.log(`Loaded scan data from ${dataSource}`);\n } else {\n console.log(\n \"No scan data at ~/.aws-security/dashboard/data.json — deploying with bundled sample data\",\n );\n }\n\n const s3 = new S3Client({ region });\n\n // Configure static website hosting\n console.log(`Configuring s3://${bucket} for static website hosting...`);\n await s3.send(\n new PutBucketWebsiteCommand({\n Bucket: bucket,\n WebsiteConfiguration: {\n IndexDocument: { Suffix: \"index.html\" },\n ErrorDocument: { Key: \"index.html\" }, // SPA fallback\n },\n }),\n );\n\n // Set bucket policy for public read access\n const partition = region.startsWith(\"cn-\") ? \"aws-cn\" : \"aws\";\n console.log(`Setting public read bucket policy on s3://${bucket}...`);\n await s3.send(\n new PutBucketPolicyCommand({\n Bucket: bucket,\n Policy: JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Sid: \"PublicReadGetObject\",\n Effect: \"Allow\",\n Principal: \"*\",\n Action: \"s3:GetObject\",\n Resource: `arn:${partition}:s3:::${bucket}/*`,\n },\n ],\n }),\n }),\n );\n\n // Upload all files\n const files = collectFiles(dashboardDir);\n console.log(`Uploading ${files.length} files to s3://${bucket}...`);\n\n for (const filePath of files) {\n const key = relative(dashboardDir, filePath);\n const ext = extname(filePath);\n const contentType = CONTENT_TYPES[ext] || \"application/octet-stream\";\n const body = readFileSync(filePath);\n\n await s3.send(\n new PutObjectCommand({\n Bucket: bucket,\n Key: key,\n Body: body,\n ContentType: contentType,\n }),\n );\n console.log(` ${key}`);\n }\n\n const domain = region.startsWith(\"cn-\") ? \"amazonaws.com.cn\" : \"amazonaws.com\";\n const websiteUrl = `http://${bucket}.s3-website.${region}.${domain}`;\n console.log(`\\nDashboard deployed successfully!`);\n console.log(`Website URL: ${websiteUrl}`);\n console.log(\n \"\\nNote: Ensure S3 Block Public Access is disabled on this bucket for the website to be accessible.\\n\",\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\n\nimport { VERSION } from \"./version.js\";\nimport type { Scanner } from \"./scanners/base.js\";\nimport { runAllScanners, runMultiAccountScanners } from \"./scanners/runner.js\";\nimport { ServiceDetectionScanner } from \"./scanners/service-detection.js\";\nimport type { ServiceDetectionResult } from \"./scanners/service-detection.js\";\nimport { SecretExposureScanner } from \"./scanners/secret-exposure.js\";\nimport { SslCertificateScanner } from \"./scanners/ssl-certificate.js\";\nimport { DnsDanglingScanner } from \"./scanners/dns-dangling.js\";\nimport { NetworkReachabilityScanner } from \"./scanners/network-reachability.js\";\nimport { IamPrivilegeEscalationScanner } from \"./scanners/iam-privilege-escalation.js\";\nimport { PublicAccessVerifyScanner } from \"./scanners/public-access-verify.js\";\nimport { TagComplianceScanner } from \"./scanners/tag-compliance.js\";\nimport { IdleResourcesScanner } from \"./scanners/idle-resources.js\";\nimport { DisasterRecoveryScanner } from \"./scanners/disaster-recovery.js\";\nimport { SecurityHubFindingsScanner } from \"./scanners/security-hub-findings.js\";\nimport { GuardDutyFindingsScanner } from \"./scanners/guardduty-findings.js\";\nimport { InspectorFindingsScanner } from \"./scanners/inspector-findings.js\";\nimport { TrustedAdvisorFindingsScanner } from \"./scanners/trusted-advisor-findings.js\";\nimport { ConfigRulesFindingsScanner } from \"./scanners/config-rules-findings.js\";\nimport { AccessAnalyzerFindingsScanner } from \"./scanners/access-analyzer-findings.js\";\nimport { PatchComplianceFindingsScanner } from \"./scanners/patch-compliance-findings.js\";\nimport { generateMarkdownReport } from \"./tools/report-tool.js\";\nimport { generateMlps3Report } from \"./tools/mlps-report.js\";\nimport { generateHtmlReport, generateMlps3HtmlReport } from \"./tools/html-report.js\";\nimport { saveResults } from \"./tools/save-results.js\";\nimport { SCAN_GROUPS, applyFindingsFilter } from \"./tools/scan-groups.js\";\nimport {\n SECURITY_RULES_CONTENT,\n RISK_SCORING_CONTENT,\n} from \"./resources/index.js\";\nimport { getPartition, getAccountId } from \"./utils/aws-client.js\";\nimport { listOrgAccounts } from \"./utils/org-accounts.js\";\nimport type { FullScanResult, ScanResult, ScanContext } from \"./types.js\";\nimport { readFileSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\n\nexport { type Scanner } from \"./scanners/base.js\";\nexport { runAllScanners, runMultiAccountScanners } from \"./scanners/runner.js\";\nexport { assumeRole, buildRoleArn, getCurrentAccountId } from \"./utils/assume-role.js\";\nexport { listOrgAccounts, type OrgAccount } from \"./utils/org-accounts.js\";\nexport { generateMarkdownReport } from \"./tools/report-tool.js\";\nexport { generateHtmlReport, generateMlps3HtmlReport } from \"./tools/html-report.js\";\nexport { saveResults, calculateScore } from \"./tools/save-results.js\";\nexport type {\n Finding,\n ScanResult,\n ScanContext,\n FullScanResult,\n DashboardData,\n DashboardHistoryEntry,\n Severity,\n Priority,\n} from \"./types.js\";\n\nconst MODULE_DESCRIPTIONS: Record<string, string> = {\n service_detection:\n \"Detects which AWS security services (Security Hub, GuardDuty, Inspector, Config, Macie) are enabled and assesses security maturity.\",\n secret_exposure:\n \"Checks Lambda env vars and EC2 userData for exposed secrets (AWS keys, private keys, passwords).\",\n ssl_certificate:\n \"Checks ACM certificates for expiry, failed status, and upcoming renewals.\",\n dns_dangling:\n \"Checks Route53 CNAME records for dangling DNS (subdomain takeover risk).\",\n network_reachability:\n \"Analyzes true network reachability by combining Security Group + NACL rules for public EC2 instances.\",\n iam_privilege_escalation:\n \"Detects IAM privilege escalation paths — users/roles that can escalate to admin via policy manipulation, role creation, or service abuse.\",\n public_access_verify:\n \"Verifies actual public accessibility of resources marked as public (S3 HTTP check, RDS DNS resolution).\",\n tag_compliance:\n \"Checks EC2, RDS, and S3 resources for required tags (Environment, Project, Owner).\",\n idle_resources:\n \"Finds unused/idle AWS resources (unattached EBS volumes, unused EIPs, stopped instances, unused security groups) that waste money and increase attack surface.\",\n disaster_recovery:\n \"Assesses disaster recovery readiness — RDS Multi-AZ & backups, EBS snapshot coverage, S3 versioning & cross-region replication.\",\n security_hub_findings:\n \"Aggregates active findings from AWS Security Hub — replaces individual config scanners with centralized compliance checks.\",\n guardduty_findings:\n \"Aggregates threat detection findings from Amazon GuardDuty — account compromise, instance compromise, and reconnaissance.\",\n inspector_findings:\n \"Aggregates vulnerability findings from Amazon Inspector — CVEs in EC2, Lambda, and container images.\",\n trusted_advisor_findings:\n \"Aggregates security checks from AWS Trusted Advisor — requires Business or Enterprise Support plan.\",\n config_rules_findings:\n \"Pulls non-compliant AWS Config Rule evaluation results — configuration compliance violations across all resource types.\",\n access_analyzer_findings:\n \"Pulls active IAM Access Analyzer findings — resources accessible from outside the account (external principals, public access).\",\n patch_compliance_findings:\n \"Checks SSM Patch Manager compliance — managed instances with missing or failed security and system patches.\",\n};\n\nfunction summarizeResult(result: FullScanResult): string {\n const { summary } = result;\n const lines = [\n `Scan complete for account ${result.accountId} in ${result.region}.`,\n `Total findings: ${summary.totalFindings} (${summary.critical} Critical, ${summary.high} High, ${summary.medium} Medium, ${summary.low} Low)`,\n `Modules: ${summary.modulesSuccess} succeeded, ${summary.modulesError} errored`,\n ];\n return lines.join(\"\\n\");\n}\n\nfunction summarizeScanResult(result: ScanResult): string {\n const lines = [\n `Module: ${result.module} — ${result.status}`,\n `Resources scanned: ${result.resourcesScanned}, Findings: ${result.findingsCount}`,\n ];\n if (result.warnings?.length) {\n lines.push(`Warnings: ${result.warnings.length}`);\n }\n return lines.join(\"\\n\");\n}\n\nasync function buildScanContext(region: string): Promise<ScanContext> {\n let accountId: string;\n try {\n accountId = await getAccountId(region);\n } catch {\n accountId = \"unknown\";\n }\n return { region, partition: getPartition(region), accountId };\n}\n\nexport function createServer(defaultRegion: string): McpServer {\n const server = new McpServer(\n { name: \"aws-security-mcp\", version: VERSION },\n { capabilities: { resources: {}, tools: {}, prompts: {} } },\n );\n\n const allScanners: Scanner[] = [\n new ServiceDetectionScanner(),\n new SecretExposureScanner(),\n new SslCertificateScanner(),\n new DnsDanglingScanner(),\n new NetworkReachabilityScanner(),\n new IamPrivilegeEscalationScanner(),\n new PublicAccessVerifyScanner(),\n new TagComplianceScanner(),\n new IdleResourcesScanner(),\n new DisasterRecoveryScanner(),\n new SecurityHubFindingsScanner(),\n new GuardDutyFindingsScanner(),\n new InspectorFindingsScanner(),\n new TrustedAdvisorFindingsScanner(),\n new ConfigRulesFindingsScanner(),\n new AccessAnalyzerFindingsScanner(),\n new PatchComplianceFindingsScanner(),\n ];\n\n const scannerMap = new Map<string, Scanner>();\n for (const s of allScanners) {\n scannerMap.set(s.moduleName, s);\n }\n\n // --- Tools ---\n\n // 1. scan_all\n server.tool(\n \"scan_all\",\n \"Run all security scanners in parallel (including service detection). Read-only. Does not modify any AWS resources. Supports multi-account org scanning.\",\n {\n region: z.string().optional().describe(\"AWS region to scan (default: server region)\"),\n org_mode: z.boolean().optional().describe(\"Enable multi-account scanning via AWS Organizations\"),\n role_name: z.string().optional().describe(\"IAM role name to assume in child accounts (default: AWSSecurityMCPAudit)\"),\n account_ids: z.array(z.string()).optional().describe(\"Specific account IDs to scan (default: all org accounts)\"),\n },\n async ({ region, org_mode, role_name, account_ids }) => {\n try {\n const r = region ?? defaultRegion;\n let result: FullScanResult;\n\n if (org_mode) {\n result = await runMultiAccountScanners(allScanners, r, {\n orgMode: true,\n roleName: role_name ?? \"AWSSecurityMCPAudit\",\n accountIds: account_ids,\n });\n } else {\n result = await runAllScanners(allScanners, r);\n }\n\n return {\n content: [\n { type: \"text\", text: summarizeResult(result) },\n { type: \"text\", text: JSON.stringify(result, null, 2) },\n ],\n };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // Individual scanner tools\n const individualScanners: Array<{ toolName: string; moduleName: string; label: string }> = [\n { toolName: \"detect_services\", moduleName: \"service_detection\", label: \"Security Service Detection\" },\n { toolName: \"scan_secret_exposure\", moduleName: \"secret_exposure\", label: \"Secret Exposure\" },\n { toolName: \"scan_ssl_certificate\", moduleName: \"ssl_certificate\", label: \"SSL Certificate\" },\n { toolName: \"scan_dns_dangling\", moduleName: \"dns_dangling\", label: \"Dangling DNS\" },\n { toolName: \"scan_network_reachability\", moduleName: \"network_reachability\", label: \"Network Reachability\" },\n { toolName: \"scan_iam_privilege_escalation\", moduleName: \"iam_privilege_escalation\", label: \"IAM Privilege Escalation\" },\n { toolName: \"scan_public_access_verify\", moduleName: \"public_access_verify\", label: \"Public Access Verify\" },\n { toolName: \"scan_tag_compliance\", moduleName: \"tag_compliance\", label: \"Tag Compliance\" },\n { toolName: \"scan_idle_resources\", moduleName: \"idle_resources\", label: \"Idle Resources\" },\n { toolName: \"scan_disaster_recovery\", moduleName: \"disaster_recovery\", label: \"Disaster Recovery\" },\n { toolName: \"scan_security_hub_findings\", moduleName: \"security_hub_findings\", label: \"Security Hub Findings\" },\n { toolName: \"scan_guardduty_findings\", moduleName: \"guardduty_findings\", label: \"GuardDuty Findings\" },\n { toolName: \"scan_inspector_findings\", moduleName: \"inspector_findings\", label: \"Inspector Findings\" },\n { toolName: \"scan_trusted_advisor_findings\", moduleName: \"trusted_advisor_findings\", label: \"Trusted Advisor Findings\" },\n { toolName: \"scan_config_rules_findings\", moduleName: \"config_rules_findings\", label: \"Config Rules Findings\" },\n { toolName: \"scan_access_analyzer_findings\", moduleName: \"access_analyzer_findings\", label: \"Access Analyzer Findings\" },\n { toolName: \"scan_patch_compliance_findings\", moduleName: \"patch_compliance_findings\", label: \"Patch Compliance Findings\" },\n ];\n\n for (const { toolName, moduleName, label } of individualScanners) {\n server.tool(\n toolName,\n `Run ${label} security scanner only. Read-only. Does not modify any AWS resources.`,\n { region: z.string().optional().describe(\"AWS region to scan (default: server region)\") },\n async ({ region }) => {\n try {\n const r = region ?? defaultRegion;\n const ctx = await buildScanContext(r);\n const scanner = scannerMap.get(moduleName)!;\n const result: ScanResult = await scanner.scan(ctx);\n return {\n content: [\n { type: \"text\", text: summarizeScanResult(result) },\n { type: \"text\", text: JSON.stringify(result, null, 2) },\n ],\n };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n }\n\n // scan_group\n server.tool(\n \"scan_group\",\n \"Run a predefined group of security scanners for a specific scenario (e.g., MLPS compliance, network defense). Read-only. Supports multi-account org scanning.\",\n {\n group: z.string().describe(\"Scan group ID: mlps3_precheck, hw_defense, exposure, data_encryption, least_privilege, log_integrity, disaster_recovery, idle_resources, tag_compliance, new_account_baseline, aggregation\"),\n region: z.string().optional().describe(\"AWS region to scan (default: server region)\"),\n org_mode: z.boolean().optional().describe(\"Enable multi-account scanning via AWS Organizations\"),\n role_name: z.string().optional().describe(\"IAM role name to assume in child accounts (default: AWSSecurityMCPAudit)\"),\n account_ids: z.array(z.string()).optional().describe(\"Specific account IDs to scan (default: all org accounts)\"),\n },\n async ({ group, region, org_mode, role_name, account_ids }) => {\n try {\n const groupDef = SCAN_GROUPS[group];\n if (!groupDef) {\n const available = Object.keys(SCAN_GROUPS).join(\", \");\n return {\n content: [{ type: \"text\", text: `Error: Unknown scan group \"${group}\". Available groups: ${available}` }],\n isError: true,\n };\n }\n\n const r = region ?? defaultRegion;\n\n // Resolve scanners: \"ALL\" means all registered scanners\n let selectedScanners: Scanner[];\n const missingModules: string[] = [];\n\n if (groupDef.modules.includes(\"ALL\")) {\n selectedScanners = allScanners;\n } else {\n selectedScanners = [];\n for (const mod of groupDef.modules) {\n const scanner = scannerMap.get(mod);\n if (scanner) {\n selectedScanners.push(scanner);\n } else {\n missingModules.push(mod);\n }\n }\n }\n\n if (selectedScanners.length === 0) {\n return {\n content: [{ type: \"text\", text: `Error: No available scanners for group \"${group}\". Requested modules: ${groupDef.modules.join(\", \")}` }],\n isError: true,\n };\n }\n\n let result: FullScanResult;\n\n if (org_mode) {\n result = await runMultiAccountScanners(selectedScanners, r, {\n orgMode: true,\n roleName: role_name ?? \"AWSSecurityMCPAudit\",\n accountIds: account_ids,\n });\n } else {\n result = await runAllScanners(selectedScanners, r);\n }\n\n // Apply post-filter if the group defines one\n if (groupDef.findingsFilter) {\n for (const mod of result.modules) {\n const originalCount = mod.findings.length;\n mod.findings = applyFindingsFilter(mod.module, mod.findings, groupDef.findingsFilter);\n mod.findingsCount = mod.findings.length;\n if (mod.findings.length < originalCount) {\n const filtered = originalCount - mod.findings.length;\n if (!mod.warnings) mod.warnings = [];\n mod.warnings.push(`Post-filter removed ${filtered} finding(s) not matching group criteria.`);\n }\n }\n // Recalculate summary after filtering\n let critical = 0, high = 0, medium = 0, low = 0;\n for (const m of result.modules) {\n for (const f of m.findings) {\n switch (f.severity) {\n case \"CRITICAL\": critical++; break;\n case \"HIGH\": high++; break;\n case \"MEDIUM\": medium++; break;\n case \"LOW\": low++; break;\n }\n }\n }\n result.summary.totalFindings = critical + high + medium + low;\n result.summary.critical = critical;\n result.summary.high = high;\n result.summary.medium = medium;\n result.summary.low = low;\n }\n\n const lines: string[] = [\n `Scan group: ${groupDef.name} (${group})`,\n groupDef.description,\n \"\",\n summarizeResult(result),\n ];\n\n if (missingModules.length > 0) {\n lines.push(\"\");\n lines.push(`Warning: ${missingModules.length} requested module(s) not available: ${missingModules.join(\", \")}`);\n }\n\n return {\n content: [\n { type: \"text\", text: lines.join(\"\\n\") },\n { type: \"text\", text: JSON.stringify(result, null, 2) },\n ],\n };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // list_groups\n server.tool(\n \"list_groups\",\n \"List available scan groups with descriptions. Read-only.\",\n async () => {\n try {\n const groups = Object.entries(SCAN_GROUPS).map(([id, def]) => ({\n id,\n name: def.name,\n description: def.description,\n modules: def.modules,\n reportType: def.reportType,\n }));\n return { content: [{ type: \"text\", text: JSON.stringify(groups, null, 2) }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // 9. generate_report\n server.tool(\n \"generate_report\",\n \"Generate a Markdown security report from scan results. Read-only. Does not modify any AWS resources.\",\n { scan_results: z.string().describe(\"JSON string of FullScanResult from scan_all\") },\n async ({ scan_results }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const report = generateMarkdownReport(parsed);\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // generate_mlps3_report\n server.tool(\n \"generate_mlps3_report\",\n \"Generate a GB/T 22239-2019 等保三级 compliance pre-check report from scan results. Best used with scan_group mlps3_precheck results. Read-only.\",\n { scan_results: z.string().describe(\"JSON string of FullScanResult from scan_group mlps3_precheck or scan_all\") },\n async ({ scan_results }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const report = generateMlps3Report(parsed);\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // generate_html_report\n server.tool(\n \"generate_html_report\",\n \"Generate a professional HTML security report. Save the output as an .html file.\",\n {\n scan_results: z.string().describe(\"JSON string of FullScanResult from scan_all\"),\n history: z.string().optional().describe(\"JSON string of DashboardHistoryEntry[] from dashboard data.json for 30-day trend charts\"),\n },\n async ({ scan_results, history }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const historyData = history ? JSON.parse(history) : undefined;\n const report = generateHtmlReport(parsed, historyData);\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // generate_mlps3_html_report\n server.tool(\n \"generate_mlps3_html_report\",\n \"Generate a professional HTML MLPS Level 3 compliance report (等保三级). Save as .html file.\",\n {\n scan_results: z.string().describe(\"JSON string of FullScanResult from scan_group mlps3_precheck or scan_all\"),\n history: z.string().optional().describe(\"JSON string of DashboardHistoryEntry[] from dashboard data.json for 30-day trend charts\"),\n },\n async ({ scan_results, history }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const historyData = history ? JSON.parse(history) : undefined;\n const report = generateMlps3HtmlReport(parsed, historyData);\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // 10. generate_maturity_report\n server.tool(\n \"generate_maturity_report\",\n \"Generate a security maturity assessment report from scan_all results. Requires service_detection module output. Read-only.\",\n { scan_results: z.string().describe(\"JSON string of FullScanResult from scan_all\") },\n async ({ scan_results }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const sdModule = parsed.modules.find((m) => m.module === \"service_detection\");\n if (!sdModule) {\n return {\n content: [{ type: \"text\", text: \"Error: scan results do not include service_detection module. Run scan_all first.\" }],\n isError: true,\n };\n }\n\n // Extract the serviceDetection data attached by the scanner\n const detection = (sdModule as ScanResult & { serviceDetection?: ServiceDetectionResult }).serviceDetection;\n\n if (!detection) {\n return {\n content: [{ type: \"text\", text: \"Error: service detection data is missing (possible JSON round-trip loss). Run scan_all to get fresh results with complete service detection data.\" }],\n isError: true,\n };\n }\n\n const serviceImpacts: Record<string, string> = {\n \"CloudTrail\": \"API activity logging\",\n \"Security Hub\": \"+300 security checks\",\n \"GuardDuty\": \"Threat detection\",\n \"Inspector\": \"Vulnerability scanning\",\n \"AWS Config\": \"Configuration tracking\",\n \"Macie\": \"Sensitive data detection\",\n };\n const serviceFreeTrials: Record<string, boolean> = {\n \"Security Hub\": true,\n \"GuardDuty\": true,\n \"Inspector\": true,\n \"Macie\": true,\n };\n\n const services = detection.services;\n const coveragePercent = detection.coveragePercent;\n const maturityLevel = detection.maturityLevel;\n\n const enabledCount = services.filter((s) => s.enabled === true).length;\n const knownCount = services.filter((s) => s.enabled !== null).length;\n const totalServices = services.length;\n\n // Build the report\n const lines: string[] = [];\n lines.push(\"# AWS Security Maturity Assessment\");\n lines.push(\"\");\n lines.push(`## Account: ${parsed.accountId} | Region: ${parsed.region}`);\n lines.push(\"\");\n lines.push(`## Security Service Coverage: ${coveragePercent}%`);\n lines.push(`## Maturity Level: ${maturityLevel.charAt(0).toUpperCase() + maturityLevel.slice(1)}`);\n lines.push(\"\");\n lines.push(\"### Service Status\");\n lines.push(\"\");\n lines.push(\"| Service | Status | Impact |\");\n lines.push(\"|---------|--------|--------|\");\n for (const svc of services) {\n const status = svc.enabled === true ? \"\\u2705 Enabled\" : svc.enabled === false ? \"\\u274c Not Enabled\" : \"\\u26a0\\ufe0f Unknown\";\n const impact = serviceImpacts[svc.name] ?? \"\";\n lines.push(`| ${svc.name} | ${status} | ${impact} |`);\n }\n\n const unknowns = services.filter((s) => s.enabled === null);\n if (unknowns.length > 0) {\n lines.push(\"\");\n lines.push(`> \\u26a0\\ufe0f ${unknowns.length} service(s) could not be checked (access denied or detection error). Re-run with appropriate permissions for accurate coverage.`);\n }\n\n // Recommendations\n const disabled = services.filter((s) => s.enabled === false);\n if (disabled.length > 0) {\n lines.push(\"\");\n lines.push(\"### Recommendations (Priority Order)\");\n lines.push(\"\");\n // Priority order: Security Hub, GuardDuty, Inspector, Config, Macie, CloudTrail\n const priorityOrder = [\"Security Hub\", \"GuardDuty\", \"Inspector\", \"AWS Config\", \"Macie\", \"CloudTrail\"];\n const sorted = disabled.sort(\n (a, b) => priorityOrder.indexOf(a.name) - priorityOrder.indexOf(b.name),\n );\n let idx = 1;\n for (const svc of sorted) {\n const trial = serviceFreeTrials[svc.name] ? \" \\u2014 free trial available\" : \"\";\n lines.push(`${idx}. Enable ${svc.name}${trial}`);\n idx++;\n }\n }\n\n // Maturity roadmap\n lines.push(\"\");\n lines.push(\"### Maturity Roadmap\");\n lines.push(\"\");\n if (unknowns.length > 0) {\n lines.push(`- **Current**: ${maturityLevel.charAt(0).toUpperCase() + maturityLevel.slice(1)} (${enabledCount}/${knownCount} known services, ${unknowns.length} unknown)`);\n } else {\n lines.push(`- **Current**: ${maturityLevel.charAt(0).toUpperCase() + maturityLevel.slice(1)} (${enabledCount}/${totalServices} services)`);\n }\n\n if (maturityLevel !== \"comprehensive\") {\n const nextMilestones: Record<string, { level: string; target: number; suggestions: string[] }> = {\n basic: { level: \"Intermediate\", target: 2, suggestions: [\"Security Hub\", \"GuardDuty\"] },\n intermediate: { level: \"Advanced\", target: 4, suggestions: [\"Inspector\", \"AWS Config\"] },\n advanced: { level: \"Comprehensive\", target: 6, suggestions: [\"Macie\"] },\n };\n const next = nextMilestones[maturityLevel];\n if (next) {\n const remaining = next.suggestions.filter((s) =>\n services.some((svc) => svc.name === s && !svc.enabled),\n );\n if (remaining.length > 0) {\n lines.push(`- **Next milestone**: ${next.level} (${next.target}/${knownCount}) \\u2014 enable ${remaining.join(\" + \")}`);\n }\n }\n lines.push(`- **Target**: Comprehensive (${knownCount}/${knownCount})`);\n }\n\n lines.push(\"\");\n\n const report = lines.join(\"\\n\");\n\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],\n isError: true,\n };\n }\n },\n );\n\n // 11. save_results\n server.tool(\n \"save_results\",\n \"Saves scan results to local disk or S3 for dashboard display. Does not modify any AWS resources.\",\n {\n scan_results: z.string().describe(\"JSON string of FullScanResult from scan_all\"),\n output_dir: z.string().optional().describe(\"Output directory (default: ~/.aws-security)\"),\n },\n async ({ scan_results, output_dir }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const dataPath = saveResults(parsed, output_dir);\n return {\n content: [\n { type: \"text\", text: `Dashboard data saved to ${dataPath}` },\n ],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],\n isError: true,\n };\n }\n },\n );\n\n // 11. list_modules\n server.tool(\n \"list_modules\",\n \"List available security scan modules with descriptions. Read-only. Does not modify any AWS resources.\",\n async () => {\n try {\n const modules = allScanners.map((s) => ({\n name: s.moduleName,\n description: MODULE_DESCRIPTIONS[s.moduleName] ?? s.moduleName,\n }));\n return { content: [{ type: \"text\", text: JSON.stringify(modules, null, 2) }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // list_org_accounts\n server.tool(\n \"list_org_accounts\",\n \"List all accounts in the AWS Organization. Useful for discovering accounts before multi-account scanning. Read-only.\",\n { region: z.string().optional().describe(\"AWS region (default: server region)\") },\n async ({ region }) => {\n try {\n const r = region ?? defaultRegion;\n const accounts = await listOrgAccounts(r);\n return {\n content: [\n { type: \"text\", text: `Found ${accounts.length} active account(s) in the organization.` },\n { type: \"text\", text: JSON.stringify(accounts, null, 2) },\n ],\n };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // get_setup_template\n server.tool(\n \"get_setup_template\",\n \"Returns the CloudFormation StackSet template for deploying the cross-account security audit IAM role. Read-only.\",\n {\n format: z.enum([\"yaml\", \"json\"]).optional().describe(\"Template format: yaml or json (default: yaml)\"),\n },\n async ({ format }) => {\n try {\n const ext = format === \"json\" ? \"json\" : \"yaml\";\n const templateFileName = `stackset-audit-role.${ext}`;\n // Try multiple locations for the template\n let templateContent: string;\n try {\n // When running from source\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const templatePath = join(currentDir, \"..\", \"templates\", templateFileName);\n templateContent = readFileSync(templatePath, \"utf-8\");\n } catch {\n try {\n // When running from dist\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const templatePath = join(currentDir, \"..\", \"..\", \"templates\", templateFileName);\n templateContent = readFileSync(templatePath, \"utf-8\");\n } catch {\n return {\n content: [{ type: \"text\", text: `Error: Template file ${templateFileName} not found. Ensure the templates/ directory is included in the package.` }],\n isError: true,\n };\n }\n }\n return {\n content: [\n { type: \"text\", text: `CloudFormation StackSet template (${ext.toUpperCase()}) for cross-account audit role:\\n\\nDeploy this as a StackSet from your Management Account to all member accounts.` },\n { type: \"text\", text: templateContent },\n ],\n };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // --- Resources ---\n\n server.resource(\n \"security-rules\",\n \"security://rules\",\n { description: \"Describes all 17 scan modules and their check rules\", mimeType: \"text/markdown\" },\n async () => ({\n contents: [{ uri: \"security://rules\", text: SECURITY_RULES_CONTENT, mimeType: \"text/markdown\" }],\n }),\n );\n\n server.resource(\n \"risk-scoring\",\n \"security://risk-scoring\",\n { description: \"Describes the risk scoring model and severity/priority mapping\", mimeType: \"text/markdown\" },\n async () => ({\n contents: [{ uri: \"security://risk-scoring\", text: RISK_SCORING_CONTENT, mimeType: \"text/markdown\" }],\n }),\n );\n\n // --- Prompts ---\n\n server.prompt(\n \"security-scan\",\n \"Run a full AWS security scan workflow: scan all modules, generate a report, and summarize findings.\",\n async () => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: \"Run scan_all to perform a full AWS security scan. Then take the JSON result and pass it to generate_report to create a Markdown report. Finally, summarize the top findings and recommend immediate actions based on priority.\",\n },\n },\n ],\n }),\n );\n\n server.prompt(\n \"analyze-finding\",\n \"Deep analysis of a specific security finding.\",\n { finding: z.string().describe(\"JSON string of a single Finding object to analyze\") },\n async ({ finding }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Analyze this AWS security finding in depth. Explain the risk, potential attack vectors, blast radius, and provide detailed step-by-step remediation guidance.\\n\\nFinding:\\n${finding}`,\n },\n },\n ],\n }),\n );\n\n return server;\n}\n\nexport async function startServer(defaultRegion: string): Promise<void> {\n const server = createServer(defaultRegion);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","export const VERSION = \"0.4.3\";\n","import { STSClient, GetCallerIdentityCommand } from \"@aws-sdk/client-sts\";\n\nlet cachedAccountId: string | undefined;\n\nexport function getPartition(region: string): string {\n if (region.startsWith(\"cn-\")) return \"aws-cn\";\n if (region.startsWith(\"us-gov-\")) return \"aws-us-gov\";\n return \"aws\";\n}\n\nexport function getIamRegion(region: string): string {\n // IAM is global in standard AWS (us-east-1) but regional in China\n if (region.startsWith(\"cn-\")) return region;\n return \"us-east-1\";\n}\n\nexport async function getAccountId(region?: string): Promise<string> {\n if (cachedAccountId) return cachedAccountId;\n\n const stsRegion = region ?? \"us-east-1\";\n const sts = new STSClient({ region: stsRegion });\n const response = await sts.send(new GetCallerIdentityCommand({}));\n cachedAccountId = response.Account ?? \"unknown\";\n return cachedAccountId;\n}\n\nexport function createClient<T>(\n ClientClass: new (config: any) => T,\n region?: string,\n credentials?: { accessKeyId: string; secretAccessKey: string; sessionToken: string },\n): T {\n const config: any = { region: region ?? \"us-east-1\" };\n if (credentials) config.credentials = credentials;\n return new ClientClass(config);\n}\n","import { STSClient, AssumeRoleCommand, GetCallerIdentityCommand } from \"@aws-sdk/client-sts\";\n\nexport async function getCurrentAccountId(region: string): Promise<string> {\n const sts = new STSClient({ region });\n const result = await sts.send(new GetCallerIdentityCommand({}));\n return result.Account!;\n}\n\nexport const DEFAULT_EXTERNAL_ID = \"aws-security-mcp-audit\";\n\nexport async function assumeRole(roleArn: string, region: string, options?: {\n sessionName?: string;\n externalId?: string;\n}): Promise<{\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken: string;\n}> {\n const sessionName = options?.sessionName ?? \"aws-security-mcp\";\n const externalId = options?.externalId ?? DEFAULT_EXTERNAL_ID;\n const sts = new STSClient({ region });\n const result = await sts.send(new AssumeRoleCommand({\n RoleArn: roleArn,\n RoleSessionName: sessionName,\n ExternalId: externalId,\n DurationSeconds: 3600,\n }));\n return {\n accessKeyId: result.Credentials!.AccessKeyId!,\n secretAccessKey: result.Credentials!.SecretAccessKey!,\n sessionToken: result.Credentials!.SessionToken!,\n };\n}\n\nexport function buildRoleArn(accountId: string, roleName: string, partition = \"aws\"): string {\n return `arn:${partition}:iam::${accountId}:role/${roleName}`;\n}\n","import { OrganizationsClient, ListAccountsCommand } from \"@aws-sdk/client-organizations\";\n\nexport interface OrgAccount {\n id: string;\n name: string;\n email: string;\n status: string;\n}\n\nexport async function listOrgAccounts(region: string): Promise<OrgAccount[]> {\n // Organizations API must use specific endpoints\n // Global: us-east-1, China: cn-northwest-1\n const orgRegion = region.startsWith(\"cn-\") ? \"cn-northwest-1\" : \"us-east-1\";\n const client = new OrganizationsClient({ region: orgRegion });\n const accounts: OrgAccount[] = [];\n let nextToken: string | undefined;\n\n do {\n const result = await client.send(new ListAccountsCommand({ NextToken: nextToken }));\n for (const acct of result.Accounts || []) {\n if (acct.Status === \"ACTIVE\") {\n accounts.push({\n id: acct.Id!,\n name: acct.Name || \"\",\n email: acct.Email || \"\",\n status: acct.Status!,\n });\n }\n }\n nextToken = result.NextToken;\n } while (nextToken);\n\n return accounts;\n}\n","import { FullScanResult, ScanResult, ScanContext, AwsCredentials } from \"../types.js\";\nimport { Scanner } from \"./base.js\";\nimport { getAccountId, getPartition } from \"../utils/aws-client.js\";\nimport { assumeRole, buildRoleArn } from \"../utils/assume-role.js\";\nimport { listOrgAccounts, type OrgAccount } from \"../utils/org-accounts.js\";\n\n/** Aggregation scanners that already pull cross-account data — run once from admin account */\nconst AGGREGATION_MODULES = new Set([\n \"security_hub_findings\",\n \"guardduty_findings\",\n \"inspector_findings\",\n]);\n\nfunction buildSummary(modules: ScanResult[]) {\n let critical = 0;\n let high = 0;\n let medium = 0;\n let low = 0;\n let modulesSuccess = 0;\n let modulesError = 0;\n\n for (const m of modules) {\n if (m.status === \"success\") {\n modulesSuccess++;\n } else {\n modulesError++;\n }\n for (const f of m.findings) {\n switch (f.severity) {\n case \"CRITICAL\": critical++; break;\n case \"HIGH\": high++; break;\n case \"MEDIUM\": medium++; break;\n case \"LOW\": low++; break;\n }\n }\n }\n\n return {\n totalFindings: critical + high + medium + low,\n critical,\n high,\n medium,\n low,\n modulesSuccess,\n modulesError,\n };\n}\n\nasync function runScannersWithContext(\n scanners: Scanner[],\n ctx: ScanContext,\n): Promise<ScanResult[]> {\n const settled = await Promise.allSettled(scanners.map((s) => s.scan(ctx)));\n\n return settled.map((result, i) => {\n if (result.status === \"fulfilled\") {\n // Stamp accountId on all findings\n for (const f of result.value.findings) {\n if (!f.accountId) f.accountId = ctx.accountId;\n if (!f.accountAlias && ctx.accountAlias) f.accountAlias = ctx.accountAlias;\n }\n return result.value;\n }\n return {\n module: scanners[i].moduleName,\n status: \"error\" as const,\n error: result.reason instanceof Error ? result.reason.message : String(result.reason),\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: 0,\n findings: [],\n };\n });\n}\n\nexport async function runAllScanners(\n scanners: Scanner[],\n region: string,\n): Promise<FullScanResult> {\n const scanStart = new Date().toISOString();\n\n // Best-effort accountId retrieval — don't let STS failure break the whole scan\n let accountId: string;\n try {\n accountId = await getAccountId(region);\n } catch {\n accountId = \"unknown\";\n }\n\n const partition = getPartition(region);\n const ctx: ScanContext = { region, partition, accountId };\n\n const modules = await runScannersWithContext(scanners, ctx);\n\n const scanEnd = new Date().toISOString();\n\n return {\n scanStart,\n scanEnd,\n region,\n accountId,\n modules,\n summary: buildSummary(modules),\n };\n}\n\nexport interface MultiAccountOptions {\n orgMode: boolean;\n roleName: string;\n accountIds?: string[];\n}\n\nexport async function runMultiAccountScanners(\n scanners: Scanner[],\n region: string,\n opts: MultiAccountOptions,\n): Promise<FullScanResult> {\n const scanStart = new Date().toISOString();\n const partition = getPartition(region);\n\n // Get current (admin) account ID\n let adminAccountId: string;\n try {\n adminAccountId = await getAccountId(region);\n } catch {\n adminAccountId = \"unknown\";\n }\n\n // Discover org accounts\n let accounts: OrgAccount[];\n try {\n accounts = await listOrgAccounts(region);\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n // Graceful fallback: scan current account only, with clear warning\n const result = await runAllScanners(scanners, region);\n if (result.modules.length > 0) {\n if (!result.modules[0].warnings) result.modules[0].warnings = [];\n result.modules[0].warnings.unshift(`org_mode enabled but Organizations listing failed: ${errMsg}. Scanning current account only.`);\n }\n return result;\n }\n\n // Filter to specific accounts if requested\n if (opts.accountIds?.length) {\n const idSet = new Set(opts.accountIds);\n accounts = accounts.filter((a) => idSet.has(a.id));\n }\n\n // Separate aggregation vs per-account scanners\n const aggregationScanners = scanners.filter((s) => AGGREGATION_MODULES.has(s.moduleName));\n const perAccountScanners = scanners.filter((s) => !AGGREGATION_MODULES.has(s.moduleName));\n\n const allModules: ScanResult[] = [];\n\n // 1. Run aggregation scanners ONCE from admin account (they already aggregate cross-account)\n if (aggregationScanners.length > 0) {\n const adminCtx: ScanContext = { region, partition, accountId: adminAccountId };\n const aggResults = await runScannersWithContext(aggregationScanners, adminCtx);\n allModules.push(...aggResults);\n }\n\n // 2. Run per-account scanners for each account\n for (const account of accounts) {\n let credentials: AwsCredentials | undefined;\n let accountAlias = account.name;\n\n // Skip assume-role for the admin account itself\n if (account.id !== adminAccountId) {\n try {\n const roleArn = buildRoleArn(account.id, opts.roleName, partition);\n credentials = await assumeRole(roleArn, region);\n } catch (err) {\n // Record a failed module for this account\n allModules.push({\n module: `assume_role_${account.id}`,\n status: \"error\",\n error: `Failed to assume role in account ${account.id} (${account.name}): ${err instanceof Error ? err.message : String(err)}`,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: 0,\n findings: [],\n });\n continue;\n }\n }\n\n const ctx: ScanContext = {\n region,\n partition,\n accountId: account.id,\n accountAlias,\n credentials,\n };\n\n const accountResults = await runScannersWithContext(perAccountScanners, ctx);\n allModules.push(...accountResults);\n }\n\n const scanEnd = new Date().toISOString();\n\n // Post-filter: if account_ids was specified, filter aggregation findings too\n if (opts.accountIds?.length) {\n const idSet = new Set(opts.accountIds);\n for (const mod of allModules) {\n if (AGGREGATION_MODULES.has(mod.module)) {\n mod.findings = mod.findings.filter((f) => !f.accountId || idSet.has(f.accountId));\n mod.findingsCount = mod.findings.length;\n }\n }\n }\n\n return {\n scanStart,\n scanEnd,\n region,\n accountId: adminAccountId,\n modules: allModules,\n summary: buildSummary(allModules),\n };\n}\n","import {\n SecurityHubClient,\n DescribeHubCommand,\n} from \"@aws-sdk/client-securityhub\";\nimport {\n GuardDutyClient,\n ListDetectorsCommand,\n} from \"@aws-sdk/client-guardduty\";\nimport {\n Inspector2Client,\n BatchGetAccountStatusCommand,\n} from \"@aws-sdk/client-inspector2\";\nimport {\n ConfigServiceClient,\n DescribeConfigurationRecordersCommand,\n} from \"@aws-sdk/client-config-service\";\nimport {\n Macie2Client,\n GetMacieSessionCommand,\n} from \"@aws-sdk/client-macie2\";\nimport {\n CloudTrailClient,\n DescribeTrailsCommand,\n} from \"@aws-sdk/client-cloudtrail\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nexport interface ServiceStatus {\n name: string;\n enabled: boolean | null; // null = unknown (access denied or detection error)\n details?: string;\n recommendation?: string;\n freeTrialAvailable?: boolean;\n}\n\nexport interface ServiceDetectionResult {\n services: ServiceStatus[];\n coveragePercent: number;\n maturityLevel: \"basic\" | \"intermediate\" | \"advanced\" | \"comprehensive\";\n}\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction isAccessDenied(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const name = (err as Error & { name?: string }).name ?? \"\";\n const code = (err as Error & { Code?: string }).Code ?? \"\";\n return (\n name === \"AccessDeniedException\" ||\n name === \"UnauthorizedAccess\" ||\n name === \"AccessDenied\" ||\n code === \"AccessDeniedException\" ||\n code === \"AccessDenied\" ||\n name === \"ForbiddenException\" ||\n // AWS SDK v3 uses __type or $metadata for some errors\n (err.message?.includes(\"is not authorized to perform\") ?? false) ||\n (err.message?.includes(\"Access Denied\") ?? false)\n );\n}\n\nfunction isNotEnabled(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n return (\n err.name === \"InvalidAccessException\" || // Security Hub specific\n err.name === \"DisabledException\" ||\n err.message.includes(\"not enabled\") ||\n err.message.includes(\"not subscribed\")\n );\n}\n\nfunction computeMaturityLevel(\n enabledCount: number,\n): \"basic\" | \"intermediate\" | \"advanced\" | \"comprehensive\" {\n if (enabledCount >= 6) return \"comprehensive\";\n if (enabledCount >= 4) return \"advanced\";\n if (enabledCount >= 2) return \"intermediate\";\n return \"basic\";\n}\n\nexport class ServiceDetectionScanner implements Scanner {\n readonly moduleName = \"service_detection\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n const services: ServiceStatus[] = [];\n\n // --- CloudTrail ---\n try {\n const ct = createClient(CloudTrailClient, region, ctx.credentials);\n const resp = await ct.send(new DescribeTrailsCommand({}));\n const trails = resp.trailList ?? [];\n if (trails.length > 0) {\n services.push({\n name: \"CloudTrail\",\n enabled: true,\n details: `${trails.length} trail(s) configured`,\n });\n } else {\n services.push({\n name: \"CloudTrail\",\n enabled: false,\n recommendation: \"Create a multi-region trail for API logging\",\n });\n // CloudTrail is checked by service detection only for coverage assessment.\n }\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"CloudTrail: insufficient permissions to check status\");\n services.push({ name: \"CloudTrail\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"CloudTrail\",\n enabled: false,\n recommendation: \"Create a multi-region trail for API logging\",\n });\n // CloudTrail is checked by service detection only for coverage assessment\n } else {\n warnings.push(`CloudTrail detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"CloudTrail\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- Security Hub ---\n try {\n const sh = createClient(SecurityHubClient, region, ctx.credentials);\n await sh.send(new DescribeHubCommand({}));\n services.push({\n name: \"Security Hub\",\n enabled: true,\n details: \"Enabled with automated security checks\",\n });\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"Security Hub: insufficient permissions to check status\");\n services.push({ name: \"Security Hub\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"Security Hub\",\n enabled: false,\n recommendation: \"Enable Security Hub for 300+ automated security checks\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: \"AWS Security Hub is not enabled\",\n resourceType: \"AWS::SecurityHub::Hub\",\n resourceId: \"securityhub\",\n resourceArn: `arn:${partition}:securityhub:${region}:${accountId}:hub/default`,\n region,\n description:\n \"AWS Security Hub is not enabled in this region. Security Hub provides a comprehensive view of security alerts and compliance status.\",\n impact:\n \"Enables 300+ automated security checks across AWS services. Without it, security findings are fragmented across individual services.\",\n remediationSteps: [\n \"Open the AWS Security Hub console.\",\n \"Click 'Go to Security Hub' and enable it.\",\n \"Enable the AWS Foundational Security Best Practices standard.\",\n \"Security Hub offers a 30-day free trial.\",\n ],\n }),\n );\n } else {\n warnings.push(`Security Hub detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"Security Hub\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- GuardDuty ---\n try {\n const gd = createClient(GuardDutyClient, region, ctx.credentials);\n const resp = await gd.send(new ListDetectorsCommand({}));\n const detectors = resp.DetectorIds ?? [];\n if (detectors.length > 0) {\n services.push({\n name: \"GuardDuty\",\n enabled: true,\n details: `${detectors.length} detector(s) active`,\n });\n } else {\n services.push({\n name: \"GuardDuty\",\n enabled: false,\n recommendation: \"Enable GuardDuty for continuous threat detection\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: \"Amazon GuardDuty is not enabled\",\n resourceType: \"AWS::GuardDuty::Detector\",\n resourceId: \"guardduty\",\n resourceArn: `arn:${partition}:guardduty:${region}:${accountId}:detector/none`,\n region,\n description:\n \"Amazon GuardDuty is not enabled in this region. GuardDuty provides intelligent threat detection by analyzing CloudTrail, VPC Flow Logs, and DNS logs.\",\n impact:\n \"Provides continuous threat detection for account compromise, instance compromise, and malicious reconnaissance. Without it, many attack patterns go undetected.\",\n remediationSteps: [\n \"Open the Amazon GuardDuty console.\",\n \"Click 'Get Started' and enable GuardDuty.\",\n \"GuardDuty offers a 30-day free trial.\",\n \"Consider enabling S3 protection and EKS protection add-ons.\",\n ],\n }),\n );\n }\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"GuardDuty: insufficient permissions to check status\");\n services.push({ name: \"GuardDuty\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"GuardDuty\",\n enabled: false,\n recommendation: \"Enable GuardDuty for continuous threat detection\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: \"Amazon GuardDuty is not enabled\",\n resourceType: \"AWS::GuardDuty::Detector\",\n resourceId: \"guardduty\",\n resourceArn: `arn:${partition}:guardduty:${region}:${accountId}:detector/none`,\n region,\n description:\n \"Amazon GuardDuty is not enabled in this region. GuardDuty provides intelligent threat detection by analyzing CloudTrail, VPC Flow Logs, and DNS logs.\",\n impact:\n \"Provides continuous threat detection for account compromise, instance compromise, and malicious reconnaissance. Without it, many attack patterns go undetected.\",\n remediationSteps: [\n \"Open the Amazon GuardDuty console.\",\n \"Click 'Get Started' and enable GuardDuty.\",\n \"GuardDuty offers a 30-day free trial.\",\n \"Consider enabling S3 protection and EKS protection add-ons.\",\n ],\n }),\n );\n } else {\n warnings.push(`GuardDuty detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"GuardDuty\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- Inspector ---\n try {\n const insp = createClient(Inspector2Client, region, ctx.credentials);\n const resp = await insp.send(new BatchGetAccountStatusCommand({ accountIds: [accountId] }));\n const accounts = resp.accounts ?? [];\n const active = accounts.some(\n (a) =>\n a.state?.status === \"ENABLED\" ||\n a.state?.status === \"ENABLING\",\n );\n if (active) {\n services.push({\n name: \"Inspector\",\n enabled: true,\n details: \"Vulnerability scanning active\",\n });\n } else {\n services.push({\n name: \"Inspector\",\n enabled: false,\n recommendation: \"Enable Inspector to scan for software vulnerabilities\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: \"Amazon Inspector is not enabled\",\n resourceType: \"AWS::Inspector2::AccountStatus\",\n resourceId: \"inspector\",\n resourceArn: `arn:${partition}:inspector2:${region}:${accountId}:account`,\n region,\n description:\n \"Amazon Inspector is not enabled in this region. Inspector automatically discovers and scans EC2 instances, containers, and Lambda functions for software vulnerabilities.\",\n impact:\n \"Scans for software vulnerabilities in EC2 instances, container images, and Lambda functions. Without it, known CVEs may go undetected.\",\n remediationSteps: [\n \"Open the Amazon Inspector console.\",\n \"Click 'Get Started' and enable Inspector.\",\n \"Inspector offers a 15-day free trial.\",\n \"Enable scanning for EC2, ECR, and Lambda as appropriate.\",\n ],\n }),\n );\n }\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"Inspector: insufficient permissions to check status\");\n services.push({ name: \"Inspector\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"Inspector\",\n enabled: false,\n recommendation: \"Enable Inspector to scan for software vulnerabilities\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: \"Amazon Inspector is not enabled\",\n resourceType: \"AWS::Inspector2::AccountStatus\",\n resourceId: \"inspector\",\n resourceArn: `arn:${partition}:inspector2:${region}:${accountId}:account`,\n region,\n description:\n \"Amazon Inspector is not enabled in this region. Inspector automatically discovers and scans EC2 instances, containers, and Lambda functions for software vulnerabilities.\",\n impact:\n \"Scans for software vulnerabilities in EC2 instances, container images, and Lambda functions. Without it, known CVEs may go undetected.\",\n remediationSteps: [\n \"Open the Amazon Inspector console.\",\n \"Click 'Get Started' and enable Inspector.\",\n \"Inspector offers a 15-day free trial.\",\n \"Enable scanning for EC2, ECR, and Lambda as appropriate.\",\n ],\n }),\n );\n } else {\n warnings.push(`Inspector detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"Inspector\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- AWS Config ---\n try {\n const cfg = createClient(ConfigServiceClient, region, ctx.credentials);\n const resp = await cfg.send(new DescribeConfigurationRecordersCommand({}));\n const recorders = resp.ConfigurationRecorders ?? [];\n if (recorders.length > 0) {\n services.push({\n name: \"AWS Config\",\n enabled: true,\n details: `${recorders.length} recorder(s) configured`,\n });\n } else {\n services.push({\n name: \"AWS Config\",\n enabled: false,\n recommendation: \"Enable AWS Config to track configuration changes\",\n });\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: \"AWS Config is not enabled\",\n resourceType: \"AWS::Config::ConfigurationRecorder\",\n resourceId: \"config\",\n resourceArn: `arn:${partition}:config:${region}:${accountId}:configuration-recorder/none`,\n region,\n description:\n \"AWS Config is not enabled in this region. Config continuously records resource configurations and enables compliance auditing.\",\n impact:\n \"Tracks configuration changes and enables compliance rules. Without it, configuration drift and non-compliant resources go undetected.\",\n remediationSteps: [\n \"Open the AWS Config console.\",\n \"Click 'Get Started' and configure a recorder.\",\n \"Select the resource types to record.\",\n \"Configure an S3 bucket for configuration snapshots.\",\n ],\n }),\n );\n }\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"AWS Config: insufficient permissions to check status\");\n services.push({ name: \"AWS Config\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"AWS Config\",\n enabled: false,\n recommendation: \"Enable AWS Config to track configuration changes\",\n });\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: \"AWS Config is not enabled\",\n resourceType: \"AWS::Config::ConfigurationRecorder\",\n resourceId: \"config\",\n resourceArn: `arn:${partition}:config:${region}:${accountId}:configuration-recorder/none`,\n region,\n description:\n \"AWS Config is not enabled in this region. Config continuously records resource configurations and enables compliance auditing.\",\n impact:\n \"Tracks configuration changes and enables compliance rules. Without it, configuration drift and non-compliant resources go undetected.\",\n remediationSteps: [\n \"Open the AWS Config console.\",\n \"Click 'Get Started' and configure a recorder.\",\n \"Select the resource types to record.\",\n \"Configure an S3 bucket for configuration snapshots.\",\n ],\n }),\n );\n } else {\n warnings.push(`AWS Config detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"AWS Config\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- Macie (not available in AWS China regions) ---\n if (region.startsWith(\"cn-\")) {\n services.push({ name: \"Macie\", enabled: null, details: \"Not available in China regions\" });\n warnings.push(\"Macie is not available in AWS China regions.\");\n } else {\n try {\n const mc = createClient(Macie2Client, region, ctx.credentials);\n await mc.send(new GetMacieSessionCommand({}));\n services.push({\n name: \"Macie\",\n enabled: true,\n details: \"Sensitive data detection active\",\n });\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"Macie: insufficient permissions to check status\");\n services.push({ name: \"Macie\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"Macie\",\n enabled: false,\n recommendation: \"Enable Macie to detect sensitive data in S3\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 5.0,\n title: \"Amazon Macie is not enabled\",\n resourceType: \"AWS::Macie::Session\",\n resourceId: \"macie\",\n resourceArn: `arn:${partition}:macie2:${region}:${accountId}:session`,\n region,\n description:\n \"Amazon Macie is not enabled in this region. Macie uses machine learning to discover and protect sensitive data stored in S3.\",\n impact:\n \"Detects sensitive data (PII, credentials, financial data) in S3 buckets. Without it, sensitive data exposure may go unnoticed.\",\n remediationSteps: [\n \"Open the Amazon Macie console.\",\n \"Click 'Get Started' and enable Macie.\",\n \"Macie offers a 30-day free trial for sensitive data discovery.\",\n \"Configure automated sensitive data discovery jobs.\",\n ],\n }),\n );\n } else {\n warnings.push(`Macie detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"Macie\", enabled: null, details: \"Detection error\" });\n }\n }\n }\n\n // Compute coverage and maturity (exclude unknown services from coverage denominator)\n const knownServices = services.filter((s) => s.enabled !== null);\n const enabledCount = services.filter((s) => s.enabled === true).length;\n const coveragePercent = knownServices.length > 0 ? Math.round((enabledCount / knownServices.length) * 100) : 0;\n const maturityLevel = computeMaturityLevel(enabledCount);\n\n const detectionResult: ServiceDetectionResult = {\n services,\n coveragePercent,\n maturityLevel,\n };\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: services.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n // Attach the structured detection result as a custom property via the findings metadata\n ...({ serviceDetection: detectionResult } as Record<string, unknown>),\n } as ScanResult & { serviceDetection: ServiceDetectionResult };\n }\n}\n","import { Severity, Priority } from \"../types.js\";\n\nexport function severityFromScore(score: number): Severity {\n if (score >= 9.0) return \"CRITICAL\";\n if (score >= 7.0) return \"HIGH\";\n if (score >= 4.0) return \"MEDIUM\";\n return \"LOW\";\n}\n\nexport function priorityFromSeverity(severity: Severity): Priority {\n switch (severity) {\n case \"CRITICAL\": return \"P0\";\n case \"HIGH\": return \"P1\";\n case \"MEDIUM\": return \"P2\";\n case \"LOW\": return \"P3\";\n }\n}\n","import {\n LambdaClient,\n ListFunctionsCommand,\n type FunctionConfiguration,\n} from \"@aws-sdk/client-lambda\";\nimport {\n EC2Client,\n DescribeInstancesCommand,\n DescribeInstanceAttributeCommand,\n type Instance,\n} from \"@aws-sdk/client-ec2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst SECRET_PATTERNS: Array<{ name: string; pattern: RegExp; matchType: \"value\" | \"name\" }> = [\n { name: \"AWS Access Key\", pattern: /AKIA[0-9A-Z]{16}/, matchType: \"value\" },\n { name: \"Private Key\", pattern: /-----BEGIN.*PRIVATE KEY-----/, matchType: \"value\" },\n { name: \"Password in env var\", pattern: /^(PASSWORD|PASSWD|DB_PASSWORD|SECRET|API_KEY|APIKEY|TOKEN|AUTH_TOKEN)$/i, matchType: \"name\" },\n];\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class SecretExposureScanner implements Scanner {\n readonly moduleName = \"secret_exposure\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n // --- Lambda functions ---\n try {\n const lambda = createClient(LambdaClient, region, ctx.credentials);\n const functions: FunctionConfiguration[] = [];\n let marker: string | undefined;\n do {\n const resp = await lambda.send(\n new ListFunctionsCommand({ Marker: marker }),\n );\n if (resp.Functions) functions.push(...resp.Functions);\n marker = resp.NextMarker;\n } while (marker);\n\n resourcesScanned += functions.length;\n\n for (const fn of functions) {\n const fnName = fn.FunctionName ?? \"unknown\";\n const fnArn =\n fn.FunctionArn ??\n `arn:${partition}:lambda:${region}:${accountId}:function:${fnName}`;\n const envVars = fn.Environment?.Variables ?? {};\n\n for (const [varName, varValue] of Object.entries(envVars)) {\n for (const sp of SECRET_PATTERNS) {\n if (sp.matchType === \"name\") {\n if (sp.pattern.test(varName)) {\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `Lambda ${fnName} has suspicious env var \"${varName}\"`,\n resourceType: \"AWS::Lambda::Function\",\n resourceId: fnName,\n resourceArn: fnArn,\n region,\n description: `Lambda function \"${fnName}\" has an environment variable named \"${varName}\" which may contain a secret.`,\n impact:\n \"Secrets in Lambda environment variables are visible to anyone with lambda:GetFunctionConfiguration permission and may leak through logs.\",\n remediationSteps: [\n \"Move the secret to AWS Secrets Manager or SSM Parameter Store (SecureString).\",\n \"Update the Lambda function to fetch the secret at runtime.\",\n \"Rotate the exposed credential immediately.\",\n ],\n }),\n );\n }\n } else {\n // match value\n if (sp.pattern.test(varValue)) {\n const riskScore = sp.name === \"AWS Access Key\" ? 9.5 : 9.0;\n findings.push(\n makeFinding({\n riskScore,\n title: `Lambda ${fnName} env var contains ${sp.name}`,\n resourceType: \"AWS::Lambda::Function\",\n resourceId: fnName,\n resourceArn: fnArn,\n region,\n description: `Lambda function \"${fnName}\" has an environment variable containing a ${sp.name} pattern.`,\n impact:\n \"Hard-coded credentials in Lambda environment variables can be extracted by any principal with read access to the function configuration.\",\n remediationSteps: [\n \"Remove the hard-coded credential from environment variables.\",\n \"Use AWS Secrets Manager or SSM Parameter Store (SecureString) instead.\",\n \"Rotate the exposed credential immediately.\",\n \"Review CloudTrail logs for unauthorized use of the credential.\",\n ],\n }),\n );\n }\n }\n }\n }\n }\n } catch (e: unknown) {\n warnings.push(`Lambda scan error: ${e instanceof Error ? e.message : String(e)}`);\n }\n\n // --- EC2 userData ---\n try {\n const ec2 = createClient(EC2Client, region, ctx.credentials);\n const instances: Instance[] = [];\n let nextToken: string | undefined;\n do {\n const resp = await ec2.send(\n new DescribeInstancesCommand({ NextToken: nextToken }),\n );\n for (const res of resp.Reservations ?? []) {\n if (res.Instances) instances.push(...res.Instances);\n }\n nextToken = resp.NextToken;\n } while (nextToken);\n\n resourcesScanned += instances.length;\n\n for (const inst of instances) {\n const instId = inst.InstanceId ?? \"unknown\";\n const instArn = `arn:${partition}:ec2:${region}:${accountId}:instance/${instId}`;\n\n let userData: string | undefined;\n try {\n const attrResp = await ec2.send(\n new DescribeInstanceAttributeCommand({\n InstanceId: instId,\n Attribute: \"userData\",\n }),\n );\n const raw = attrResp.UserData?.Value;\n if (raw) {\n userData = Buffer.from(raw, \"base64\").toString(\"utf-8\");\n }\n } catch (e: unknown) {\n warnings.push(`Could not read userData for ${instId}: ${e instanceof Error ? e.message : String(e)}`);\n continue;\n }\n\n if (!userData) continue;\n\n for (const sp of SECRET_PATTERNS) {\n if (sp.matchType === \"name\") continue; // name-matching doesn't apply to userData\n if (sp.pattern.test(userData)) {\n const riskScore = sp.name === \"AWS Access Key\" ? 9.5 : 8.0;\n findings.push(\n makeFinding({\n riskScore,\n title: `EC2 ${instId} userData contains ${sp.name}`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: instArn,\n region,\n description: `EC2 instance \"${instId}\" has user data containing a ${sp.name} pattern.`,\n impact:\n \"Instance user data is accessible to anyone with ec2:DescribeInstanceAttribute permission and from the instance metadata service.\",\n remediationSteps: [\n \"Remove the secret from instance user data.\",\n \"Use IAM instance profiles for AWS API access instead of embedding keys.\",\n \"Use Secrets Manager or SSM Parameter Store for other secrets.\",\n \"Rotate the exposed credential immediately.\",\n ],\n }),\n );\n }\n }\n }\n } catch (e: unknown) {\n warnings.push(`EC2 userData scan error: ${e instanceof Error ? e.message : String(e)}`);\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n ACMClient,\n ListCertificatesCommand,\n DescribeCertificateCommand,\n type CertificateSummary,\n} from \"@aws-sdk/client-acm\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class SslCertificateScanner implements Scanner {\n readonly moduleName = \"ssl_certificate\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n const client = createClient(ACMClient, region, ctx.credentials);\n\n // List all certificates\n const certs: CertificateSummary[] = [];\n let nextToken: string | undefined;\n do {\n const resp = await client.send(\n new ListCertificatesCommand({ NextToken: nextToken }),\n );\n if (resp.CertificateSummaryList) {\n certs.push(...resp.CertificateSummaryList);\n }\n nextToken = resp.NextToken;\n } while (nextToken);\n\n for (const cert of certs) {\n const certArn = cert.CertificateArn ?? \"unknown\";\n const domainName = cert.DomainName ?? \"unknown\";\n\n let detail;\n try {\n const descResp = await client.send(\n new DescribeCertificateCommand({ CertificateArn: certArn }),\n );\n detail = descResp.Certificate;\n } catch (e: unknown) {\n warnings.push(`Could not describe certificate ${certArn}: ${e instanceof Error ? e.message : String(e)}`);\n continue;\n }\n\n if (!detail) continue;\n\n const status = detail.Status ?? \"UNKNOWN\";\n const inUseBy = detail.InUseBy ?? [];\n const inUseStr = inUseBy.length > 0 ? ` In use by ${inUseBy.length} resource(s).` : \" Not currently in use.\";\n\n // Check for FAILED status\n if (status === \"FAILED\") {\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `Certificate for ${domainName} is in FAILED status`,\n resourceType: \"AWS::ACM::Certificate\",\n resourceId: domainName,\n resourceArn: certArn,\n region,\n description: `ACM certificate for \"${domainName}\" has status FAILED.${inUseStr}`,\n impact:\n \"The certificate failed validation and cannot be used for TLS termination. Services relying on it may lose HTTPS protection.\",\n remediationSteps: [\n \"Check the failure reason in the ACM console.\",\n \"Request a new certificate with correct domain validation.\",\n \"If using DNS validation, ensure the CNAME records are correctly configured.\",\n ],\n }),\n );\n continue;\n }\n\n // Check expiry (only for ISSUED certificates)\n if (status === \"ISSUED\" && detail.NotAfter) {\n const now = new Date();\n const expiryDate = new Date(detail.NotAfter);\n const daysUntilExpiry = Math.floor(\n (expiryDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24),\n );\n\n if (daysUntilExpiry < 0) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `Certificate for ${domainName} has expired`,\n resourceType: \"AWS::ACM::Certificate\",\n resourceId: domainName,\n resourceArn: certArn,\n region,\n description: `ACM certificate for \"${domainName}\" expired ${Math.abs(daysUntilExpiry)} days ago.${inUseStr}`,\n impact:\n \"Expired certificates cause TLS errors for end users. Browsers will display security warnings and block access.\",\n remediationSteps: [\n \"Renew or replace the certificate immediately.\",\n \"If using ACM-managed renewal, check why automatic renewal failed.\",\n \"Verify domain validation records are still in place.\",\n ],\n }),\n );\n } else if (daysUntilExpiry < 30) {\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: `Certificate for ${domainName} expires in ${daysUntilExpiry} days`,\n resourceType: \"AWS::ACM::Certificate\",\n resourceId: domainName,\n resourceArn: certArn,\n region,\n description: `ACM certificate for \"${domainName}\" expires in ${daysUntilExpiry} days (${expiryDate.toISOString().split(\"T\")[0]}).${inUseStr}`,\n impact:\n \"Certificate will expire soon. If not renewed, services will experience TLS errors.\",\n remediationSteps: [\n \"Verify ACM automatic renewal is working (check renewal status).\",\n \"If imported certificate, prepare and import the renewed certificate.\",\n \"Set up CloudWatch alarms for certificate expiry.\",\n ],\n }),\n );\n } else if (daysUntilExpiry < 90) {\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `Certificate for ${domainName} expires in ${daysUntilExpiry} days`,\n resourceType: \"AWS::ACM::Certificate\",\n resourceId: domainName,\n resourceArn: certArn,\n region,\n description: `ACM certificate for \"${domainName}\" expires in ${daysUntilExpiry} days (${expiryDate.toISOString().split(\"T\")[0]}).${inUseStr}`,\n impact:\n \"Certificate is approaching expiry. Plan renewal to avoid service disruption.\",\n remediationSteps: [\n \"Verify ACM automatic renewal is configured and working.\",\n \"If imported certificate, begin the renewal process.\",\n \"Consider setting up monitoring for certificate expiry dates.\",\n ],\n }),\n );\n }\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: certs.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n Route53Client,\n ListHostedZonesCommand,\n ListResourceRecordSetsCommand,\n type HostedZone,\n type ResourceRecordSet,\n} from \"@aws-sdk/client-route-53\";\nimport {\n S3Client,\n HeadBucketCommand,\n} from \"@aws-sdk/client-s3\";\nimport { promises as dns } from \"dns\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction extractS3BucketName(target: string): string | null {\n // Matches: bucket.s3.amazonaws.com, bucket.s3-website-us-east-1.amazonaws.com,\n // bucket.s3.cn-north-1.amazonaws.com.cn, etc.\n const s3Pattern = /^([^.]+)\\.s3[.-]/;\n const m = target.match(s3Pattern);\n return m ? m[1] : null;\n}\n\nfunction classifyTarget(target: string): \"s3\" | \"elb\" | \"cloudfront\" | null {\n if (/\\.s3[.-](.*\\.)?amazonaws\\.com(\\.cn)?\\.?$/.test(target)) return \"s3\";\n if (/\\.elb\\.amazonaws\\.com(\\.cn)?\\.?$/.test(target)) return \"elb\";\n if (/\\.cloudfront\\.net\\.?$/.test(target)) return \"cloudfront\";\n return null;\n}\n\nasync function dnsResolves(hostname: string): Promise<boolean> {\n try {\n // Remove trailing dot for DNS lookup\n const h = hostname.endsWith(\".\") ? hostname.slice(0, -1) : hostname;\n await dns.resolve(h);\n return true;\n } catch {\n return false;\n }\n}\n\nexport class DnsDanglingScanner implements Scanner {\n readonly moduleName = \"dns_dangling\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const route53 = createClient(Route53Client, region, ctx.credentials);\n\n // List hosted zones\n const zones: HostedZone[] = [];\n let marker: string | undefined;\n do {\n const resp = await route53.send(\n new ListHostedZonesCommand({ Marker: marker }),\n );\n if (resp.HostedZones) zones.push(...resp.HostedZones);\n marker = resp.IsTruncated ? resp.NextMarker : undefined;\n } while (marker);\n\n for (const zone of zones) {\n const zoneId = zone.Id ?? \"unknown\";\n const zoneName = zone.Name ?? \"unknown\";\n const shortZoneId = zoneId.replace(\"/hostedzone/\", \"\");\n\n // List record sets\n const records: ResourceRecordSet[] = [];\n let nextName: string | undefined;\n let nextType: string | undefined;\n do {\n const resp = await route53.send(\n new ListResourceRecordSetsCommand({\n HostedZoneId: shortZoneId,\n StartRecordName: nextName,\n StartRecordType: nextType as ResourceRecordSet[\"Type\"],\n }),\n );\n if (resp.ResourceRecordSets) records.push(...resp.ResourceRecordSets);\n if (resp.IsTruncated) {\n nextName = resp.NextRecordName;\n nextType = resp.NextRecordType;\n } else {\n nextName = undefined;\n nextType = undefined;\n }\n } while (nextName);\n\n // Filter CNAME records\n const cnameRecords = records.filter(\n (r) => r.Type === \"CNAME\" && r.ResourceRecords && r.ResourceRecords.length > 0,\n );\n\n resourcesScanned += cnameRecords.length;\n\n for (const record of cnameRecords) {\n const recordName = record.Name ?? \"unknown\";\n const target = record.ResourceRecords![0].Value ?? \"\";\n const recordArn = `arn:${partition}:route53:::hostedzone/${shortZoneId}`;\n const targetType = classifyTarget(target);\n\n if (targetType === \"s3\") {\n // Check if S3 bucket exists\n const bucketName = extractS3BucketName(target);\n if (bucketName) {\n let bucketExists = false;\n try {\n const s3 = createClient(S3Client, region, ctx.credentials);\n await s3.send(new HeadBucketCommand({ Bucket: bucketName }));\n bucketExists = true;\n } catch (e: unknown) {\n const errName = (e as { name?: string }).name ?? \"\";\n // 404 / NoSuchBucket = doesn't exist; 403 = exists but no access\n if (errName === \"Forbidden\" || errName === \"AccessDenied\" || errName === \"403\") {\n bucketExists = true;\n }\n }\n\n if (!bucketExists) {\n findings.push(\n makeFinding({\n riskScore: 9.5,\n title: `CNAME ${recordName} points to non-existent S3 bucket \"${bucketName}\"`,\n resourceType: \"AWS::Route53::RecordSet\",\n resourceId: recordName,\n resourceArn: recordArn,\n region,\n description: `DNS record \"${recordName}\" in zone \"${zoneName}\" has a CNAME to S3 bucket \"${bucketName}\" which does not exist. An attacker can claim this bucket for subdomain takeover.`,\n impact:\n \"Critical subdomain takeover vulnerability. An attacker can create the S3 bucket and serve arbitrary content on your domain, enabling phishing, cookie theft, and reputation damage.\",\n remediationSteps: [\n \"Immediately create the S3 bucket to prevent takeover.\",\n \"Remove the dangling DNS record if the bucket is no longer needed.\",\n \"Audit all CNAME records pointing to S3 buckets.\",\n ],\n }),\n );\n }\n }\n } else if (targetType === \"elb\") {\n const resolves = await dnsResolves(target);\n if (!resolves) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `CNAME ${recordName} points to non-resolving ELB`,\n resourceType: \"AWS::Route53::RecordSet\",\n resourceId: recordName,\n resourceArn: recordArn,\n region,\n description: `DNS record \"${recordName}\" in zone \"${zoneName}\" has a CNAME to ELB \"${target}\" which does not resolve. The load balancer may have been deleted.`,\n impact:\n \"Potential subdomain takeover if the ELB DNS name can be re-registered. Dangling DNS records indicate resource lifecycle gaps.\",\n remediationSteps: [\n \"Remove the dangling DNS record.\",\n \"If the ELB was deleted, clean up all associated DNS records.\",\n \"Implement automated DNS record cleanup when decommissioning resources.\",\n ],\n }),\n );\n }\n } else if (targetType === \"cloudfront\") {\n const resolves = await dnsResolves(target);\n if (!resolves) {\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `CNAME ${recordName} points to non-resolving CloudFront distribution`,\n resourceType: \"AWS::Route53::RecordSet\",\n resourceId: recordName,\n resourceArn: recordArn,\n region,\n description: `DNS record \"${recordName}\" in zone \"${zoneName}\" has a CNAME to CloudFront \"${target}\" which does not resolve. The distribution may have been deleted.`,\n impact:\n \"Potential subdomain takeover via CloudFront. An attacker may create a distribution with this alternate domain name.\",\n remediationSteps: [\n \"Remove the dangling DNS record.\",\n \"If the CloudFront distribution was deleted, clean up associated DNS records.\",\n \"Use CloudFront Origin Access Identity to limit exposure.\",\n ],\n }),\n );\n }\n } else if (targetType === null) {\n // Generic CNAME — just check if it resolves\n const resolves = await dnsResolves(target);\n if (!resolves) {\n findings.push(\n makeFinding({\n riskScore: 5.0,\n title: `CNAME ${recordName} target does not resolve`,\n resourceType: \"AWS::Route53::RecordSet\",\n resourceId: recordName,\n resourceArn: recordArn,\n region,\n description: `DNS record \"${recordName}\" in zone \"${zoneName}\" has a CNAME to \"${target}\" which does not resolve.`,\n impact:\n \"Orphaned DNS record pointing to a non-existent target. May indicate incomplete resource cleanup.\",\n remediationSteps: [\n \"Verify the target resource still exists.\",\n \"Remove the DNS record if it is no longer needed.\",\n \"Implement DNS record lifecycle management.\",\n ],\n }),\n );\n }\n }\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n EC2Client,\n DescribeInstancesCommand,\n DescribeSecurityGroupsCommand,\n DescribeNetworkAclsCommand,\n DescribeAddressesCommand,\n type Instance,\n type SecurityGroup,\n type NetworkAcl,\n type IpPermission,\n type NetworkAclEntry,\n} from \"@aws-sdk/client-ec2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst HIGH_RISK_PORTS: Record<number, string> = {\n 22: \"SSH\",\n 3389: \"RDP\",\n 3306: \"MySQL\",\n 5432: \"PostgreSQL\",\n 1433: \"MSSQL\",\n 27017: \"MongoDB\",\n 6379: \"Redis\",\n 9200: \"Elasticsearch\",\n 11211: \"Memcached\",\n};\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction sgAllowsPort(sgs: SecurityGroup[], port: number): boolean {\n for (const sg of sgs) {\n for (const perm of sg.IpPermissions ?? []) {\n if (permissionAllowsWorldPort(perm, port)) return true;\n }\n }\n return false;\n}\n\nfunction sgAllowsAllPorts(sgs: SecurityGroup[]): boolean {\n for (const sg of sgs) {\n for (const perm of sg.IpPermissions ?? []) {\n if (isAllPorts(perm) && hasWorldCidr(perm)) return true;\n }\n }\n return false;\n}\n\nfunction permissionAllowsWorldPort(perm: IpPermission, port: number): boolean {\n if (!hasWorldCidr(perm)) return false;\n const from = perm.FromPort ?? -1;\n const to = perm.ToPort ?? -1;\n if (from === -1 && to === -1) return true; // all traffic\n return port >= from && port <= to;\n}\n\nfunction hasWorldCidr(perm: IpPermission): boolean {\n const hasIpv4 = (perm.IpRanges ?? []).some((r) => r.CidrIp === \"0.0.0.0/0\");\n const hasIpv6 = (perm.Ipv6Ranges ?? []).some((r) => r.CidrIpv6 === \"::/0\");\n return hasIpv4 || hasIpv6;\n}\n\nfunction isAllPorts(perm: IpPermission): boolean {\n const from = perm.FromPort ?? -1;\n const to = perm.ToPort ?? -1;\n return (from === -1 && to === -1) || (from === 0 && to === 65535);\n}\n\nfunction naclAllowsPort(nacl: NetworkAcl, port: number): boolean {\n // NACL rules are evaluated in order (lowest rule number first)\n // We check inbound rules only (Egress === false)\n const inboundRules = (nacl.Entries ?? [])\n .filter((e) => e.Egress === false)\n .sort((a, b) => (a.RuleNumber ?? 0) - (b.RuleNumber ?? 0));\n\n for (const rule of inboundRules) {\n if (naclRuleMatchesPort(rule, port) && naclRuleMatchesWorldCidr(rule)) {\n // RuleAction \"allow\" or \"deny\"\n return rule.RuleAction === \"allow\";\n }\n }\n // Default: deny\n return false;\n}\n\nfunction naclRuleMatchesPort(rule: NetworkAclEntry, port: number): boolean {\n // Protocol -1 means all traffic\n if (rule.Protocol === \"-1\") return true;\n // Protocol 6 = TCP, 17 = UDP\n if (rule.Protocol !== \"6\" && rule.Protocol !== \"17\") return false;\n const from = rule.PortRange?.From ?? 0;\n const to = rule.PortRange?.To ?? 65535;\n return port >= from && port <= to;\n}\n\nfunction naclRuleMatchesWorldCidr(rule: NetworkAclEntry): boolean {\n return rule.CidrBlock === \"0.0.0.0/0\" || rule.Ipv6CidrBlock === \"::/0\";\n}\n\nexport class NetworkReachabilityScanner implements Scanner {\n readonly moduleName = \"network_reachability\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n const client = createClient(EC2Client, region, ctx.credentials);\n\n // Get EIPs for lookup\n const eipMap = new Map<string, string>(); // instanceId -> EIP\n try {\n const eipResp = await client.send(new DescribeAddressesCommand({}));\n for (const addr of eipResp.Addresses ?? []) {\n if (addr.InstanceId && addr.PublicIp) {\n eipMap.set(addr.InstanceId, addr.PublicIp);\n }\n }\n } catch (e: unknown) {\n warnings.push(`Could not list Elastic IPs: ${e instanceof Error ? e.message : String(e)}`);\n }\n\n // Get instances\n const instances: Instance[] = [];\n let nextToken: string | undefined;\n do {\n const resp = await client.send(\n new DescribeInstancesCommand({ NextToken: nextToken }),\n );\n for (const res of resp.Reservations ?? []) {\n if (res.Instances) instances.push(...res.Instances);\n }\n nextToken = resp.NextToken;\n } while (nextToken);\n\n // Filter to instances with public IPs or EIPs\n const publicInstances = instances.filter((inst) => {\n const instId = inst.InstanceId ?? \"\";\n return inst.PublicIpAddress || eipMap.has(instId);\n });\n\n // Collect all SG IDs and subnet IDs\n const sgIds = new Set<string>();\n const subnetIds = new Set<string>();\n for (const inst of publicInstances) {\n for (const sg of inst.SecurityGroups ?? []) {\n if (sg.GroupId) sgIds.add(sg.GroupId);\n }\n if (inst.SubnetId) subnetIds.add(inst.SubnetId);\n }\n\n // Fetch all referenced SGs\n const sgMap = new Map<string, SecurityGroup>();\n if (sgIds.size > 0) {\n const sgResp = await client.send(\n new DescribeSecurityGroupsCommand({\n GroupIds: [...sgIds],\n }),\n );\n for (const sg of sgResp.SecurityGroups ?? []) {\n if (sg.GroupId) sgMap.set(sg.GroupId, sg);\n }\n }\n\n // Fetch NACLs for referenced subnets\n const subnetNaclMap = new Map<string, NetworkAcl>(); // subnetId -> NACL\n if (subnetIds.size > 0) {\n let naclToken: string | undefined;\n const allNacls: NetworkAcl[] = [];\n do {\n const naclResp = await client.send(\n new DescribeNetworkAclsCommand({\n Filters: [{ Name: \"association.subnet-id\", Values: [...subnetIds] }],\n NextToken: naclToken,\n }),\n );\n if (naclResp.NetworkAcls) allNacls.push(...naclResp.NetworkAcls);\n naclToken = naclResp.NextToken;\n } while (naclToken);\n\n for (const nacl of allNacls) {\n for (const assoc of nacl.Associations ?? []) {\n if (assoc.SubnetId) {\n subnetNaclMap.set(assoc.SubnetId, nacl);\n }\n }\n }\n }\n\n // Analyze each public instance\n for (const inst of publicInstances) {\n const instId = inst.InstanceId ?? \"unknown\";\n const instArn = `arn:${partition}:ec2:${region}:${accountId}:instance/${instId}`;\n const publicIp = inst.PublicIpAddress ?? eipMap.get(instId) ?? \"unknown\";\n const subnetId = inst.SubnetId ?? \"\";\n\n // Get this instance's SGs\n const instSgs: SecurityGroup[] = [];\n for (const sg of inst.SecurityGroups ?? []) {\n if (sg.GroupId) {\n const fullSg = sgMap.get(sg.GroupId);\n if (fullSg) instSgs.push(fullSg);\n }\n }\n\n const nacl = subnetNaclMap.get(subnetId);\n\n // Check each high-risk port\n for (const [portStr, portName] of Object.entries(HIGH_RISK_PORTS)) {\n const port = Number(portStr);\n const sgAllows = sgAllowsPort(instSgs, port);\n const naclAllows = nacl ? naclAllowsPort(nacl, port) : true; // if no NACL info, assume allow\n\n if (sgAllows && naclAllows) {\n findings.push(\n makeFinding({\n riskScore: 9.5,\n title: `EC2 ${instId} (${publicIp}): ${portName} (${port}) reachable from internet`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: instArn,\n region,\n description: `EC2 instance \"${instId}\" has public IP ${publicIp} and both its security group(s) and subnet NACL allow inbound ${portName} (port ${port}) from the internet.`,\n impact:\n `${portName} is directly reachable from the internet, enabling brute-force, exploitation, or unauthorized access.`,\n remediationSteps: [\n `Restrict security group inbound rules for port ${port} to specific IPs.`,\n \"Use Systems Manager Session Manager or a bastion host instead of direct access.\",\n \"Add NACL deny rules for high-risk ports as an additional layer.\",\n \"Enable VPC Flow Logs to monitor connection attempts.\",\n ],\n }),\n );\n } else if (sgAllows && !naclAllows) {\n findings.push(\n makeFinding({\n riskScore: 2.0,\n title: `EC2 ${instId}: ${portName} (${port}) allowed by SG but blocked by NACL`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: instArn,\n region,\n description: `EC2 instance \"${instId}\" (${publicIp}) has security group rules allowing ${portName} (port ${port}) from the internet, but the subnet NACL blocks it.`,\n impact:\n \"Currently protected by NACL, but the SG is overly permissive. NACL changes could expose the port.\",\n remediationSteps: [\n `Tighten the security group rules for port ${port} to match the intended access.`,\n \"Do not rely solely on NACLs for access control.\",\n ],\n }),\n );\n }\n }\n\n // Check for all-ports open via SG + NACL\n if (sgAllowsAllPorts(instSgs)) {\n // Check if NACL is also wide open (allows common ports)\n const naclOpen = nacl ? naclAllowsPort(nacl, 80) : true; // proxy check with port 80\n if (naclOpen) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `EC2 ${instId} (${publicIp}): all ports reachable from internet`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: instArn,\n region,\n description: `EC2 instance \"${instId}\" has public IP ${publicIp} and its security group allows all ports from the internet with no NACL restriction.`,\n impact:\n \"All services on this instance are exposed to the internet, creating a large attack surface.\",\n remediationSteps: [\n \"Replace the all-ports SG rule with specific port rules.\",\n \"Implement NACL rules to restrict inbound traffic as defense in depth.\",\n \"Audit all services running on the instance.\",\n ],\n }),\n );\n }\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: publicInstances.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n IAMClient,\n ListUsersCommand,\n ListAttachedUserPoliciesCommand,\n GetPolicyCommand,\n GetPolicyVersionCommand,\n ListUserPoliciesCommand,\n GetUserPolicyCommand,\n type User,\n} from \"@aws-sdk/client-iam\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient, getIamRegion } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\ninterface PolicyStatement {\n Effect?: string;\n Action?: string | string[];\n Resource?: string | string[];\n}\n\nfunction extractActions(doc: unknown): string[] {\n const actions: string[] = [];\n if (!doc || typeof doc !== \"object\") return actions;\n const policy = doc as { Statement?: PolicyStatement | PolicyStatement[] };\n const stmts = Array.isArray(policy.Statement)\n ? policy.Statement\n : policy.Statement\n ? [policy.Statement]\n : [];\n\n for (const stmt of stmts) {\n if (stmt.Effect !== \"Allow\") continue;\n const acts = Array.isArray(stmt.Action)\n ? stmt.Action\n : stmt.Action\n ? [stmt.Action]\n : [];\n actions.push(...acts);\n }\n return actions.map((a) => a.toLowerCase());\n}\n\nfunction hasAction(actions: string[], pattern: string): boolean {\n const pat = pattern.toLowerCase();\n return actions.some((a) => {\n if (a === \"*\") return true;\n if (a === pat) return true;\n // Wildcard match: \"iam:*\" matches \"iam:createrole\"\n if (a.endsWith(\"*\")) {\n const prefix = a.slice(0, -1);\n if (pat.startsWith(prefix)) return true;\n }\n return false;\n });\n}\n\nexport class IamPrivilegeEscalationScanner implements Scanner {\n readonly moduleName = \"iam_privilege_escalation\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n const iamRegion = getIamRegion(region);\n\n warnings.push(\n \"Note: This scanner currently checks IAM users only. Role and group policy analysis will be added in a future version.\",\n );\n\n try {\n const client = createClient(IAMClient, iamRegion, ctx.credentials);\n\n // List all IAM users\n const users: User[] = [];\n let marker: string | undefined;\n do {\n const resp = await client.send(\n new ListUsersCommand({ Marker: marker }),\n );\n if (resp.Users) users.push(...resp.Users);\n marker = resp.IsTruncated ? resp.Marker : undefined;\n } while (marker);\n\n for (const user of users) {\n const userName = user.UserName ?? \"unknown\";\n const userArn =\n user.Arn ??\n `arn:${partition}:iam::${accountId}:user/${userName}`;\n\n // Collect all allowed actions from both managed and inline policies\n const allActions: string[] = [];\n\n // 1. Check attached (managed) policies\n try {\n const attachedResp = await client.send(\n new ListAttachedUserPoliciesCommand({ UserName: userName }),\n );\n for (const policy of attachedResp.AttachedPolicies ?? []) {\n const policyArn = policy.PolicyArn;\n if (!policyArn) continue;\n try {\n const policyResp = await client.send(\n new GetPolicyCommand({ PolicyArn: policyArn }),\n );\n const versionId =\n policyResp.Policy?.DefaultVersionId ?? \"v1\";\n const versionResp = await client.send(\n new GetPolicyVersionCommand({\n PolicyArn: policyArn,\n VersionId: versionId,\n }),\n );\n const doc = versionResp.PolicyVersion?.Document;\n if (doc) {\n const parsed = JSON.parse(decodeURIComponent(doc));\n allActions.push(...extractActions(parsed));\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(\n `Could not read policy ${policyArn} for user ${userName}: ${msg}`,\n );\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(\n `Could not list attached policies for user ${userName}: ${msg}`,\n );\n }\n\n // 2. Check inline policies\n try {\n const inlineResp = await client.send(\n new ListUserPoliciesCommand({ UserName: userName }),\n );\n for (const policyName of inlineResp.PolicyNames ?? []) {\n try {\n const inlinePolicyResp = await client.send(\n new GetUserPolicyCommand({\n UserName: userName,\n PolicyName: policyName,\n }),\n );\n const doc = inlinePolicyResp.PolicyDocument;\n if (doc) {\n const parsed = JSON.parse(decodeURIComponent(doc));\n allActions.push(...extractActions(parsed));\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(\n `Could not read inline policy ${policyName} for user ${userName}: ${msg}`,\n );\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(\n `Could not list inline policies for user ${userName}: ${msg}`,\n );\n }\n\n if (allActions.length === 0) continue;\n\n // Check for wildcard iam:* or full wildcard *\n if (\n hasAction(allActions, \"iam:*\") ||\n allActions.includes(\"*\")\n ) {\n findings.push(\n makeFinding({\n riskScore: 9.0,\n title: `IAM user ${userName} has iam:* wildcard permissions`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has wildcard IAM permissions (iam:* or *), granting full control over identity and access management.`,\n impact:\n \"The user can create, modify, or delete any IAM resource including creating admin users, modifying policies, and escalating privileges without restriction.\",\n remediationSteps: [\n `Remove wildcard IAM permissions from user \"${userName}\".`,\n \"Replace with specific, least-privilege IAM permissions.\",\n \"Use IAM Access Analyzer to identify actually used permissions.\",\n ],\n }),\n );\n // Skip further checks — wildcard already covers everything\n continue;\n }\n\n // Self-grant admin: iam:PutUserPolicy or iam:AttachUserPolicy\n if (\n hasAction(allActions, \"iam:putuserpolicy\") ||\n hasAction(allActions, \"iam:attachuserpolicy\")\n ) {\n findings.push(\n makeFinding({\n riskScore: 9.5,\n title: `IAM user ${userName} can self-grant admin via policy attachment`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has iam:PutUserPolicy or iam:AttachUserPolicy, allowing them to attach AdministratorAccess or any policy to themselves.`,\n impact:\n \"The user can escalate to full administrator access by attaching an admin policy to their own account.\",\n remediationSteps: [\n `Remove iam:PutUserPolicy and iam:AttachUserPolicy from user \"${userName}\".`,\n \"Use permission boundaries to restrict policy attachment scope.\",\n \"Require MFA for sensitive IAM operations via condition keys.\",\n ],\n }),\n );\n }\n\n // Create admin roles: iam:CreateRole + iam:AttachRolePolicy\n if (\n hasAction(allActions, \"iam:createrole\") &&\n hasAction(allActions, \"iam:attachrolepolicy\")\n ) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `IAM user ${userName} can create admin roles`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has both iam:CreateRole and iam:AttachRolePolicy, allowing creation of new roles with admin policies.`,\n impact:\n \"The user can create a new IAM role with AdministratorAccess and assume it to gain full account access.\",\n remediationSteps: [\n `Restrict iam:CreateRole and iam:AttachRolePolicy with resource conditions for user \"${userName}\".`,\n \"Use permission boundaries on all created roles.\",\n \"Monitor IAM role creation via CloudTrail alerts.\",\n ],\n }),\n );\n }\n\n // PassRole + Lambda escalation: iam:PassRole + lambda:CreateFunction\n if (\n hasAction(allActions, \"iam:passrole\") &&\n hasAction(allActions, \"lambda:createfunction\")\n ) {\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `IAM user ${userName} can escalate via Lambda role passing`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has iam:PassRole and lambda:CreateFunction, allowing them to create a Lambda function with an admin role.`,\n impact:\n \"The user can pass a high-privilege role to a Lambda function and invoke it to execute actions beyond their own permissions.\",\n remediationSteps: [\n `Restrict iam:PassRole to specific role ARNs for user \"${userName}\".`,\n \"Use condition keys to limit which roles can be passed to Lambda.\",\n \"Implement SCP guardrails for privilege escalation paths.\",\n ],\n }),\n );\n }\n\n // Create access keys for other users: iam:CreateAccessKey\n if (hasAction(allActions, \"iam:createaccesskey\")) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `IAM user ${userName} can create access keys for other users`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has iam:CreateAccessKey, which allows creating access keys for any IAM user unless restricted by resource conditions.`,\n impact:\n \"The user can impersonate other IAM users (including admins) by generating access keys on their behalf.\",\n remediationSteps: [\n `Restrict iam:CreateAccessKey to the user's own ARN using a resource condition.`,\n \"Implement SCP to prevent cross-user key creation.\",\n \"Monitor CreateAccessKey events in CloudTrail.\",\n ],\n }),\n );\n }\n\n // STS AssumeRole on admin roles\n if (hasAction(allActions, \"sts:assumerole\")) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `IAM user ${userName} can assume roles (potential admin escalation)`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has sts:AssumeRole, which may allow assuming high-privilege or admin roles if not restricted by resource ARN.`,\n impact:\n \"The user can escalate privileges by assuming roles with higher permissions than their own.\",\n remediationSteps: [\n `Restrict sts:AssumeRole to specific role ARNs for user \"${userName}\".`,\n \"Require MFA for assuming sensitive roles via role trust policy conditions.\",\n \"Audit which roles this user can assume and their permission levels.\",\n ],\n }),\n );\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: users.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n S3Client,\n ListBucketsCommand,\n GetPublicAccessBlockCommand,\n GetBucketAclCommand,\n GetBucketPolicyStatusCommand,\n GetBucketLocationCommand,\n} from \"@aws-sdk/client-s3\";\nimport {\n RDSClient,\n DescribeDBInstancesCommand,\n type DBInstance,\n} from \"@aws-sdk/client-rds\";\nimport dns from \"node:dns\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction s3Endpoint(bucket: string, region: string): string {\n const suffix = region.startsWith(\"cn-\")\n ? \"amazonaws.com.cn\"\n : \"amazonaws.com\";\n return `https://${bucket}.s3.${region}.${suffix}/`;\n}\n\nasync function getBucketRegion(\n client: S3Client,\n bucketName: string,\n defaultRegion: string,\n warnings: string[],\n): Promise<string> {\n try {\n const resp = await client.send(\n new GetBucketLocationCommand({ Bucket: bucketName }),\n );\n const loc = String(resp.LocationConstraint ?? \"\") || \"us-east-1\";\n return loc;\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Failed to detect region for bucket ${bucketName}, using ${defaultRegion}: ${msg}`);\n return defaultRegion;\n }\n}\n\nasync function isBucketMarkedPublic(\n client: S3Client,\n bucketName: string,\n warnings: string[],\n): Promise<boolean | \"skip\"> {\n // Check if Block Public Access is off AND (public ACL or public policy)\n let bpaBlocks = false;\n try {\n const bpa = await client.send(\n new GetPublicAccessBlockCommand({ Bucket: bucketName }),\n );\n const cfg = bpa.PublicAccessBlockConfiguration;\n bpaBlocks = !!(\n cfg?.BlockPublicAcls &&\n cfg?.IgnorePublicAcls &&\n cfg?.BlockPublicPolicy &&\n cfg?.RestrictPublicBuckets\n );\n } catch (e: unknown) {\n if (\n e instanceof Error &&\n e.name === \"NoSuchPublicAccessBlockConfiguration\"\n ) {\n bpaBlocks = false;\n } else {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Could not check public access for bucket ${bucketName}: ${msg}`);\n return \"skip\";\n }\n }\n\n if (bpaBlocks) return false;\n\n // Check ACL for public grants\n try {\n const acl = await client.send(\n new GetBucketAclCommand({ Bucket: bucketName }),\n );\n for (const grant of acl.Grants ?? []) {\n const uri = grant.Grantee?.URI ?? \"\";\n if (uri.includes(\"AllUsers\") || uri.includes(\"AuthenticatedUsers\")) {\n return true;\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Could not check ACL for bucket ${bucketName}: ${msg}`);\n }\n\n // Check bucket policy status\n try {\n const policyStatus = await client.send(\n new GetBucketPolicyStatusCommand({ Bucket: bucketName }),\n );\n if (policyStatus.PolicyStatus?.IsPublic) return true;\n } catch (e: unknown) {\n // NoSuchBucketPolicy is expected for buckets without policies\n if (e instanceof Error && !e.name.includes(\"NoSuchBucketPolicy\")) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Could not check policy status for bucket ${bucketName}: ${msg}`);\n }\n }\n\n return false;\n}\n\nfunction isPrivateIp(ip: string): boolean {\n if (ip.startsWith(\"10.\")) return true;\n if (ip.startsWith(\"192.168.\")) return true;\n if (ip.startsWith(\"172.\")) {\n const second = parseInt(ip.split(\".\")[1], 10);\n return second >= 16 && second <= 31;\n }\n if (ip.startsWith(\"127.\")) return true;\n return false;\n}\n\nexport class PublicAccessVerifyScanner implements Scanner {\n readonly moduleName = \"public_access_verify\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n // --- S3 public access verification ---\n try {\n const s3Client = createClient(S3Client, region, ctx.credentials);\n const listResp = await s3Client.send(new ListBucketsCommand({}));\n const buckets = listResp.Buckets ?? [];\n\n for (const bucket of buckets) {\n const name = bucket.Name ?? \"unknown\";\n const arn = `arn:${partition}:s3:::${name}`;\n\n const bucketRegion = await getBucketRegion(s3Client, name, region, warnings);\n const bucketClient =\n bucketRegion === region\n ? s3Client\n : createClient(S3Client, bucketRegion, ctx.credentials);\n\n const markedPublic = await isBucketMarkedPublic(bucketClient, name, warnings);\n if (markedPublic === \"skip\" || !markedPublic) continue;\n\n resourcesScanned++;\n const url = s3Endpoint(name, bucketRegion);\n\n try {\n const resp = await fetch(url, {\n method: \"HEAD\",\n signal: AbortSignal.timeout(5000),\n });\n\n if (resp.ok || resp.status === 200) {\n findings.push(\n makeFinding({\n riskScore: 9.5,\n title: `S3 bucket ${name} is publicly readable (verified)`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region: bucketRegion,\n description: `HTTP HEAD to ${url} returned status ${resp.status}. The bucket is confirmed publicly accessible from the internet.`,\n impact:\n \"Anyone on the internet can read objects from this bucket, potentially exposing sensitive data.\",\n remediationSteps: [\n \"Enable Block Public Access on the bucket immediately.\",\n \"Review and remove public ACL grants and public bucket policies.\",\n \"Audit bucket contents for sensitive data exposure.\",\n ],\n }),\n );\n } else if (resp.status === 403) {\n findings.push(\n makeFinding({\n riskScore: 2.0,\n title: `S3 bucket ${name} is marked public but returns 403 (blocked)`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region: bucketRegion,\n description: `Bucket \"${name}\" has public ACL/policy configuration but HTTP access returns 403 Forbidden, likely blocked by other controls.`,\n impact:\n \"Currently not accessible, but the public configuration is a risk if blocking controls are removed.\",\n remediationSteps: [\n \"Clean up the public ACL or policy to match the intended access model.\",\n \"Enable Block Public Access to formalize the restriction.\",\n ],\n }),\n );\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`HTTP check for bucket ${name} failed: ${msg}`);\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`S3 public access verification failed: ${msg}`);\n }\n\n // --- RDS public DNS verification ---\n try {\n const rdsClient = createClient(RDSClient, region, ctx.credentials);\n const instances: DBInstance[] = [];\n let marker: string | undefined;\n do {\n const resp = await rdsClient.send(\n new DescribeDBInstancesCommand({ Marker: marker }),\n );\n if (resp.DBInstances) instances.push(...resp.DBInstances);\n marker = resp.Marker;\n } while (marker);\n\n for (const db of instances) {\n if (!db.PubliclyAccessible) continue;\n\n const dbId = db.DBInstanceIdentifier ?? \"unknown\";\n const dbArn =\n db.DBInstanceArn ??\n `arn:${partition}:rds:${region}:${accountId}:db/${dbId}`;\n const endpoint = db.Endpoint?.Address;\n if (!endpoint) continue;\n\n resourcesScanned++;\n\n try {\n const addresses = await dns.promises.resolve4(endpoint);\n const hasPublicIp = addresses.some((ip) => !isPrivateIp(ip));\n\n if (hasPublicIp) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `RDS instance ${dbId} endpoint resolves to public IP (verified)`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS endpoint ${endpoint} resolves to public IP(s): ${addresses.join(\", \")}. The database is network-reachable from the internet.`,\n impact:\n \"The database can be reached from the public internet, making it vulnerable to brute-force, credential stuffing, and exploitation of database vulnerabilities.\",\n remediationSteps: [\n \"Set PubliclyAccessible to false on the RDS instance.\",\n \"Move the instance to a private subnet.\",\n \"Use VPN or bastion host for database access.\",\n \"Restrict security group inbound rules to known IPs.\",\n ],\n }),\n );\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`DNS resolution for RDS ${dbId} (${endpoint}) failed: ${msg}`);\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`RDS public access verification failed: ${msg}`);\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n EC2Client,\n DescribeInstancesCommand,\n type Instance,\n} from \"@aws-sdk/client-ec2\";\nimport {\n RDSClient,\n DescribeDBInstancesCommand,\n type DBInstance,\n} from \"@aws-sdk/client-rds\";\nimport {\n S3Client,\n ListBucketsCommand,\n GetBucketTaggingCommand,\n} from \"@aws-sdk/client-s3\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst DEFAULT_REQUIRED_TAGS = [\"Environment\", \"Project\", \"Owner\"];\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction getMissingTags(\n tags: Array<{ Key?: string; Value?: string }>,\n requiredTags: string[],\n): string[] {\n const tagKeys = new Set(tags.map((t) => t.Key ?? \"\"));\n return requiredTags.filter((rt) => !tagKeys.has(rt));\n}\n\nexport class TagComplianceScanner implements Scanner {\n readonly moduleName = \"tag_compliance\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n const requiredTags = DEFAULT_REQUIRED_TAGS;\n\n try {\n // --- EC2 instances ---\n try {\n const ec2Client = createClient(EC2Client, region, ctx.credentials);\n const instances: Instance[] = [];\n let nextToken: string | undefined;\n do {\n const resp = await ec2Client.send(\n new DescribeInstancesCommand({ NextToken: nextToken }),\n );\n for (const res of resp.Reservations ?? []) {\n if (res.Instances) instances.push(...res.Instances);\n }\n nextToken = resp.NextToken;\n } while (nextToken);\n\n resourcesScanned += instances.length;\n\n for (const instance of instances) {\n const id = instance.InstanceId ?? \"unknown\";\n const arn = `arn:${partition}:ec2:${region}:${accountId}:instance/${id}`;\n const tags = instance.Tags ?? [];\n const missing = getMissingTags(tags, requiredTags);\n\n if (missing.length > 0) {\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `EC2 instance ${id} missing required tags: ${missing.join(\", \")}`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: id,\n resourceArn: arn,\n region,\n description: `EC2 instance \"${id}\" is missing the following required tags: ${missing.join(\", \")}.`,\n impact:\n \"Resources without proper tags cannot be tracked for cost allocation, ownership, or compliance purposes.\",\n remediationSteps: [\n `Add the missing tags (${missing.join(\", \")}) to instance ${id}.`,\n \"Implement AWS Config rules or Tag Policies to enforce tagging.\",\n \"Use AWS Tag Editor for bulk tagging operations.\",\n ],\n }),\n );\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`EC2 tag compliance check failed: ${msg}`);\n }\n\n // --- RDS instances ---\n try {\n const rdsClient = createClient(RDSClient, region, ctx.credentials);\n const dbInstances: DBInstance[] = [];\n let marker: string | undefined;\n do {\n const resp = await rdsClient.send(\n new DescribeDBInstancesCommand({ Marker: marker }),\n );\n if (resp.DBInstances) dbInstances.push(...resp.DBInstances);\n marker = resp.Marker;\n } while (marker);\n\n resourcesScanned += dbInstances.length;\n\n for (const db of dbInstances) {\n const dbId = db.DBInstanceIdentifier ?? \"unknown\";\n const dbArn =\n db.DBInstanceArn ??\n `arn:${partition}:rds:${region}:${accountId}:db/${dbId}`;\n const tags = (db.TagList ?? []).map((t) => ({\n Key: t.Key,\n Value: t.Value,\n }));\n const missing = getMissingTags(tags, requiredTags);\n\n if (missing.length > 0) {\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `RDS instance ${dbId} missing required tags: ${missing.join(\", \")}`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS instance \"${dbId}\" is missing the following required tags: ${missing.join(\", \")}.`,\n impact:\n \"Resources without proper tags cannot be tracked for cost allocation, ownership, or compliance purposes.\",\n remediationSteps: [\n `Add the missing tags (${missing.join(\", \")}) to RDS instance ${dbId}.`,\n \"Implement AWS Config rules or Tag Policies to enforce tagging.\",\n \"Use AWS Tag Editor for bulk tagging operations.\",\n ],\n }),\n );\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`RDS tag compliance check failed: ${msg}`);\n }\n\n // --- S3 buckets ---\n try {\n const s3Client = createClient(S3Client, region, ctx.credentials);\n const listResp = await s3Client.send(new ListBucketsCommand({}));\n const buckets = listResp.Buckets ?? [];\n resourcesScanned += buckets.length;\n\n for (const bucket of buckets) {\n const name = bucket.Name ?? \"unknown\";\n const arn = `arn:${partition}:s3:::${name}`;\n\n try {\n const taggingResp = await s3Client.send(\n new GetBucketTaggingCommand({ Bucket: name }),\n );\n const tags = (taggingResp.TagSet ?? []).map((t) => ({\n Key: t.Key,\n Value: t.Value,\n }));\n const missing = getMissingTags(tags, requiredTags);\n\n if (missing.length > 0) {\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `S3 bucket ${name} missing required tags: ${missing.join(\", \")}`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region: \"global\",\n description: `S3 bucket \"${name}\" is missing the following required tags: ${missing.join(\", \")}.`,\n impact:\n \"Resources without proper tags cannot be tracked for cost allocation, ownership, or compliance purposes.\",\n remediationSteps: [\n `Add the missing tags (${missing.join(\", \")}) to bucket ${name}.`,\n \"Implement AWS Config rules or Tag Policies to enforce tagging.\",\n \"Use AWS Tag Editor for bulk tagging operations.\",\n ],\n }),\n );\n }\n } catch (e: unknown) {\n if (\n e instanceof Error &&\n e.name === \"NoSuchTagSet\"\n ) {\n // No tags at all — all required tags are missing\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `S3 bucket ${name} missing required tags: ${requiredTags.join(\", \")}`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region: \"global\",\n description: `S3 bucket \"${name}\" has no tags configured. Missing all required tags: ${requiredTags.join(\", \")}.`,\n impact:\n \"Resources without proper tags cannot be tracked for cost allocation, ownership, or compliance purposes.\",\n remediationSteps: [\n `Add the required tags (${requiredTags.join(\", \")}) to bucket ${name}.`,\n \"Implement AWS Config rules or Tag Policies to enforce tagging.\",\n \"Use AWS Tag Editor for bulk tagging operations.\",\n ],\n }),\n );\n } else {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`S3 tag check for ${name} failed: ${msg}`);\n }\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`S3 tag compliance check failed: ${msg}`);\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n EC2Client,\n DescribeVolumesCommand,\n DescribeAddressesCommand,\n DescribeInstancesCommand,\n DescribeNetworkInterfacesCommand,\n DescribeSecurityGroupsCommand,\n type Volume,\n type Address,\n type Instance,\n type SecurityGroup,\n} from \"@aws-sdk/client-ec2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class IdleResourcesScanner implements Scanner {\n readonly moduleName = \"idle_resources\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n const client = createClient(EC2Client, region, ctx.credentials);\n let resourcesScanned = 0;\n\n // 1. Unattached EBS volumes (State = \"available\")\n const volumes: Volume[] = [];\n let volToken: string | undefined;\n do {\n const resp = await client.send(\n new DescribeVolumesCommand({ NextToken: volToken }),\n );\n if (resp.Volumes) volumes.push(...resp.Volumes);\n volToken = resp.NextToken;\n } while (volToken);\n\n resourcesScanned += volumes.length;\n\n for (const vol of volumes) {\n if (vol.State === \"available\") {\n const volId = vol.VolumeId ?? \"unknown\";\n findings.push(\n makeFinding({\n riskScore: 3.0,\n title: `EBS volume ${volId} is unattached`,\n resourceType: \"AWS::EC2::Volume\",\n resourceId: volId,\n resourceArn: `arn:${partition}:ec2:${region}:${accountId}:volume/${volId}`,\n region,\n description: `EBS volume \"${volId}\" (${vol.Size ?? \"?\"}GB, ${vol.VolumeType ?? \"unknown\"}) is in \"available\" state with no attachments.`,\n impact:\n \"Unattached volumes incur storage costs and may contain sensitive data that is no longer actively managed.\",\n remediationSteps: [\n \"Determine if the volume is still needed.\",\n \"If not needed, create a snapshot for archival and delete the volume.\",\n \"If needed, attach it to the appropriate instance.\",\n ],\n }),\n );\n }\n }\n\n // 2. Unused Elastic IPs (not associated with any instance)\n let addresses: Address[] = [];\n try {\n const addrResp = await client.send(new DescribeAddressesCommand({}));\n addresses = addrResp.Addresses ?? [];\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Elastic IP check failed: ${msg}`);\n }\n\n resourcesScanned += addresses.length;\n\n for (const addr of addresses) {\n if (!addr.AssociationId) {\n const allocId = addr.AllocationId ?? \"unknown\";\n const publicIp = addr.PublicIp ?? \"unknown\";\n findings.push(\n makeFinding({\n riskScore: 2.0,\n title: `Elastic IP ${publicIp} is not associated`,\n resourceType: \"AWS::EC2::EIP\",\n resourceId: allocId,\n resourceArn: `arn:${partition}:ec2:${region}:${accountId}:elastic-ip/${allocId}`,\n region,\n description: `Elastic IP ${publicIp} (${allocId}) is allocated but not associated with any instance or network interface.`,\n impact:\n \"Unused Elastic IPs cost ~$3.60/month each and represent unnecessary spend.\",\n remediationSteps: [\n \"Associate the EIP with an instance or network interface if needed.\",\n \"Release the EIP if it is no longer required.\",\n ],\n }),\n );\n }\n }\n\n // 3. Stopped EC2 instances (>30 days)\n const instances: Instance[] = [];\n let instToken: string | undefined;\n do {\n const instResp = await client.send(\n new DescribeInstancesCommand({ NextToken: instToken }),\n );\n for (const res of instResp.Reservations ?? []) {\n if (res.Instances) instances.push(...res.Instances);\n }\n instToken = instResp.NextToken;\n } while (instToken);\n\n resourcesScanned += instances.length;\n const now = Date.now();\n\n for (const inst of instances) {\n if (inst.State?.Name === \"stopped\") {\n const instId = inst.InstanceId ?? \"unknown\";\n const reason = inst.StateTransitionReason ?? \"\";\n const stoppedTime = reason ? parseStopTime(reason) : null;\n\n if (!stoppedTime) {\n warnings.push(\n `Could not determine stop date for instance ${instId}. StateTransitionReason: ${reason}`,\n );\n continue;\n }\n\n const stoppedDays = Math.round(\n (now - stoppedTime) / (24 * 60 * 60 * 1000),\n );\n\n if (stoppedDays > 30) {\n findings.push(\n makeFinding({\n riskScore: 3.0,\n title: `EC2 instance ${instId} has been stopped for ${stoppedDays} days`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: `arn:${partition}:ec2:${region}:${accountId}:instance/${instId}`,\n region,\n description: `EC2 instance \"${instId}\" (${inst.InstanceType ?? \"unknown\"}) is in stopped state for ${stoppedDays} days. Attached EBS volumes continue to incur charges.`,\n impact:\n \"Stopped instances still incur EBS storage costs and may contain stale configurations or unpatched AMIs.\",\n remediationSteps: [\n \"Determine if the instance is still needed.\",\n \"If not needed, create an AMI for archival and terminate the instance.\",\n \"If needed temporarily, consider using a launch template for on-demand recreation.\",\n ],\n }),\n );\n }\n }\n }\n\n // 4. Unused Security Groups (not attached to any ENI)\n const securityGroups: SecurityGroup[] = [];\n let sgToken: string | undefined;\n do {\n const sgResp = await client.send(\n new DescribeSecurityGroupsCommand({ NextToken: sgToken }),\n );\n if (sgResp.SecurityGroups) securityGroups.push(...sgResp.SecurityGroups);\n sgToken = sgResp.NextToken;\n } while (sgToken);\n\n // Find all SGs referenced by ENIs\n const usedSgIds = new Set<string>();\n let eniToken: string | undefined;\n do {\n const eniResp = await client.send(\n new DescribeNetworkInterfacesCommand({ NextToken: eniToken }),\n );\n for (const eni of eniResp.NetworkInterfaces ?? []) {\n for (const group of eni.Groups ?? []) {\n if (group.GroupId) usedSgIds.add(group.GroupId);\n }\n }\n eniToken = eniResp.NextToken;\n } while (eniToken);\n\n resourcesScanned += securityGroups.length;\n\n for (const sg of securityGroups) {\n const sgId = sg.GroupId ?? \"unknown\";\n // Skip default security groups — they cannot be deleted\n if (sg.GroupName === \"default\") continue;\n\n if (!usedSgIds.has(sgId)) {\n findings.push(\n makeFinding({\n riskScore: 2.0,\n title: `Security group ${sgId} is not attached to any resource`,\n resourceType: \"AWS::EC2::SecurityGroup\",\n resourceId: sgId,\n resourceArn: `arn:${partition}:ec2:${region}:${sg.OwnerId ?? accountId}:security-group/${sgId}`,\n region,\n description: `Security group \"${sg.GroupName}\" (${sgId}) is not associated with any network interface.`,\n impact:\n \"Unused security groups add clutter and may cause confusion during security reviews.\",\n remediationSteps: [\n \"Verify the security group is not referenced by other resources (e.g., launch templates).\",\n \"Delete the security group if it is no longer needed.\",\n ],\n }),\n );\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n\n/**\n * Parse the stop time from EC2 StateTransitionReason.\n * Format: \"User initiated (2024-01-15 08:30:00 GMT)\"\n */\nfunction parseStopTime(reason: string): number | null {\n const match = reason.match(/\\((\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}\\s\\w+)\\)/);\n if (!match) return null;\n const parsed = Date.parse(match[1]);\n return isNaN(parsed) ? null : parsed;\n}\n","import {\n RDSClient,\n DescribeDBInstancesCommand,\n type DBInstance,\n} from \"@aws-sdk/client-rds\";\nimport {\n EC2Client,\n DescribeVolumesCommand,\n DescribeSnapshotsCommand,\n type Volume,\n type Snapshot,\n} from \"@aws-sdk/client-ec2\";\nimport {\n S3Client,\n ListBucketsCommand,\n GetBucketVersioningCommand,\n GetBucketReplicationCommand,\n} from \"@aws-sdk/client-s3\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class DisasterRecoveryScanner implements Scanner {\n readonly moduleName = \"disaster_recovery\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n let resourcesScanned = 0;\n\n // --- RDS checks ---\n const rdsClient = createClient(RDSClient, region, ctx.credentials);\n const instances: DBInstance[] = [];\n let marker: string | undefined;\n do {\n const resp = await rdsClient.send(\n new DescribeDBInstancesCommand({ Marker: marker }),\n );\n if (resp.DBInstances) instances.push(...resp.DBInstances);\n marker = resp.Marker;\n } while (marker);\n\n resourcesScanned += instances.length;\n\n for (const db of instances) {\n const dbId = db.DBInstanceIdentifier ?? \"unknown\";\n const dbArn =\n db.DBInstanceArn ??\n `arn:${partition}:rds:${region}:${accountId}:db/${dbId}`;\n const engine = db.Engine ?? \"unknown\";\n\n // MultiAZ check\n if (!db.MultiAZ) {\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: `RDS instance ${dbId} is not Multi-AZ`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS instance \"${dbId}\" (${engine}) does not have Multi-AZ deployment enabled.`,\n impact:\n \"Single-AZ deployments have no automatic failover. An AZ outage will cause downtime and potential data loss.\",\n remediationSteps: [\n \"Enable Multi-AZ deployment for the RDS instance.\",\n \"This provides automatic failover to a standby in a different AZ.\",\n ],\n }),\n );\n }\n\n // Backup retention check\n const retention = db.BackupRetentionPeriod ?? 0;\n if (retention === 0) {\n findings.push(\n makeFinding({\n riskScore: 5.5,\n title: `RDS instance ${dbId} has automated backups disabled`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS instance \"${dbId}\" (${engine}) has backup retention period set to 0 (disabled).`,\n impact:\n \"No automated backups or point-in-time recovery. Data loss from failures or corruption is unrecoverable.\",\n remediationSteps: [\n \"Set the backup retention period to at least 7 days.\",\n \"Consider cross-region backup replication for critical databases.\",\n ],\n }),\n );\n } else if (retention < 7) {\n findings.push(\n makeFinding({\n riskScore: 5.5,\n title: `RDS instance ${dbId} backup retention is only ${retention} day(s)`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS instance \"${dbId}\" (${engine}) has backup retention period of ${retention} day(s), below the recommended 7 days.`,\n impact:\n \"Short retention windows limit point-in-time recovery options and may not meet compliance requirements.\",\n remediationSteps: [\n \"Increase the backup retention period to at least 7 days.\",\n \"For production databases, consider 14-35 days retention.\",\n ],\n }),\n );\n }\n }\n\n // --- EBS snapshot checks ---\n const ec2Client = createClient(EC2Client, region, ctx.credentials);\n\n const volumes: Volume[] = [];\n let volToken: string | undefined;\n do {\n const resp = await ec2Client.send(\n new DescribeVolumesCommand({ NextToken: volToken }),\n );\n if (resp.Volumes) volumes.push(...resp.Volumes);\n volToken = resp.NextToken;\n } while (volToken);\n\n // Get all snapshots owned by this account\n const snapshots: Snapshot[] = [];\n let snapToken: string | undefined;\n do {\n const resp = await ec2Client.send(\n new DescribeSnapshotsCommand({\n OwnerIds: [\"self\"],\n NextToken: snapToken,\n }),\n );\n if (resp.Snapshots) snapshots.push(...resp.Snapshots);\n snapToken = resp.NextToken;\n } while (snapToken);\n\n // Build a map: volumeId -> most recent snapshot time\n const latestSnapshotByVolume = new Map<string, number>();\n for (const snap of snapshots) {\n if (!snap.VolumeId || snap.State !== \"completed\") continue;\n const snapTime = snap.StartTime?.getTime() ?? 0;\n const existing = latestSnapshotByVolume.get(snap.VolumeId) ?? 0;\n if (snapTime > existing) {\n latestSnapshotByVolume.set(snap.VolumeId, snapTime);\n }\n }\n\n // Only check in-use volumes for snapshot coverage\n const inUseVolumes = volumes.filter((v) => v.State === \"in-use\");\n resourcesScanned += inUseVolumes.length;\n const now = Date.now();\n\n for (const vol of inUseVolumes) {\n const volId = vol.VolumeId ?? \"unknown\";\n const volArn = `arn:${partition}:ec2:${region}:${accountId}:volume/${volId}`;\n const latestSnap = latestSnapshotByVolume.get(volId);\n\n if (latestSnap === undefined) {\n // No snapshots at all\n findings.push(\n makeFinding({\n riskScore: 7.0,\n title: `EBS volume ${volId} has no snapshots`,\n resourceType: \"AWS::EC2::Volume\",\n resourceId: volId,\n resourceArn: volArn,\n region,\n description: `EBS volume \"${volId}\" (${vol.Size ?? \"?\"}GB, ${vol.VolumeType ?? \"unknown\"}) has no snapshots. Data cannot be recovered if the volume fails.`,\n impact:\n \"Complete data loss if the volume becomes unavailable. No backup exists for disaster recovery.\",\n remediationSteps: [\n \"Create a snapshot of the volume immediately.\",\n \"Set up automated snapshots using AWS Backup or Amazon Data Lifecycle Manager.\",\n ],\n }),\n );\n } else if (now - latestSnap > SEVEN_DAYS_MS) {\n const daysSince = Math.round((now - latestSnap) / (24 * 60 * 60 * 1000));\n findings.push(\n makeFinding({\n riskScore: 5.0,\n title: `EBS volume ${volId} has no recent snapshot (${daysSince} days old)`,\n resourceType: \"AWS::EC2::Volume\",\n resourceId: volId,\n resourceArn: volArn,\n region,\n description: `EBS volume \"${volId}\" (${vol.Size ?? \"?\"}GB) most recent snapshot is ${daysSince} days old, exceeding the 7-day threshold.`,\n impact:\n \"Recovery from the latest snapshot would lose up to ${daysSince} days of data.\",\n remediationSteps: [\n \"Create a fresh snapshot of the volume.\",\n \"Configure automated snapshot schedules using AWS Backup or Data Lifecycle Manager.\",\n ],\n }),\n );\n }\n }\n\n // --- S3 checks ---\n const s3Client = createClient(S3Client, region, ctx.credentials);\n\n let bucketNames: string[] = [];\n try {\n const listResp = await s3Client.send(new ListBucketsCommand({}));\n bucketNames = (listResp.Buckets ?? []).map((b) => b.Name).filter((n): n is string => !!n);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`S3 bucket list failed: ${msg}`);\n }\n\n resourcesScanned += bucketNames.length;\n\n for (const name of bucketNames) {\n const arn = `arn:${partition}:s3:::${name}`;\n\n // Versioning check\n try {\n const ver = await s3Client.send(\n new GetBucketVersioningCommand({ Bucket: name }),\n );\n if (ver.Status !== \"Enabled\") {\n findings.push(\n makeFinding({\n riskScore: 3.0,\n title: `S3 bucket ${name} does not have versioning enabled`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region,\n description: `Bucket \"${name}\" versioning is ${ver.Status ?? \"not set\"}. Object deletion or overwrite is irreversible.`,\n impact:\n \"Accidental deletion or corruption of objects cannot be recovered without versioning.\",\n remediationSteps: [\n \"Enable versioning on the bucket.\",\n \"Consider adding lifecycle rules to manage version storage costs.\",\n ],\n }),\n );\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Bucket ${name} versioning check failed: ${msg}`);\n }\n\n // Cross-region replication check\n try {\n await s3Client.send(\n new GetBucketReplicationCommand({ Bucket: name }),\n );\n // If the call succeeds, replication is configured — no finding needed\n } catch (e: unknown) {\n if (\n e instanceof Error &&\n e.name === \"ReplicationConfigurationNotFoundError\"\n ) {\n findings.push(\n makeFinding({\n riskScore: 3.5,\n title: `S3 bucket ${name} has no cross-region replication`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region,\n description: `Bucket \"${name}\" does not have cross-region replication configured.`,\n impact:\n \"Data is stored in a single region. A regional outage could make the data unavailable.\",\n remediationSteps: [\n \"Enable cross-region replication to a bucket in another region.\",\n \"Ensure versioning is enabled (required for CRR).\",\n \"Consider S3 Replication Time Control for critical data.\",\n ],\n }),\n );\n } else {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Bucket ${name} replication check failed: ${msg}`);\n }\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n SecurityHubClient,\n GetFindingsCommand,\n} from \"@aws-sdk/client-securityhub\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction shSeverityToScore(label: string): number | null {\n switch (label) {\n case \"CRITICAL\": return 9.5;\n case \"HIGH\": return 8.0;\n case \"MEDIUM\": return 5.5;\n case \"LOW\": return 3.0;\n case \"INFORMATIONAL\": return null; // skip\n default: return null;\n }\n}\n\nexport class SecurityHubFindingsScanner implements Scanner {\n readonly moduleName = \"security_hub_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(SecurityHubClient, region, ctx.credentials);\n let nextToken: string | undefined;\n\n do {\n const resp = await client.send(\n new GetFindingsCommand({\n Filters: {\n WorkflowStatus: [\n { Value: \"NEW\", Comparison: \"EQUALS\" },\n { Value: \"NOTIFIED\", Comparison: \"EQUALS\" },\n ],\n RecordState: [{ Value: \"ACTIVE\", Comparison: \"EQUALS\" }],\n },\n MaxResults: 100,\n NextToken: nextToken,\n }),\n );\n\n const shFindings = resp.Findings ?? [];\n resourcesScanned += shFindings.length;\n\n for (const f of shFindings) {\n const severityLabel = f.Severity?.Label ?? \"INFORMATIONAL\";\n const score = shSeverityToScore(severityLabel);\n if (score === null) continue; // skip INFORMATIONAL\n\n const severity = severityFromScore(score);\n const resourceId = f.Resources?.[0]?.Id ?? \"unknown\";\n const resourceType = f.Resources?.[0]?.Type ?? \"AWS::Unknown\";\n const resourceArn = resourceId.startsWith(\"arn:\")\n ? resourceId\n : `arn:${partition}:securityhub:${region}:${accountId}:finding/${f.Id ?? \"unknown\"}`;\n\n const remediationSteps: string[] = [];\n if (f.Remediation?.Recommendation?.Text) {\n remediationSteps.push(f.Remediation.Recommendation.Text);\n }\n if (f.Remediation?.Recommendation?.Url) {\n remediationSteps.push(`Reference: ${f.Remediation.Recommendation.Url}`);\n }\n if (remediationSteps.length === 0) {\n remediationSteps.push(\"Review the finding in the AWS Security Hub console and follow the recommended remediation.\");\n }\n\n findings.push({\n severity,\n title: f.Title ?? \"Security Hub Finding\",\n resourceType,\n resourceId,\n resourceArn,\n region: f.Region ?? region,\n description: f.Description ?? f.Title ?? \"No description\",\n impact: `Source: ${f.ProductName ?? \"Security Hub\"} (${f.GeneratorId ?? \"unknown\"})`,\n riskScore: score,\n remediationSteps,\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId: f.AwsAccountId ?? accountId,\n });\n }\n\n nextToken = resp.NextToken;\n } while (nextToken);\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isNotEnabled =\n (err instanceof Error && err.name === \"InvalidAccessException\") ||\n msg.includes(\"not subscribed\") ||\n msg.includes(\"not enabled\");\n\n if (isNotEnabled) {\n warnings.push(\"Security Hub is not enabled in this region. Enable it to aggregate security findings.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Security Hub findings scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n GuardDutyClient,\n ListDetectorsCommand,\n ListFindingsCommand,\n GetFindingsCommand,\n} from \"@aws-sdk/client-guardduty\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction gdSeverityToScore(severity: number): number {\n if (severity >= 7.0) return 8.0; // HIGH\n if (severity >= 4.0) return 5.5; // MEDIUM\n return 3.0; // LOW\n}\n\nexport class GuardDutyFindingsScanner implements Scanner {\n readonly moduleName = \"guardduty_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(GuardDutyClient, region, ctx.credentials);\n\n // Step 1: Get detector ID\n const detectorsResp = await client.send(new ListDetectorsCommand({}));\n const detectorIds = detectorsResp.DetectorIds ?? [];\n\n if (detectorIds.length === 0) {\n warnings.push(\"GuardDuty is not enabled in this region (no detectors found).\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n const detectorId = detectorIds[0];\n\n // Step 2: List finding IDs (not archived)\n let nextToken: string | undefined;\n const findingIds: string[] = [];\n\n do {\n const listResp = await client.send(\n new ListFindingsCommand({\n DetectorId: detectorId,\n FindingCriteria: {\n Criterion: {\n \"service.archived\": {\n Eq: [\"false\"],\n },\n },\n },\n MaxResults: 50,\n NextToken: nextToken,\n }),\n );\n findingIds.push(...(listResp.FindingIds ?? []));\n nextToken = listResp.NextToken;\n } while (nextToken);\n\n resourcesScanned = findingIds.length;\n\n if (findingIds.length === 0) {\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n // Step 3: Get finding details (batch of 50)\n for (let i = 0; i < findingIds.length; i += 50) {\n const batch = findingIds.slice(i, i + 50);\n const detailsResp = await client.send(\n new GetFindingsCommand({\n DetectorId: detectorId,\n FindingIds: batch,\n }),\n );\n\n for (const gdf of detailsResp.Findings ?? []) {\n const gdSeverity = gdf.Severity ?? 0;\n const score = gdSeverityToScore(gdSeverity);\n const severity = severityFromScore(score);\n\n const resourceType = gdf.Resource?.ResourceType ?? \"AWS::Unknown\";\n const resourceId = gdf.Resource?.InstanceDetails?.InstanceId\n ?? gdf.Resource?.AccessKeyDetails?.AccessKeyId\n ?? gdf.Arn\n ?? \"unknown\";\n const resourceArn = gdf.Arn\n ?? `arn:${partition}:guardduty:${region}:${accountId}:detector/${detectorId}/finding/${gdf.Id ?? \"unknown\"}`;\n\n findings.push({\n severity,\n title: `[GuardDuty] ${gdf.Title ?? gdf.Type ?? \"Finding\"}`,\n resourceType,\n resourceId,\n resourceArn,\n region: gdf.Region ?? region,\n description: gdf.Description ?? gdf.Title ?? \"No description\",\n impact: `GuardDuty threat type: ${gdf.Type ?? \"unknown\"} (severity ${gdSeverity})`,\n riskScore: score,\n remediationSteps: [\n \"Review the finding in the Amazon GuardDuty console.\",\n `Finding type: ${gdf.Type ?? \"unknown\"}`,\n \"Follow the recommended remediation in the GuardDuty documentation.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId: gdf.AccountId ?? accountId,\n });\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n module: this.moduleName,\n status: \"error\",\n error: `GuardDuty findings scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n Inspector2Client,\n ListFindingsCommand,\n type FilterCriteria,\n} from \"@aws-sdk/client-inspector2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction inspectorSeverityToScore(label: string): number | null {\n switch (label) {\n case \"CRITICAL\": return 9.5;\n case \"HIGH\": return 8.0;\n case \"MEDIUM\": return 5.5;\n case \"LOW\": return 3.0;\n case \"INFORMATIONAL\": return null;\n case \"UNTRIAGED\": return 5.5;\n default: return null;\n }\n}\n\nexport class InspectorFindingsScanner implements Scanner {\n readonly moduleName = \"inspector_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(Inspector2Client, region, ctx.credentials);\n let nextToken: string | undefined;\n\n const filterCriteria: FilterCriteria = {\n findingStatus: [{ comparison: \"EQUALS\", value: \"ACTIVE\" }],\n };\n\n do {\n const resp = await client.send(\n new ListFindingsCommand({\n filterCriteria,\n maxResults: 100,\n nextToken,\n }),\n );\n\n const inspFindings = resp.findings ?? [];\n resourcesScanned += inspFindings.length;\n\n for (const f of inspFindings) {\n const severityLabel = f.severity ?? \"INFORMATIONAL\";\n const score = inspectorSeverityToScore(severityLabel);\n if (score === null) continue;\n\n const severity = severityFromScore(score);\n\n // Build title with CVE if available\n const cveId = f.packageVulnerabilityDetails?.vulnerabilityId;\n const titleBase = f.title ?? \"Inspector Finding\";\n const title = cveId ? `[${cveId}] ${titleBase}` : titleBase;\n\n const resourceId = f.resources?.[0]?.id ?? \"unknown\";\n const resourceType = f.resources?.[0]?.type ?? \"AWS::Unknown\";\n const resourceArn = resourceId.startsWith(\"arn:\")\n ? resourceId\n : `arn:${partition}:inspector2:${region}:${accountId}:finding/${f.findingArn ?? \"unknown\"}`;\n\n const remediationSteps: string[] = [];\n if (f.remediation?.recommendation?.text) {\n remediationSteps.push(f.remediation.recommendation.text);\n }\n if (f.remediation?.recommendation?.Url) {\n remediationSteps.push(`Reference: ${f.remediation.recommendation.Url}`);\n }\n if (f.packageVulnerabilityDetails?.referenceUrls?.length) {\n remediationSteps.push(`CVE references: ${f.packageVulnerabilityDetails.referenceUrls.slice(0, 3).join(\", \")}`);\n }\n if (remediationSteps.length === 0) {\n remediationSteps.push(\"Review the finding in the Amazon Inspector console and apply the recommended patch or update.\");\n }\n\n const description = f.description ?? titleBase;\n const impact = cveId\n ? `Vulnerability ${cveId} — CVSS: ${f.packageVulnerabilityDetails?.cvss?.[0]?.baseScore ?? \"N/A\"}`\n : `Inspector finding type: ${f.type ?? \"unknown\"}`;\n\n findings.push({\n severity,\n title,\n resourceType,\n resourceId,\n resourceArn,\n region,\n description,\n impact,\n riskScore: score,\n remediationSteps,\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId: f.awsAccountId ?? accountId,\n });\n }\n\n nextToken = resp.nextToken;\n } while (nextToken);\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const errName = err instanceof Error ? err.name : \"\";\n\n const isAccessDenied = errName === \"AccessDeniedException\" || msg.includes(\"AccessDeniedException\");\n const isNotEnabled = msg.includes(\"not enabled\") || msg.includes(\"not subscribed\");\n\n if (isAccessDenied) {\n warnings.push(\"Insufficient permissions to access Inspector. Grant inspector2:ListFindings to scan for vulnerabilities.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n if (isNotEnabled) {\n warnings.push(\"Inspector is not enabled in this region. Enable it to scan for software vulnerabilities.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Inspector findings scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n SupportClient,\n DescribeTrustedAdvisorChecksCommand,\n DescribeTrustedAdvisorCheckResultCommand,\n} from \"@aws-sdk/client-support\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction taStatusToScore(status: string): number | null {\n switch (status) {\n case \"error\": return 8.0; // RED = action required\n case \"warning\": return 5.5; // YELLOW = investigation recommended\n case \"ok\": return null; // GREEN = no issue\n case \"not_available\": return null;\n default: return null;\n }\n}\n\nexport class TrustedAdvisorFindingsScanner implements Scanner {\n readonly moduleName = \"trusted_advisor_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n // Trusted Advisor API endpoint: cn-north-1 for China, us-east-1 for standard\n const supportRegion = region.startsWith(\"cn-\") ? \"cn-north-1\" : \"us-east-1\";\n const clientConfig: any = { region: supportRegion };\n if (ctx.credentials) clientConfig.credentials = ctx.credentials;\n const client = new SupportClient(clientConfig);\n\n // Step 1: List security checks\n const checksResp = await client.send(\n new DescribeTrustedAdvisorChecksCommand({ language: \"en\" }),\n );\n const allChecks = checksResp.checks ?? [];\n const securityChecks = allChecks.filter((c) => c.category === \"security\");\n\n if (securityChecks.length === 0) {\n warnings.push(\"No Trusted Advisor security checks found.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n // Step 2: Get results for each security check\n for (const check of securityChecks) {\n if (!check.id) continue;\n\n try {\n const resultResp = await client.send(\n new DescribeTrustedAdvisorCheckResultCommand({\n checkId: check.id,\n }),\n );\n\n const result = resultResp.result;\n if (!result) continue;\n\n const status = result.status ?? \"not_available\";\n const score = taStatusToScore(status);\n\n resourcesScanned++;\n\n if (score === null) continue; // ok or not_available — skip\n\n // Map flagged resources to findings\n const flaggedResources = result.flaggedResources ?? [];\n\n if (flaggedResources.length === 0) {\n // Check-level finding without specific resources\n const severity = severityFromScore(score);\n findings.push({\n severity,\n title: `[Trusted Advisor] ${check.name ?? \"Security Check\"}`,\n resourceType: \"AWS::TrustedAdvisor::Check\",\n resourceId: check.id,\n resourceArn: `arn:${partition}:trustedadvisor:${region}:${accountId}:check/${check.id}`,\n region,\n description: check.description ?? check.name ?? \"Security check flagged\",\n impact: `Trusted Advisor status: ${status}`,\n riskScore: score,\n remediationSteps: [\n \"Review this Trusted Advisor check in the AWS console.\",\n \"Follow the recommended actions to resolve the flagged issue.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n continue;\n }\n\n // Create findings for flagged resources (limit to first 25 per check)\n const metadata = check.metadata ?? [];\n for (const fr of flaggedResources.slice(0, 25)) {\n if (fr.isSuppressed) continue;\n\n const severity = severityFromScore(score);\n const resourceMeta = fr.metadata ?? [];\n\n // Try to extract resource ID from metadata\n const resourceIdIdx = metadata.indexOf(\"Resource ID\");\n const regionIdx = metadata.indexOf(\"Region\");\n const flaggedResourceId = resourceIdIdx >= 0 && resourceMeta[resourceIdIdx]\n ? resourceMeta[resourceIdIdx]\n : fr.resourceId ?? \"unknown\";\n const flaggedRegion = regionIdx >= 0 && resourceMeta[regionIdx]\n ? resourceMeta[regionIdx]\n : region;\n\n findings.push({\n severity,\n title: `[Trusted Advisor] ${check.name ?? \"Security Check\"}: ${flaggedResourceId}`,\n resourceType: \"AWS::TrustedAdvisor::FlaggedResource\",\n resourceId: flaggedResourceId,\n resourceArn: `arn:${partition}:trustedadvisor:${flaggedRegion}:${accountId}:check/${check.id}/${fr.resourceId ?? \"unknown\"}`,\n region: flaggedRegion,\n description: `${check.name}: ${resourceMeta.join(\" | \")}`,\n impact: `Trusted Advisor status: ${status} — ${check.name ?? \"security check\"}`,\n riskScore: score,\n remediationSteps: [\n `Review Trusted Advisor check: ${check.name}`,\n \"Follow the recommended actions in the AWS Trusted Advisor console.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n }\n } catch (checkErr) {\n const checkMsg = checkErr instanceof Error ? checkErr.message : String(checkErr);\n warnings.push(`Trusted Advisor check ${check.name ?? check.id} failed: ${checkMsg}`);\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isSubscriptionRequired =\n msg.includes(\"SubscriptionRequiredException\") ||\n msg.includes(\"subscription\") ||\n msg.includes(\"AWS Premium Support\") ||\n (err instanceof Error && err.name === \"SubscriptionRequiredException\");\n\n if (isSubscriptionRequired) {\n warnings.push(\"Trusted Advisor requires AWS Business or Enterprise Support plan. Skipping.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Trusted Advisor scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n ConfigServiceClient,\n DescribeComplianceByConfigRuleCommand,\n GetComplianceDetailsByConfigRuleCommand,\n type ComplianceByConfigRule,\n} from \"@aws-sdk/client-config-service\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\n/** Security-related Config rule name patterns that warrant HIGH severity */\nconst SECURITY_RULE_PATTERNS = [\n \"securitygroup\", \"security-group\",\n \"encryption\", \"encrypted\",\n \"public\", \"unrestricted\",\n \"mfa\", \"password\", \"access-key\",\n \"root\", \"admin\",\n \"logging\", \"cloudtrail\",\n \"iam\", \"kms\", \"ssl\", \"tls\",\n \"vpc-flow\", \"guardduty\", \"securityhub\",\n];\n\nfunction ruleIsSecurityRelated(ruleName: string): boolean {\n const lower = ruleName.toLowerCase();\n return SECURITY_RULE_PATTERNS.some((pat) => lower.includes(pat));\n}\n\nexport class ConfigRulesFindingsScanner implements Scanner {\n readonly moduleName = \"config_rules_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(ConfigServiceClient, region, ctx.credentials);\n\n // Step 1: Get all rules and their compliance status\n let nextToken: string | undefined;\n const nonCompliantRules: ComplianceByConfigRule[] = [];\n\n do {\n const resp = await client.send(\n new DescribeComplianceByConfigRuleCommand({ NextToken: nextToken }),\n );\n\n for (const rule of resp.ComplianceByConfigRules ?? []) {\n resourcesScanned++;\n if (rule.Compliance?.ComplianceType === \"NON_COMPLIANT\") {\n nonCompliantRules.push(rule);\n }\n }\n\n nextToken = resp.NextToken;\n } while (nextToken);\n\n if (resourcesScanned === 0) {\n warnings.push(\"AWS Config is not enabled in this region or no Config Rules are defined.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n // Step 2: For each non-compliant rule, get the non-compliant resources\n for (const rule of nonCompliantRules) {\n const ruleName = rule.ConfigRuleName ?? \"unknown\";\n\n try {\n let detailToken: string | undefined;\n do {\n const detailResp = await client.send(\n new GetComplianceDetailsByConfigRuleCommand({\n ConfigRuleName: ruleName,\n ComplianceTypes: [\"NON_COMPLIANT\"],\n NextToken: detailToken,\n }),\n );\n\n for (const evalResult of detailResp.EvaluationResults ?? []) {\n const qualifier = evalResult.EvaluationResultIdentifier?.EvaluationResultQualifier;\n const resourceType = qualifier?.ResourceType ?? \"AWS::Unknown\";\n const resourceId = qualifier?.ResourceId ?? \"unknown\";\n const annotation = evalResult.Annotation;\n\n const isSecurityRule = ruleIsSecurityRelated(ruleName);\n const riskScore = isSecurityRule ? 7.5 : 5.5;\n const severity = severityFromScore(riskScore);\n\n const descParts = [`Config Rule: ${ruleName}`, `Resource Type: ${resourceType}`];\n if (annotation) descParts.push(`Annotation: ${annotation}`);\n\n findings.push({\n severity,\n title: `Config Rule: ${ruleName} - ${resourceType}/${resourceId} Non-Compliant`,\n resourceType,\n resourceId,\n resourceArn: resourceId,\n region,\n description: descParts.join(\". \"),\n impact: `Resource is non-compliant with Config Rule: ${ruleName}`,\n riskScore,\n remediationSteps: [\n `Review the Config Rule \"${ruleName}\" in the AWS Config console.`,\n `Check resource ${resourceId} for compliance violations.`,\n \"Follow the rule's remediation guidance to bring the resource into compliance.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n }\n\n detailToken = detailResp.NextToken;\n } while (detailToken);\n } catch (detailErr) {\n const msg = detailErr instanceof Error ? detailErr.message : String(detailErr);\n warnings.push(`Failed to get details for rule ${ruleName}: ${msg}`);\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n\n // Config not enabled is a common case — return success with warning\n if (\n msg.includes(\"NoSuchConfigurationRecorder\") ||\n msg.includes(\"InsufficientDeliveryPolicy\") ||\n msg.includes(\"No Configuration Recorder\")\n ) {\n warnings.push(\"AWS Config is not enabled in this region.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Config Rules scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n AccessAnalyzerClient,\n ListAnalyzersCommand,\n ListFindingsV2Command,\n type AnalyzerSummary,\n type FindingSummaryV2,\n} from \"@aws-sdk/client-accessanalyzer\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\n/** Maps Access Analyzer findingType to a risk score. */\nfunction findingTypeToScore(findingType: string | undefined): number {\n const ft = findingType as string | undefined;\n switch (ft) {\n case \"ExternalAccess\": return 8.0;\n case \"UnusedIAMRole\":\n case \"UnusedIAMUserAccessKey\":\n case \"UnusedIAMUserPassword\": return 5.5;\n case \"UnusedPermission\": return 3.0;\n default: return 5.5;\n }\n}\n\nconst UNUSED_FINDING_TYPES = new Set([\n \"UnusedIAMRole\",\n \"UnusedIAMUserAccessKey\",\n \"UnusedIAMUserPassword\",\n \"UnusedPermission\",\n]);\n\nfunction isSecurityRelevant(findingType: string | undefined): boolean {\n const ft = findingType as string | undefined;\n return ft === \"ExternalAccess\" || UNUSED_FINDING_TYPES.has(ft ?? \"\");\n}\n\nfunction isExternalAccess(findingType: string | undefined): boolean {\n return (findingType as string | undefined) === \"ExternalAccess\";\n}\n\nexport class AccessAnalyzerFindingsScanner implements Scanner {\n readonly moduleName = \"access_analyzer_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(AccessAnalyzerClient, region, ctx.credentials);\n\n // Step 1: List active analyzers\n let analyzerToken: string | undefined;\n const analyzers: AnalyzerSummary[] = [];\n\n do {\n const resp = await client.send(\n new ListAnalyzersCommand({ nextToken: analyzerToken }),\n );\n for (const analyzer of resp.analyzers ?? []) {\n if (analyzer.status === \"ACTIVE\") {\n analyzers.push(analyzer);\n }\n }\n analyzerToken = resp.nextToken;\n } while (analyzerToken);\n\n if (analyzers.length === 0) {\n warnings.push(\"No IAM Access Analyzer found. Create an analyzer to detect external access to your resources.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n // Step 2: For each active analyzer, list ACTIVE findings\n for (const analyzer of analyzers) {\n const analyzerArn = analyzer.arn ?? \"unknown\";\n\n let findingToken: string | undefined;\n do {\n const listResp = await client.send(\n new ListFindingsV2Command({\n analyzerArn,\n filter: {\n status: { eq: [\"ACTIVE\"] },\n },\n nextToken: findingToken,\n }),\n );\n\n for (const aaf of listResp.findings ?? []) {\n // Only include security-relevant finding types\n if (!isSecurityRelevant(aaf.findingType)) {\n continue;\n }\n\n resourcesScanned++;\n const score = findingTypeToScore(aaf.findingType);\n const severity = severityFromScore(score);\n\n const resourceArn = aaf.resource ?? \"unknown\";\n const resourceType = aaf.resourceType ?? \"AWS::Unknown\";\n const resourceId = resourceArn.split(\"/\").pop() ?? resourceArn.split(\":\").pop() ?? \"unknown\";\n const external = isExternalAccess(aaf.findingType);\n\n const descParts = [`Resource Type: ${resourceType}`];\n if (aaf.resourceOwnerAccount) descParts.push(`Owner Account: ${aaf.resourceOwnerAccount}`);\n if (aaf.findingType) descParts.push(`Finding Type: ${aaf.findingType}`);\n\n const title = buildFindingTitle(aaf);\n\n const impact = external\n ? `Resource is accessible from outside the account. Type: ${aaf.findingType ?? \"unknown\"}`\n : `Unused access detected — review and remove to follow least-privilege. Type: ${aaf.findingType ?? \"unknown\"}`;\n\n const remediationSteps = external\n ? [\n \"Review the finding in the IAM Access Analyzer console.\",\n `Check resource ${resourceId} for unintended external access.`,\n \"Remove or restrict the resource policy to eliminate external access.\",\n ]\n : [\n \"Review the finding in the IAM Access Analyzer console.\",\n `Check resource ${resourceId} for unused access permissions.`,\n \"Remove unused permissions, roles, or credentials to follow least-privilege.\",\n ];\n\n findings.push({\n severity,\n title,\n resourceType: mapResourceType(resourceType),\n resourceId,\n resourceArn,\n region,\n description: descParts.join(\". \"),\n impact,\n riskScore: score,\n remediationSteps,\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId: aaf.resourceOwnerAccount ?? accountId,\n });\n }\n\n findingToken = listResp.nextToken;\n } while (findingToken);\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Access Analyzer scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n\nfunction buildFindingTitle(finding: FindingSummaryV2): string {\n const resourceType = finding.resourceType ?? \"Resource\";\n const resource = finding.resource\n ? (finding.resource.split(\"/\").pop() ?? finding.resource.split(\":\").pop() ?? finding.resource)\n : \"unknown\";\n const label = isExternalAccess(finding.findingType)\n ? \"external access detected\"\n : \"unused access detected\";\n return `[Access Analyzer] ${resourceType} ${resource} — ${label}`;\n}\n\nfunction mapResourceType(aaType: string): string {\n const mapping: Record<string, string> = {\n \"AWS::S3::Bucket\": \"AWS::S3::Bucket\",\n \"AWS::IAM::Role\": \"AWS::IAM::Role\",\n \"AWS::SQS::Queue\": \"AWS::SQS::Queue\",\n \"AWS::Lambda::Function\": \"AWS::Lambda::Function\",\n \"AWS::Lambda::LayerVersion\": \"AWS::Lambda::LayerVersion\",\n \"AWS::KMS::Key\": \"AWS::KMS::Key\",\n \"AWS::SecretsManager::Secret\": \"AWS::SecretsManager::Secret\",\n \"AWS::SNS::Topic\": \"AWS::SNS::Topic\",\n \"AWS::EFS::FileSystem\": \"AWS::EFS::FileSystem\",\n \"AWS::RDS::DBSnapshot\": \"AWS::RDS::DBSnapshot\",\n \"AWS::RDS::DBClusterSnapshot\": \"AWS::RDS::DBClusterSnapshot\",\n \"AWS::ECR::Repository\": \"AWS::ECR::Repository\",\n };\n return mapping[aaType] ?? aaType;\n}\n","import {\n SSMClient,\n DescribeInstanceInformationCommand,\n DescribeInstancePatchStatesCommand,\n type InstanceInformation,\n type InstancePatchState,\n} from \"@aws-sdk/client-ssm\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nexport class PatchComplianceFindingsScanner implements Scanner {\n readonly moduleName = \"patch_compliance_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(SSMClient, region, ctx.credentials);\n\n // Step 1: Get all managed instances\n let nextToken: string | undefined;\n const instances: InstanceInformation[] = [];\n\n do {\n const resp = await client.send(\n new DescribeInstanceInformationCommand({\n MaxResults: 50,\n NextToken: nextToken,\n }),\n );\n instances.push(...(resp.InstanceInformationList ?? []));\n nextToken = resp.NextToken;\n } while (nextToken);\n\n if (instances.length === 0) {\n warnings.push(\"No SSM-managed instances found in this region.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n resourcesScanned = instances.length;\n\n // Step 2: Get patch states in batches\n const instanceIds = instances.map((i) => i.InstanceId).filter(Boolean) as string[];\n const patchStateMap = new Map<string, InstancePatchState>();\n\n // DescribeInstancePatchStates supports up to 50 instances per call\n for (let i = 0; i < instanceIds.length; i += 50) {\n const batch = instanceIds.slice(i, i + 50);\n let patchToken: string | undefined;\n\n do {\n const patchResp = await client.send(\n new DescribeInstancePatchStatesCommand({\n InstanceIds: batch,\n NextToken: patchToken,\n }),\n );\n\n for (const ps of patchResp.InstancePatchStates ?? []) {\n if (ps.InstanceId) {\n patchStateMap.set(ps.InstanceId, ps);\n }\n }\n\n patchToken = patchResp.NextToken;\n } while (patchToken);\n }\n\n // Step 3: Generate findings for instances with missing/failed patches\n for (const instance of instances) {\n const instanceId = instance.InstanceId ?? \"unknown\";\n const platform = instance.PlatformName ?? instance.PlatformType ?? \"unknown\";\n const instanceArn = `arn:${partition}:ec2:${region}:${accountId}:instance/${instanceId}`;\n\n const patchState = patchStateMap.get(instanceId);\n\n if (!patchState) {\n // Instance not managed for patching — INFO-level finding\n const riskScore = 3.0;\n const severity = severityFromScore(riskScore);\n findings.push({\n severity,\n title: `Instance ${instanceId} has no patch compliance data`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instanceId,\n resourceArn: instanceArn,\n region,\n description: `Instance ${instanceId} (${platform}) is managed by SSM but has no patch compliance data. Patch Manager may not be configured for this instance.`,\n impact: \"Patch compliance status is unknown — vulnerabilities may exist.\",\n riskScore,\n remediationSteps: [\n \"Configure AWS Systems Manager Patch Manager for this instance.\",\n \"Create a patch baseline and maintenance window.\",\n \"Run a patch scan to establish compliance status.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n continue;\n }\n\n const missingCount = patchState.MissingCount ?? 0;\n const failedCount = patchState.FailedCount ?? 0;\n const criticalNonCompliantCount = patchState.CriticalNonCompliantCount ?? 0;\n const securityNonCompliantCount = patchState.SecurityNonCompliantCount ?? 0;\n const otherNonCompliantCount = patchState.OtherNonCompliantCount ?? 0;\n const lastScanTime = patchState.OperationEndTime?.toISOString() ?? \"unknown\";\n\n if (\n missingCount === 0 &&\n failedCount === 0 &&\n criticalNonCompliantCount === 0 &&\n securityNonCompliantCount === 0 &&\n otherNonCompliantCount === 0\n ) {\n continue; // Instance is fully patched\n }\n\n // Determine severity based on patch issues\n let riskScore: number;\n if (criticalNonCompliantCount > 0 || securityNonCompliantCount > 0 || failedCount > 0) {\n riskScore = 7.5; // HIGH — critical/security patches missing or failed\n } else if (otherNonCompliantCount > 0) {\n riskScore = 5.5; // MEDIUM — other non-compliant patches\n } else {\n riskScore = 5.5; // MEDIUM — non-security patches missing\n }\n const severity = severityFromScore(riskScore);\n\n const titleParts: string[] = [];\n if (missingCount > 0) titleParts.push(`${missingCount} missing`);\n if (failedCount > 0) titleParts.push(`${failedCount} failed`);\n if (criticalNonCompliantCount > 0) titleParts.push(`${criticalNonCompliantCount} critical non-compliant`);\n if (securityNonCompliantCount > 0) titleParts.push(`${securityNonCompliantCount} security non-compliant`);\n if (otherNonCompliantCount > 0) titleParts.push(`${otherNonCompliantCount} other non-compliant`);\n\n const descParts = [\n `Instance: ${instanceId}`,\n `Platform: ${platform}`,\n `Missing patches: ${missingCount}`,\n `Failed patches: ${failedCount}`,\n `Critical non-compliant: ${criticalNonCompliantCount}`,\n `Security non-compliant: ${securityNonCompliantCount}`,\n `Other non-compliant: ${otherNonCompliantCount}`,\n `Last scan: ${lastScanTime}`,\n ];\n\n findings.push({\n severity,\n title: `Instance ${instanceId} has ${titleParts.join(\", \")} patches`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instanceId,\n resourceArn: instanceArn,\n region,\n description: descParts.join(\". \"),\n impact: `Instance has ${missingCount} missing and ${failedCount} failed patches — potential security vulnerabilities.`,\n riskScore,\n remediationSteps: [\n `Review patch compliance for instance ${instanceId} in the Systems Manager console.`,\n \"Apply missing patches using a maintenance window or manual patching.\",\n \"Investigate and resolve any failed patch installations.\",\n \"Consider enabling automatic patching through Patch Manager.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Patch compliance scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import type { FullScanResult, Finding, Severity } from \"../types.js\";\n\nconst SEVERITY_ICON: Record<Severity, string> = {\n CRITICAL: \"🔴\",\n HIGH: \"🟠\",\n MEDIUM: \"🟡\",\n LOW: \"🟢\",\n};\n\nconst SEVERITY_ORDER: Severity[] = [\"CRITICAL\", \"HIGH\", \"MEDIUM\", \"LOW\"];\n\nfunction formatDuration(start: string, end: string): string {\n const ms = new Date(end).getTime() - new Date(start).getTime();\n if (ms < 1000) return `${ms}ms`;\n const secs = Math.round(ms / 1000);\n if (secs < 60) return `${secs}s`;\n const mins = Math.floor(secs / 60);\n const remainSecs = secs % 60;\n return `${mins}m ${remainSecs}s`;\n}\n\nfunction renderFinding(f: Finding): string {\n const steps = f.remediationSteps\n .map((s, i) => ` ${i + 1}. ${s}`)\n .join(\"\\n\");\n\n return [\n `#### ${f.title}`,\n `- **Resource:** ${f.resourceId} (\\`${f.resourceArn}\\`)`,\n `- **Description:** ${f.description}`,\n `- **Impact:** ${f.impact}`,\n `- **Risk Score:** ${f.riskScore}/10`,\n `- **Remediation:**`,\n steps,\n `- **Priority:** ${f.priority}`,\n ].join(\"\\n\");\n}\n\nexport function generateMarkdownReport(scanResults: FullScanResult): string {\n const { summary, modules, accountId, region, scanStart, scanEnd } =\n scanResults;\n const date = scanStart.split(\"T\")[0];\n const duration = formatDuration(scanStart, scanEnd);\n\n const lines: string[] = [];\n\n lines.push(`# AWS Security Scan Report — ${date}`);\n lines.push(\"\");\n\n // Executive Summary\n lines.push(\"## Executive Summary\");\n lines.push(`- **Account:** ${accountId}`);\n lines.push(`- **Region:** ${region}`);\n lines.push(`- **Scan Duration:** ${duration}`);\n lines.push(\n `- **Total Findings:** ${summary.totalFindings} (🔴 ${summary.critical} Critical | 🟠 ${summary.high} High | 🟡 ${summary.medium} Medium | 🟢 ${summary.low} Low)`,\n );\n lines.push(\"\");\n\n // Edge case: no findings\n if (summary.totalFindings === 0) {\n lines.push(\"## Findings by Severity\");\n lines.push(\"\");\n lines.push(\"✅ No security issues found.\");\n lines.push(\"\");\n } else {\n // Collect all findings\n const allFindings: Finding[] = modules.flatMap((m) => m.findings);\n\n // Group by severity\n const grouped = new Map<Severity, Finding[]>();\n for (const sev of SEVERITY_ORDER) {\n grouped.set(sev, []);\n }\n for (const f of allFindings) {\n grouped.get(f.severity)!.push(f);\n }\n\n lines.push(\"## Findings by Severity\");\n lines.push(\"\");\n\n for (const sev of SEVERITY_ORDER) {\n const findings = grouped.get(sev)!;\n const icon = SEVERITY_ICON[sev];\n lines.push(`### ${icon} ${sev.charAt(0)}${sev.slice(1).toLowerCase()}`);\n lines.push(\"\");\n\n if (findings.length === 0) {\n lines.push(`No ${sev.toLowerCase()} findings.`);\n lines.push(\"\");\n continue;\n }\n\n // Sort by riskScore descending\n findings.sort((a, b) => b.riskScore - a.riskScore);\n for (const f of findings) {\n lines.push(renderFinding(f));\n lines.push(\"\");\n }\n }\n }\n\n // Scan Statistics\n lines.push(\"## Scan Statistics\");\n lines.push(\n \"| Module | Resources Scanned | Findings | Status |\",\n );\n lines.push(\"|--------|------------------|----------|--------|\");\n for (const m of modules) {\n const status = m.status === \"success\" ? \"✅\" : \"❌\";\n lines.push(\n `| ${m.module} | ${m.resourcesScanned} | ${m.findingsCount} | ${status} |`,\n );\n }\n lines.push(\"\");\n\n // Recommendations\n if (summary.totalFindings > 0) {\n const allFindings: Finding[] = modules.flatMap((m) => m.findings);\n allFindings.sort((a, b) => b.riskScore - a.riskScore);\n\n lines.push(\"## Recommendations (Priority Order)\");\n for (let i = 0; i < allFindings.length; i++) {\n const f = allFindings[i];\n lines.push(`${i + 1}. [${f.priority}] ${f.title}: ${f.remediationSteps[0] ?? \"Review and remediate.\"}`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n","import type { FullScanResult, Finding } from \"../types.js\";\n\nexport interface MlpsCheck {\n id: string;\n category: string;\n name: string;\n modules: string[];\n findingPatterns: string[];\n}\n\nexport const MLPS_CHECKS: MlpsCheck[] = [\n // 一、身份鉴别\n {\n id: \"8.1.4.1a\",\n category: \"身份鉴别\",\n name: \"密码策略\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"password policy\", \"password length\", \"complexity\", \"password expiry\", \"reuse prevention\", \"IAM.7\", \"IAM.10\"],\n },\n {\n id: \"8.1.4.1a\",\n category: \"身份鉴别\",\n name: \"密钥轮换\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"access key older\", \"access key rotated\", \"IAM.3\", \"IAM.4\"],\n },\n {\n id: \"8.1.4.1d\",\n category: \"身份鉴别\",\n name: \"双因素认证\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"MFA\", \"IAM.5\", \"IAM.6\"],\n },\n // 二、访问控制\n {\n id: \"8.1.4.2c\",\n category: \"访问控制\",\n name: \"最小权限\",\n modules: [\"iam_privilege_escalation\", \"security_hub_findings\"],\n findingPatterns: [\n \"AdministratorAccess\", \"PowerUserAccess\", \"IAMFullAccess\",\n \"over-permissive\", \"privilege escalation\",\n \"self-grant\", \"iam:*\", \"create admin\", \"Lambda role passing\",\n \"CreateAccessKey\", \"AssumeRole\",\n ],\n },\n {\n id: \"8.1.4.2\",\n category: \"访问控制\",\n name: \"安全组\",\n modules: [\"network_reachability\", \"security_hub_findings\"],\n findingPatterns: [\"allows all ports\", \"allows SSH\", \"allows RDP\", \"MySQL\", \"PostgreSQL\", \"MongoDB\", \"Redis\", \"high-risk port\", \"security group\", \"EC2.18\", \"EC2.19\"],\n },\n // 三、安全审计\n {\n id: \"8.1.4.3a\",\n category: \"安全审计\",\n name: \"审计功能\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"CloudTrail\", \"not enabled\", \"multi-region\", \"not logging\", \"CloudTrail.1\"],\n },\n {\n id: \"8.1.4.3b\",\n category: \"安全审计\",\n name: \"审计完整性\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"log file validation\", \"log integrity\", \"log validation\", \"CloudTrail.4\", \"CloudTrail.5\"],\n },\n {\n id: \"8.1.4.3c\",\n category: \"安全审计\",\n name: \"审计保护\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"CloudTrail\", \"S3 bucket\", \"encryption\", \"versioning\", \"Block Public Access\", \"CloudTrail.6\", \"CloudTrail.7\"],\n },\n // 四、入侵防范\n {\n id: \"8.1.4.4a\",\n category: \"入侵防范\",\n name: \"GuardDuty 威胁检测\",\n modules: [\"service_detection\", \"guardduty_findings\"],\n findingPatterns: [\"GuardDuty\"],\n },\n {\n id: \"8.1.4.4a\",\n category: \"入侵防范\",\n name: \"Inspector 漏洞扫描\",\n modules: [\"service_detection\", \"inspector_findings\"],\n findingPatterns: [\"Inspector\", \"CVE-\"],\n },\n // 五、数据安全\n {\n id: \"8.1.4.5a\",\n category: \"数据安全\",\n name: \"传输加密\",\n modules: [\"ssl_certificate\", \"security_hub_findings\"],\n findingPatterns: [\"HTTPS\", \"TLS\", \"HTTP listener\", \"certificate\", \"ELB.1\"],\n },\n {\n id: \"8.1.4.5b\",\n category: \"数据安全\",\n name: \"S3 存储加密\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"no default encryption\", \"not encrypted\", \"S3.4\"],\n },\n {\n id: \"8.1.4.5b\",\n category: \"数据安全\",\n name: \"EBS 默认加密\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"EBS default encryption\", \"EC2.7\"],\n },\n {\n id: \"8.1.4.5b\",\n category: \"数据安全\",\n name: \"RDS 存储加密\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"storage is not encrypted\", \"RDS.3\"],\n },\n // 六、网络安全\n {\n id: \"8.1.3.1a\",\n category: \"网络安全\",\n name: \"网络架构\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"default VPC\", \"EC2.2\"],\n },\n {\n id: \"8.1.3.2a\",\n category: \"网络安全\",\n name: \"边界防护\",\n modules: [\"network_reachability\", \"security_hub_findings\"],\n findingPatterns: [\"allows all ports\", \"allows SSH\", \"allows RDP\", \"security group\", \"EC2.18\", \"EC2.19\"],\n },\n];\n\nexport const CATEGORY_ORDER = [\n \"身份鉴别\",\n \"访问控制\",\n \"安全审计\",\n \"入侵防范\",\n \"数据安全\",\n \"网络安全\",\n];\n\nexport const CATEGORY_SECTION: Record<string, string> = {\n \"身份鉴别\": \"一、身份鉴别\",\n \"访问控制\": \"二、访问控制\",\n \"安全审计\": \"三、安全审计\",\n \"入侵防范\": \"四、入侵防范\",\n \"数据安全\": \"五、数据安全\",\n \"网络安全\": \"六、网络安全\",\n};\n\nexport interface CheckResult {\n check: MlpsCheck;\n status: \"pass\" | \"fail\" | \"unknown\";\n relatedFindings: Finding[];\n}\n\nexport function evaluateCheck(\n check: MlpsCheck,\n allFindings: Finding[],\n scanModules: Array<{ module: string; status: string }>,\n): CheckResult {\n // Verify all required modules ran successfully\n const allModulesPresent = check.modules.every((mod) =>\n scanModules.some((m) => m.module === mod && m.status === \"success\"),\n );\n\n if (!allModulesPresent) {\n return { check, status: \"unknown\", relatedFindings: [] };\n }\n\n // Find findings from the relevant modules that match any of the patterns\n const relatedFindings = allFindings.filter((f) => {\n const moduleMatch = check.modules.some((mod) => f.module === mod);\n if (!moduleMatch) return false;\n\n const text = `${f.title} ${f.description}`.toLowerCase();\n return check.findingPatterns.some((pattern) =>\n text.includes(pattern.toLowerCase()),\n );\n });\n\n return {\n check,\n status: relatedFindings.length === 0 ? \"pass\" : \"fail\",\n relatedFindings,\n };\n}\n\nexport function generateMlps3Report(scanResults: FullScanResult): string {\n const { accountId, region, scanStart } = scanResults;\n const scanTime = scanStart.replace(\"T\", \" \").replace(/\\.\\d+Z$/, \" UTC\");\n\n // Collect all findings with module info\n const allFindings: Finding[] = scanResults.modules.flatMap((m) =>\n m.findings.map((f) => ({ ...f, module: f.module ?? m.module })),\n );\n\n // Evaluate all checks (pass scan module info for missing-module detection)\n const scanModules = scanResults.modules.map((m) => ({\n module: m.module,\n status: m.status,\n }));\n const results = MLPS_CHECKS.map((check) =>\n evaluateCheck(check, allFindings, scanModules),\n );\n\n const passCount = results.filter((r) => r.status === \"pass\").length;\n const failCount = results.filter((r) => r.status === \"fail\").length;\n const unknownCount = results.filter((r) => r.status === \"unknown\").length;\n const checkedTotal = passCount + failCount;\n const total = results.length;\n const percent = checkedTotal > 0 ? Math.round((passCount / checkedTotal) * 100) : 0;\n\n const lines: string[] = [];\n\n // Header\n lines.push(\"# 等保三级预检报告\");\n lines.push(\"> **本报告为等保预检参考,仅覆盖 AWS 云平台配置检查。完整等保测评需由持证测评机构执行。**\");\n lines.push(\"\");\n\n // Account info\n lines.push(\"## 账户信息\");\n lines.push(`- Account: ${accountId} | Region: ${region} | 扫描时间: ${scanTime}`);\n lines.push(\"\");\n\n // Summary\n lines.push(\"## 预检总览\");\n lines.push(`- 检查项: ${total} | 通过: ${passCount} | 不通过: ${failCount}${unknownCount > 0 ? ` | 未检查: ${unknownCount}` : \"\"}`);\n lines.push(`- 通过率: ${percent}%${unknownCount > 0 ? \"(未检查项不计入通过率)\" : \"\"}`);\n lines.push(\"\");\n\n // Group results by category\n for (const category of CATEGORY_ORDER) {\n const sectionTitle = CATEGORY_SECTION[category];\n const categoryResults = results.filter((r) => r.check.category === category);\n if (categoryResults.length === 0) continue;\n\n lines.push(`## ${sectionTitle}`);\n lines.push(\"\");\n\n // Group by check ID within category\n const byId = new Map<string, CheckResult[]>();\n for (const r of categoryResults) {\n const existing = byId.get(r.check.id) ?? [];\n existing.push(r);\n byId.set(r.check.id, existing);\n }\n\n for (const [checkId, checkResults] of byId) {\n lines.push(`### ${checkId} ${checkResults[0].check.name}`);\n for (const r of checkResults) {\n const icon = r.status === \"pass\" ? \"\\u2705\" : r.status === \"fail\" ? \"\\u274c\" : \"\\u26a0\\ufe0f\";\n const label = r.status === \"unknown\" ? \" 未检查\" : \"\";\n lines.push(`- [${icon}] ${r.check.name}${label}`);\n if (r.status === \"fail\" && r.relatedFindings.length > 0) {\n for (const f of r.relatedFindings.slice(0, 3)) {\n lines.push(` - ${f.severity}: ${f.title}`);\n }\n if (r.relatedFindings.length > 3) {\n lines.push(` - ... 及其他 ${r.relatedFindings.length - 3} 项`);\n }\n }\n }\n lines.push(\"\");\n }\n }\n\n // Remediation recommendations sorted by priority\n const failedResults = results.filter((r) => r.status === \"fail\");\n if (failedResults.length > 0) {\n lines.push(\"## 建议整改项(按优先级)\");\n lines.push(\"\");\n\n // Collect all related findings from failed checks, deduplicate, sort by riskScore\n const allFailedFindings = new Map<string, Finding>();\n for (const r of failedResults) {\n for (const f of r.relatedFindings) {\n const key = `${f.resourceId}:${f.title}`;\n if (!allFailedFindings.has(key)) {\n allFailedFindings.set(key, f);\n }\n }\n }\n\n const sorted = [...allFailedFindings.values()].sort(\n (a, b) => b.riskScore - a.riskScore,\n );\n\n for (let i = 0; i < sorted.length; i++) {\n const f = sorted[i];\n const priority = f.riskScore >= 9.0 ? \"P0\" : f.riskScore >= 7.0 ? \"P1\" : f.riskScore >= 4.0 ? \"P2\" : \"P3\";\n const remediation = f.remediationSteps[0] ?? \"Review and remediate.\";\n lines.push(`${i + 1}. [${priority}] ${f.title} — ${remediation}`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n","import type { FullScanResult, Finding, Severity, DashboardHistoryEntry } from \"../types.js\";\nimport {\n MLPS_CHECKS,\n CATEGORY_ORDER,\n CATEGORY_SECTION,\n evaluateCheck,\n} from \"./mlps-report.js\";\nimport { VERSION } from \"../version.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction esc(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction calcScore(summary: FullScanResult[\"summary\"]): number {\n const raw =\n 100 -\n summary.critical * 15 -\n summary.high * 5 -\n summary.medium * 2 -\n summary.low * 0.5;\n return Math.max(0, Math.min(100, Math.round(raw)));\n}\n\nfunction formatDuration(start: string, end: string): string {\n const ms = new Date(end).getTime() - new Date(start).getTime();\n if (ms < 1000) return `${ms}ms`;\n const secs = Math.round(ms / 1000);\n if (secs < 60) return `${secs}s`;\n return `${Math.floor(secs / 60)}m ${secs % 60}s`;\n}\n\nconst SEV_COLOR: Record<Severity, string> = {\n CRITICAL: \"#ef4444\",\n HIGH: \"#f97316\",\n MEDIUM: \"#eab308\",\n LOW: \"#22c55e\",\n};\n\nconst SEVERITY_ORDER: Severity[] = [\"CRITICAL\", \"HIGH\", \"MEDIUM\", \"LOW\"];\n\nfunction scoreColor(score: number): string {\n if (score >= 80) return \"#22c55e\";\n if (score >= 50) return \"#eab308\";\n return \"#ef4444\";\n}\n\n// ---------------------------------------------------------------------------\n// CSS\n// ---------------------------------------------------------------------------\n\nfunction sharedCss(): string {\n return `\n *{margin:0;padding:0;box-sizing:border-box}\n body{background:#0f172a;color:#f8fafc;font-family:Inter,system-ui,-apple-system,sans-serif;line-height:1.6;font-size:14px}\n .container{max-width:900px;margin:0 auto;padding:40px 24px}\n header{text-align:center;margin-bottom:40px;border-bottom:1px solid #334155;padding-bottom:24px}\n header h1{font-size:28px;font-weight:700;margin-bottom:8px;letter-spacing:-0.5px}\n .meta{color:#94a3b8;font-size:13px}\n .disclaimer{color:#94a3b8;font-size:12px;font-style:italic;margin-top:8px;max-width:640px;margin-left:auto;margin-right:auto}\n h2{font-size:20px;font-weight:600;margin:32px 0 16px;padding-bottom:8px;border-bottom:1px solid #334155}\n h3{font-size:16px;font-weight:600;margin:16px 0 8px}\n h4{font-size:14px;font-weight:600;margin:12px 0 4px}\n .card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:20px;margin-bottom:16px}\n .summary{display:flex;gap:24px;margin-bottom:32px;flex-wrap:wrap}\n .score-card{background:#1e293b;border:1px solid #334155;border-radius:12px;padding:24px 32px;text-align:center;flex:0 0 auto}\n .score-value{font-size:48px;font-weight:700}\n .score-label{color:#94a3b8;font-size:13px;margin-top:4px}\n .severity-stats{display:flex;gap:12px;flex-wrap:wrap;flex:1;align-items:center;justify-content:center}\n .stat-card{border-radius:8px;padding:16px 20px;text-align:center;min-width:100px;border:1px solid #334155;background:#1e293b}\n .stat-count{font-size:28px;font-weight:700}\n .stat-label{font-size:12px;color:#94a3b8;margin-top:2px}\n .stat-critical .stat-count{color:#ef4444}\n .stat-high .stat-count{color:#f97316}\n .stat-medium .stat-count{color:#eab308}\n .stat-low .stat-count{color:#22c55e}\n .charts{display:flex;gap:24px;margin-bottom:32px;flex-wrap:wrap;justify-content:center}\n .chart-box{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:20px;flex:1;min-width:280px}\n .chart-title{font-size:14px;font-weight:600;margin-bottom:12px;text-align:center;color:#cbd5e1}\n .sev-critical{border-left-color:#ef4444}\n .sev-high{border-left-color:#f97316}\n .sev-medium{border-left-color:#eab308}\n .sev-low{border-left-color:#22c55e}\n .badge{display:inline-block;padding:2px 10px;border-radius:4px;font-size:11px;font-weight:700;letter-spacing:0.5px;color:#fff}\n .badge-critical{background:#ef4444}\n .badge-high{background:#f97316}\n .badge-medium{background:#eab308;color:#1e293b}\n .badge-low{background:#22c55e;color:#1e293b}\n .finding-title{font-size:15px;font-weight:600;margin-bottom:8px}\n .finding-detail{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n .finding-detail strong{color:#f8fafc}\n .remediation-steps{margin-top:8px;padding-left:20px}\n .remediation-steps li{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n table{width:100%;border-collapse:collapse;margin-bottom:16px}\n th{background:#334155;color:#f8fafc;padding:10px 12px;text-align:left;font-size:13px;font-weight:600}\n td{padding:8px 12px;border-bottom:1px solid #334155;font-size:13px;color:#cbd5e1}\n tr:hover td{background:rgba(51,65,85,0.3)}\n .recommendations ol{padding-left:24px}\n .recommendations li{margin-bottom:8px;color:#cbd5e1;font-size:13px}\n .priority-p0{color:#ef4444;font-weight:700}\n .priority-p1{color:#f97316;font-weight:700}\n .priority-p2{color:#eab308;font-weight:700}\n .priority-p3{color:#22c55e;font-weight:700}\n footer{margin-top:48px;padding-top:24px;border-top:1px solid #334155;text-align:center}\n footer p{color:#64748b;font-size:12px;margin-bottom:4px}\n .check-item{display:flex;align-items:flex-start;gap:8px;padding:8px 12px;border-radius:6px;margin-bottom:4px;font-size:14px}\n .check-pass{background:rgba(34,197,94,0.1)}\n .check-fail{background:rgba(239,68,68,0.1)}\n .check-unknown{background:rgba(148,163,184,0.1)}\n .check-icon{font-size:16px;flex-shrink:0}\n .check-name{font-weight:500}\n .check-findings{margin-left:28px;margin-top:4px}\n .check-findings li{color:#94a3b8;font-size:12px;margin-bottom:2px;list-style:none}\n .no-findings{text-align:center;padding:40px;color:#22c55e;font-size:18px;font-weight:600}\n .finding-fold{background:#1e293b;border:1px solid #334155;border-radius:8px;margin-bottom:12px;border-left:4px solid;overflow:hidden}\n .finding-fold>summary{cursor:pointer;padding:12px 20px;display:flex;align-items:center;gap:12px;list-style:none;user-select:none}\n .finding-fold>summary::-webkit-details-marker{display:none}\n .finding-fold>summary::marker{content:\"\"}\n .finding-fold>summary .badge{margin-bottom:0}\n .finding-fold>summary::after{content:\"\\\\25B6\";font-size:10px;color:#64748b;flex-shrink:0;transition:transform 0.2s}\n .finding-fold[open]>summary::after{transform:rotate(90deg)}\n .finding-fold[open]>summary{border-bottom:1px solid #334155}\n .finding-body{padding:12px 20px 16px}\n .finding-summary-title{font-weight:600;font-size:14px;flex:1}\n .finding-summary-score{color:#94a3b8;font-size:13px;font-weight:600;white-space:nowrap}\n .top5-card{display:flex;gap:16px;background:#1e293b;border:1px solid #334155;border-radius:12px;padding:24px;margin-bottom:16px;border-left:4px solid}\n .top5-card .badge{margin-bottom:0}\n .top5-rank{font-size:28px;font-weight:800;color:#475569;min-width:44px;display:flex;align-items:flex-start;justify-content:center}\n .top5-content{flex:1}\n .top5-title{font-size:17px;font-weight:700;margin:8px 0}\n .top5-detail{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n .top5-detail strong{color:#f8fafc}\n .top5-remediation{margin-top:8px;padding-left:20px}\n .top5-remediation li{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n .trend-section{margin-bottom:32px}\n .trend-chart{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:20px;margin-bottom:16px}\n .trend-title{font-size:14px;font-weight:600;margin-bottom:12px;text-align:center;color:#cbd5e1}\n .category-fold{background:#1e293b;border:1px solid #334155;border-radius:8px;margin-bottom:16px;overflow:hidden}\n .category-fold>summary{cursor:pointer;padding:16px 20px;display:flex;align-items:center;gap:12px;list-style:none;font-size:18px;font-weight:600;user-select:none}\n .category-fold>summary::-webkit-details-marker{display:none}\n .category-fold>summary::marker{content:\"\"}\n .category-fold>summary::after{content:\"\\\\25B6\";font-size:12px;color:#64748b;flex-shrink:0;transition:transform 0.2s}\n .category-fold[open]>summary::after{transform:rotate(90deg)}\n .category-fold[open]>summary{border-bottom:1px solid #334155}\n .category-body{padding:12px 20px 16px}\n .category-title{flex:1}\n .category-stats{display:inline-flex;gap:12px;font-size:13px}\n .category-stat-pass{color:#22c55e}\n .category-stat-fail{color:#ef4444}\n .category-stat-unknown{color:#94a3b8}\n .module-fold{background:#1e293b;border:1px solid #334155;border-radius:8px;margin-bottom:16px;overflow:hidden}\n .module-fold>summary{cursor:pointer;padding:16px 20px;display:flex;align-items:center;gap:12px;list-style:none;user-select:none;flex-wrap:wrap}\n .module-fold>summary::-webkit-details-marker{display:none}\n .module-fold>summary::marker{content:\"\"}\n .module-fold>summary h3{margin:0;font-size:16px}\n .module-fold>summary::after{content:\"\\\\25B6\";font-size:12px;color:#64748b;flex-shrink:0;transition:transform 0.2s;margin-left:auto}\n .module-fold[open]>summary::after{transform:rotate(90deg)}\n .module-fold[open]>summary{border-bottom:1px solid #334155}\n .module-body{padding:12px 20px 16px}\n .module-badges{display:inline-flex;gap:6px;flex-wrap:wrap}\n .severity-group{margin-bottom:16px}\n .severity-group-fold{margin-bottom:16px}\n .severity-group-fold>summary{cursor:pointer;padding:4px 0;list-style:none;user-select:none}\n .severity-group-fold>summary::-webkit-details-marker{display:none}\n .severity-group-fold>summary::marker{content:\"\"}\n .severity-group-fold>summary h4{margin:0;display:inline}\n .finding-card{display:flex;align-items:center;gap:8px;padding:8px 12px;margin-bottom:4px;border-radius:6px;border-left:4px solid #334155;background:rgba(30,41,59,0.5);flex-wrap:wrap}\n .finding-title-text{font-weight:600;font-size:13px;flex:1;min-width:200px}\n .finding-resource{color:#94a3b8;font-size:12px;max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n .finding-card>details{width:100%;margin-top:4px}\n .finding-card>details>summary{cursor:pointer;font-size:12px;color:#60a5fa;user-select:none}\n .finding-card-body{padding:8px 0}\n .finding-card-body p{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n .finding-card-body ol{padding-left:20px}\n .finding-card-body li{color:#cbd5e1;font-size:13px;margin-bottom:2px}\n .rec-fold{background:#1e293b;border:1px solid #334155;border-radius:8px;margin-bottom:16px;overflow:hidden}\n .rec-fold>summary{cursor:pointer;padding:16px 20px;display:flex;align-items:center;gap:12px;list-style:none;user-select:none}\n .rec-fold>summary::-webkit-details-marker{display:none}\n .rec-fold>summary::marker{content:\"\"}\n .rec-fold>summary::after{content:\"\\\\25B6\";font-size:12px;color:#64748b;flex-shrink:0;transition:transform 0.2s;margin-left:auto}\n .rec-fold[open]>summary::after{transform:rotate(90deg)}\n .rec-fold[open]>summary{border-bottom:1px solid #334155}\n .rec-body{padding:12px 20px 16px}\n .rec-body ol{padding-left:24px}\n .rec-body li{margin-bottom:8px;color:#cbd5e1;font-size:13px}\n .rec-body .badge{margin-right:6px;vertical-align:middle}\n @media print{\n body{background:#fff;color:#1e293b;-webkit-print-color-adjust:exact;print-color-adjust:exact}\n .container{max-width:100%;padding:20px}\n .card,.score-card,.stat-card,.chart-box,.finding-fold,.top5-card,.trend-chart,.category-fold,.module-fold,.finding-card,.rec-fold{background:#fff;border:1px solid #e2e8f0}\n .badge{border:1px solid}\n header{border-bottom-color:#e2e8f0}\n h2{border-bottom-color:#e2e8f0}\n th{background:#f1f5f9;color:#1e293b}\n td{border-bottom-color:#e2e8f0;color:#475569}\n footer{border-top-color:#e2e8f0}\n .meta,.disclaimer{color:#64748b}\n .finding-detail,.top5-detail{color:#475569}\n .finding-detail strong,.top5-detail strong{color:#1e293b}\n .stat-label,.score-label{color:#64748b}\n .chart-title,.trend-title{color:#475569}\n .remediation-steps li,.top5-remediation li{color:#475569}\n .recommendations li{color:#475569}\n .finding-card-body p,.finding-card-body li{color:#475569}\n .finding-title-text{color:#1e293b}\n .finding-resource{color:#64748b}\n .check-findings li{color:#64748b}\n .finding-fold,.top5-card,.category-fold,.module-fold,.finding-card,.rec-fold{break-inside:avoid}\n .check-item{break-inside:avoid}\n svg text{fill:#1e293b !important}\n .finding-fold[open]>summary,.category-fold[open]>summary,.module-fold[open]>summary,.rec-fold[open]>summary{border-bottom-color:#e2e8f0}\n details{display:block}\n details>summary{display:block}\n details>:not(summary){display:block !important}\n }\n `;\n}\n\n// ---------------------------------------------------------------------------\n// SVG Charts\n// ---------------------------------------------------------------------------\n\nfunction donutChart(summary: FullScanResult[\"summary\"]): string {\n const total = summary.totalFindings;\n const r = 80;\n const circ = 2 * Math.PI * r; // ~502.65\n\n if (total === 0) {\n return [\n '<svg viewBox=\"0 0 200 200\" width=\"200\" height=\"200\">',\n ' <circle cx=\"100\" cy=\"100\" r=\"80\" fill=\"none\" stroke=\"#334155\" stroke-width=\"20\"/>',\n ' <text x=\"100\" y=\"105\" text-anchor=\"middle\" fill=\"#22c55e\" font-size=\"24\" font-weight=\"700\">0</text>',\n \"</svg>\",\n ].join(\"\\n\");\n }\n\n const segments: Array<{ count: number; color: string }> = [\n { count: summary.critical, color: SEV_COLOR.CRITICAL },\n { count: summary.high, color: SEV_COLOR.HIGH },\n { count: summary.medium, color: SEV_COLOR.MEDIUM },\n { count: summary.low, color: SEV_COLOR.LOW },\n ].filter((s) => s.count > 0);\n\n let offset = 0;\n const circles = segments.map((s) => {\n const arc = (s.count / total) * circ;\n const el = `<circle cx=\"100\" cy=\"100\" r=\"80\" fill=\"none\" stroke=\"${s.color}\" stroke-width=\"20\" stroke-dasharray=\"${arc.toFixed(2)} ${(circ - arc).toFixed(2)}\" stroke-dashoffset=\"${(-offset).toFixed(2)}\" transform=\"rotate(-90 100 100)\"/>`;\n offset += arc;\n return el;\n });\n\n return [\n '<svg viewBox=\"0 0 200 200\" width=\"200\" height=\"200\">',\n ...circles.map((c) => ` ${c}`),\n ` <text x=\"100\" y=\"105\" text-anchor=\"middle\" fill=\"#f8fafc\" font-size=\"28\" font-weight=\"700\">${total}</text>`,\n \"</svg>\",\n ].join(\"\\n\");\n}\n\nfunction barChart(modules: FullScanResult[\"modules\"]): string {\n const withFindings = modules\n .filter((m) => m.findingsCount > 0)\n .sort((a, b) => b.findingsCount - a.findingsCount)\n .slice(0, 12);\n\n if (withFindings.length === 0) {\n return [\n '<svg viewBox=\"0 0 400 50\" width=\"100%\">',\n ' <text x=\"200\" y=\"30\" text-anchor=\"middle\" fill=\"#22c55e\" font-size=\"14\" font-weight=\"600\">All modules clean</text>',\n \"</svg>\",\n ].join(\"\\n\");\n }\n\n const maxCount = withFindings[0].findingsCount;\n const barH = 22;\n const gap = 6;\n const labelW = 160;\n const maxBarW = 190;\n const height = withFindings.length * (barH + gap);\n\n const bars = withFindings.map((m, i) => {\n const y = i * (barH + gap);\n const w = Math.max(4, (m.findingsCount / maxCount) * maxBarW);\n const worstSev = m.findings.reduce<Severity>((worst, f) => {\n const idx = SEVERITY_ORDER.indexOf(f.severity);\n return idx < SEVERITY_ORDER.indexOf(worst) ? f.severity : worst;\n }, \"LOW\");\n const color = SEV_COLOR[worstSev];\n return [\n `<text x=\"${labelW - 8}\" y=\"${y + barH / 2 + 4}\" text-anchor=\"end\" fill=\"#94a3b8\" font-size=\"11\">${esc(m.module)}</text>`,\n `<rect x=\"${labelW}\" y=\"${y}\" width=\"${w.toFixed(1)}\" height=\"${barH}\" rx=\"3\" fill=\"${color}\" opacity=\"0.85\"/>`,\n `<text x=\"${labelW + w + 6}\" y=\"${y + barH / 2 + 4}\" fill=\"#f8fafc\" font-size=\"11\">${m.findingsCount}</text>`,\n ].join(\"\\n\");\n });\n\n return [\n `<svg viewBox=\"0 0 400 ${height}\" width=\"100%\">`,\n ...bars,\n \"</svg>\",\n ].join(\"\\n\");\n}\n\nfunction findingsTrendChart(history: DashboardHistoryEntry[]): string {\n const entries = history.slice(-30);\n if (entries.length < 2) return \"\";\n\n const W = 800;\n const H = 260;\n const pad = { top: 30, right: 20, bottom: 50, left: 50 };\n const plotW = W - pad.left - pad.right;\n const plotH = H - pad.top - pad.bottom;\n\n const maxVal = Math.max(\n 1,\n ...entries.flatMap((e) => [e.critical, e.high, e.medium, e.low]),\n );\n\n const xPos = (i: number) =>\n pad.left + (i / Math.max(1, entries.length - 1)) * plotW;\n const yPos = (v: number) => pad.top + plotH - (v / maxVal) * plotH;\n\n const lines: Array<{\n key: \"critical\" | \"high\" | \"medium\" | \"low\";\n color: string;\n label: string;\n }> = [\n { key: \"critical\", color: \"#ef4444\", label: \"Critical\" },\n { key: \"high\", color: \"#f97316\", label: \"High\" },\n { key: \"medium\", color: \"#eab308\", label: \"Medium\" },\n { key: \"low\", color: \"#22c55e\", label: \"Low\" },\n ];\n\n const polylines = lines\n .map((line) => {\n const pts = entries\n .map(\n (e, i) =>\n `${xPos(i).toFixed(1)},${yPos(e[line.key]).toFixed(1)}`,\n )\n .join(\" \");\n return `<polyline points=\"${pts}\" fill=\"none\" stroke=\"${line.color}\" stroke-width=\"2\" stroke-linejoin=\"round\"/>`;\n })\n .join(\"\\n \");\n\n const xLabels = entries\n .map((e, i) => {\n if (i % 5 !== 0 && i !== entries.length - 1) return \"\";\n return `<text x=\"${xPos(i).toFixed(1)}\" y=\"${H - 8}\" text-anchor=\"middle\" fill=\"#94a3b8\" font-size=\"10\">${e.date.slice(5)}</text>`;\n })\n .filter(Boolean)\n .join(\"\\n \");\n\n const ySteps = 5;\n const yLabels = Array.from({ length: ySteps + 1 }, (_, i) => {\n const val = Math.round((maxVal / ySteps) * i);\n return [\n `<text x=\"${pad.left - 8}\" y=\"${yPos(val).toFixed(1)}\" text-anchor=\"end\" fill=\"#94a3b8\" font-size=\"10\" dominant-baseline=\"middle\">${val}</text>`,\n `<line x1=\"${pad.left}\" y1=\"${yPos(val).toFixed(1)}\" x2=\"${W - pad.right}\" y2=\"${yPos(val).toFixed(1)}\" stroke=\"#334155\" stroke-width=\"0.5\"/>`,\n ].join(\"\\n \");\n }).join(\"\\n \");\n\n const legend = lines\n .map((line, i) => {\n const lx = pad.left + i * 110;\n return `<rect x=\"${lx}\" y=\"8\" width=\"14\" height=\"3\" rx=\"1\" fill=\"${line.color}\"/><text x=\"${lx + 18}\" y=\"12\" fill=\"#94a3b8\" font-size=\"10\">${line.label}</text>`;\n })\n .join(\"\\n \");\n\n return [\n `<svg viewBox=\"0 0 ${W} ${H}\" width=\"100%\" preserveAspectRatio=\"xMidYMid meet\">`,\n ` ${legend}`,\n ` ${yLabels}`,\n ` ${polylines}`,\n ` ${xLabels}`,\n \"</svg>\",\n ].join(\"\\n\");\n}\n\nfunction scoreTrendChart(history: DashboardHistoryEntry[]): string {\n const entries = history.slice(-30);\n if (entries.length < 2) return \"\";\n\n const W = 800;\n const H = 220;\n const pad = { top: 20, right: 20, bottom: 50, left: 50 };\n const plotW = W - pad.left - pad.right;\n const plotH = H - pad.top - pad.bottom;\n\n const xPos = (i: number) =>\n pad.left + (i / Math.max(1, entries.length - 1)) * plotW;\n const yPos = (v: number) => pad.top + plotH - (v / 100) * plotH;\n\n const pts = entries\n .map((e, i) => `${xPos(i).toFixed(1)},${yPos(e.score).toFixed(1)}`)\n .join(\" \");\n\n const zones = [\n `<rect x=\"${pad.left}\" y=\"${yPos(100).toFixed(1)}\" width=\"${plotW}\" height=\"${(yPos(80) - yPos(100)).toFixed(1)}\" fill=\"#22c55e\" opacity=\"0.06\"/>`,\n `<rect x=\"${pad.left}\" y=\"${yPos(80).toFixed(1)}\" width=\"${plotW}\" height=\"${(yPos(50) - yPos(80)).toFixed(1)}\" fill=\"#eab308\" opacity=\"0.06\"/>`,\n `<rect x=\"${pad.left}\" y=\"${yPos(50).toFixed(1)}\" width=\"${plotW}\" height=\"${(yPos(0) - yPos(50)).toFixed(1)}\" fill=\"#ef4444\" opacity=\"0.06\"/>`,\n ].join(\"\\n \");\n\n const xLabels = entries\n .map((e, i) => {\n if (i % 5 !== 0 && i !== entries.length - 1) return \"\";\n return `<text x=\"${xPos(i).toFixed(1)}\" y=\"${H - 8}\" text-anchor=\"middle\" fill=\"#94a3b8\" font-size=\"10\">${e.date.slice(5)}</text>`;\n })\n .filter(Boolean)\n .join(\"\\n \");\n\n const yVals = [0, 25, 50, 75, 100];\n const yLabels = yVals\n .map(\n (val) =>\n `<text x=\"${pad.left - 8}\" y=\"${yPos(val).toFixed(1)}\" text-anchor=\"end\" fill=\"#94a3b8\" font-size=\"10\" dominant-baseline=\"middle\">${val}</text>\\n <line x1=\"${pad.left}\" y1=\"${yPos(val).toFixed(1)}\" x2=\"${W - pad.right}\" y2=\"${yPos(val).toFixed(1)}\" stroke=\"#334155\" stroke-width=\"0.5\"/>`,\n )\n .join(\"\\n \");\n\n return [\n `<svg viewBox=\"0 0 ${W} ${H}\" width=\"100%\" preserveAspectRatio=\"xMidYMid meet\">`,\n ` ${zones}`,\n ` ${yLabels}`,\n ` <polyline points=\"${pts}\" fill=\"none\" stroke=\"#60a5fa\" stroke-width=\"2.5\" stroke-linejoin=\"round\"/>`,\n ` ${xLabels}`,\n \"</svg>\",\n ].join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// General HTML Report\n// ---------------------------------------------------------------------------\n\nexport function generateHtmlReport(\n scanResults: FullScanResult,\n history?: DashboardHistoryEntry[],\n): string {\n const { summary, modules, accountId, region, scanStart, scanEnd } =\n scanResults;\n const date = scanStart.split(\"T\")[0];\n const duration = formatDuration(scanStart, scanEnd);\n const score = calcScore(summary);\n\n const allFindings: Finding[] = modules.flatMap((m) =>\n m.findings.map((f) => ({ ...f, module: f.module ?? m.module })),\n );\n\n // --- Top 5 Findings ---\n let top5Html = \"\";\n if (allFindings.length > 0) {\n const top5 = [...allFindings]\n .sort((a, b) => b.riskScore - a.riskScore)\n .slice(0, 5);\n const cards = top5\n .map(\n (f, i) => `\n <div class=\"top5-card sev-${esc(f.severity.toLowerCase())}\">\n <div class=\"top5-rank\">#${i + 1}</div>\n <div class=\"top5-content\">\n <span class=\"badge badge-${esc(f.severity.toLowerCase())}\">${esc(f.severity)}</span>\n <div class=\"top5-title\">${esc(f.title)}</div>\n <div class=\"top5-detail\"><strong>Resource:</strong> ${esc(f.resourceId)}</div>\n <div class=\"top5-detail\"><strong>Impact:</strong> ${esc(f.impact)}</div>\n <div class=\"top5-detail\"><strong>Risk Score:</strong> ${f.riskScore}/10</div>\n <h4>Remediation</h4>\n <ol class=\"top5-remediation\">${f.remediationSteps.map((s) => `<li>${esc(s)}</li>`).join(\"\")}</ol>\n </div>\n </div>`,\n )\n .join(\"\\n\");\n top5Html = `\n <section>\n <h2>Top ${top5.length} Highest Risk Findings</h2>\n ${cards}\n </section>`;\n }\n\n // --- Findings HTML (grouped by module, then severity) ---\n let findingsHtml: string;\n if (summary.totalFindings === 0) {\n findingsHtml = '<div class=\"no-findings\">No security issues found.</div>';\n } else {\n const FOLD_THRESHOLD = 20;\n\n const renderCard = (f: Finding): string => {\n const sev = f.severity.toLowerCase();\n return `<div class=\"finding-card sev-${esc(sev)}\">\n <span class=\"badge badge-${esc(sev)}\">${esc(f.severity)}</span>\n <span class=\"finding-title-text\">${esc(f.title)}</span>\n <span class=\"finding-resource\">${esc(f.resourceArn || f.resourceId)}</span>\n <details><summary>Details</summary><div class=\"finding-card-body\">\n <p>${esc(f.description)}</p>\n <p><strong>Remediation:</strong></p>\n <ol>${f.remediationSteps.map((s) => `<li>${esc(s)}</li>`).join(\"\")}</ol>\n </div></details>\n </div>`;\n };\n\n const renderCards = (findings: Finding[]): string => {\n if (findings.length <= FOLD_THRESHOLD) {\n return findings.map(renderCard).join(\"\\n\");\n }\n const first = findings.slice(0, FOLD_THRESHOLD).map(renderCard).join(\"\\n\");\n const rest = findings.slice(FOLD_THRESHOLD).map(renderCard).join(\"\\n\");\n return `${first}\\n<details><summary>Show remaining ${findings.length - FOLD_THRESHOLD} findings...</summary>\\n${rest}\\n</details>`;\n };\n\n const SEV_EMOJI: Record<string, string> = {\n CRITICAL: \"&#128308;\",\n HIGH: \"&#128992;\",\n MEDIUM: \"&#128993;\",\n LOW: \"&#128309;\",\n };\n\n // Group findings by module\n const moduleMap = new Map<string, Finding[]>();\n for (const f of allFindings) {\n const mod = f.module ?? \"unknown\";\n if (!moduleMap.has(mod)) moduleMap.set(mod, []);\n moduleMap.get(mod)!.push(f);\n }\n\n // Sort modules: those with critical/high first, then by count\n const moduleEntries = [...moduleMap.entries()].sort((a, b) => {\n const aHasCritHigh = a[1].some((f) => f.severity === \"CRITICAL\" || f.severity === \"HIGH\");\n const bHasCritHigh = b[1].some((f) => f.severity === \"CRITICAL\" || f.severity === \"HIGH\");\n if (aHasCritHigh !== bHasCritHigh) return aHasCritHigh ? -1 : 1;\n return b[1].length - a[1].length;\n });\n\n findingsHtml = moduleEntries.map(([modName, modFindings]) => {\n const sevCounts: Record<string, number> = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };\n for (const f of modFindings) sevCounts[f.severity]++;\n\n const badges = SEVERITY_ORDER\n .filter((sev) => sevCounts[sev] > 0)\n .map((sev) => `<span class=\"badge badge-${sev.toLowerCase()}\">${sevCounts[sev]} ${sev.charAt(0) + sev.slice(1).toLowerCase()}</span>`)\n .join(\" \");\n\n const sevGroups = SEVERITY_ORDER.map((sev) => {\n const findings = modFindings.filter((f) => f.severity === sev);\n if (findings.length === 0) return \"\";\n findings.sort((a, b) => b.riskScore - a.riskScore);\n\n const emoji = SEV_EMOJI[sev] ?? \"\";\n const label = sev.charAt(0) + sev.slice(1).toLowerCase();\n\n return `<details class=\"severity-group-fold\">\n <summary><h4>${emoji} ${label} (${findings.length})</h4></summary>\n ${renderCards(findings)}\n </details>`;\n }).filter(Boolean).join(\"\\n\");\n\n return `<details class=\"module-fold\">\n <summary>\n <h3>&#128274; ${esc(modName)} (${modFindings.length})</h3>\n <span class=\"module-badges\">${badges}</span>\n </summary>\n <div class=\"module-body\">\n ${sevGroups}\n </div>\n </details>`;\n }).join(\"\\n\");\n }\n\n // --- Trend Charts ---\n let trendHtml = \"\";\n if (history && history.length >= 2) {\n trendHtml = `\n <section class=\"trend-section\">\n <h2>30-Day Trends</h2>\n <div class=\"trend-chart\">\n <div class=\"trend-title\">Findings by Severity</div>\n ${findingsTrendChart(history)}\n </div>\n <div class=\"trend-chart\">\n <div class=\"trend-title\">Security Score</div>\n ${scoreTrendChart(history)}\n </div>\n </section>`;\n }\n\n // --- Statistics table ---\n const statsRows = modules\n .map(\n (m) =>\n `<tr><td>${esc(m.module)}</td><td>${m.resourcesScanned}</td><td>${m.findingsCount}</td><td>${m.status === \"success\" ? \"&#10003;\" : \"&#10007;\"}</td></tr>`,\n )\n .join(\"\\n\");\n\n // --- Recommendations (deduplicated) ---\n let recsHtml = \"\";\n if (summary.totalFindings > 0) {\n const recMap = new Map<string, { text: string; severity: Severity; count: number }>();\n for (const f of allFindings) {\n const rem = f.remediationSteps[0] ?? \"Review and remediate.\";\n const existing = recMap.get(rem);\n if (existing) {\n existing.count++;\n if (SEVERITY_ORDER.indexOf(f.severity) < SEVERITY_ORDER.indexOf(existing.severity)) {\n existing.severity = f.severity;\n }\n } else {\n recMap.set(rem, { text: rem, severity: f.severity, count: 1 });\n }\n }\n const uniqueRecs = [...recMap.values()].sort((a, b) => {\n const sevDiff = SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity);\n if (sevDiff !== 0) return sevDiff;\n return b.count - a.count;\n });\n\n const renderRec = (r: { text: string; severity: Severity; count: number }): string => {\n const sev = r.severity.toLowerCase();\n const countLabel = r.count > 1 ? ` (&times; ${r.count})` : \"\";\n return `<li><span class=\"badge badge-${esc(sev)}\">${esc(r.severity)}</span> ${esc(r.text)}${countLabel}</li>`;\n };\n\n const TOP_N = 10;\n const topItems = uniqueRecs.slice(0, TOP_N).map(renderRec).join(\"\\n\");\n const remaining = uniqueRecs.slice(TOP_N);\n const moreHtml = remaining.length > 0\n ? `\\n<details><summary>Show ${remaining.length} more&hellip;</summary>\\n${remaining.map(renderRec).join(\"\\n\")}\\n</details>`\n : \"\";\n\n recsHtml = `\n <details class=\"rec-fold\">\n <summary><h2 style=\"margin:0;border:0;display:inline\">Recommendations (${uniqueRecs.length} unique)</h2></summary>\n <div class=\"rec-body\">\n <ol>${topItems}${moreHtml}</ol>\n </div>\n </details>`;\n }\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>AWS Security Scan Report &mdash; ${esc(date)}</title>\n<style>${sharedCss()}</style>\n</head>\n<body>\n<div class=\"container\">\n\n<header>\n <h1>&#128737;&#65039; AWS Security Scan Report</h1>\n <div class=\"meta\">Account: ${esc(accountId)} | Region: ${esc(region)} | ${esc(date)} | Duration: ${esc(duration)}</div>\n</header>\n\n<section class=\"summary\">\n <div class=\"score-card\">\n <div class=\"score-value\" style=\"color:${scoreColor(score)}\">${score}</div>\n <div class=\"score-label\">Security Score</div>\n </div>\n <div class=\"severity-stats\">\n <div class=\"stat-card stat-critical\"><div class=\"stat-count\">${summary.critical}</div><div class=\"stat-label\">Critical</div></div>\n <div class=\"stat-card stat-high\"><div class=\"stat-count\">${summary.high}</div><div class=\"stat-label\">High</div></div>\n <div class=\"stat-card stat-medium\"><div class=\"stat-count\">${summary.medium}</div><div class=\"stat-label\">Medium</div></div>\n <div class=\"stat-card stat-low\"><div class=\"stat-count\">${summary.low}</div><div class=\"stat-label\">Low</div></div>\n </div>\n</section>\n\n<section class=\"charts\">\n <div class=\"chart-box\">\n <div class=\"chart-title\">Severity Distribution</div>\n <div style=\"text-align:center\">${donutChart(summary)}</div>\n </div>\n <div class=\"chart-box\">\n <div class=\"chart-title\">Findings by Module</div>\n ${barChart(modules)}\n </div>\n</section>\n\n${trendHtml}\n\n${top5Html}\n\n<section>\n <h2>Scan Statistics</h2>\n <table>\n <thead><tr><th>Module</th><th>Resources</th><th>Findings</th><th>Status</th></tr></thead>\n <tbody>${statsRows}</tbody>\n </table>\n</section>\n\n<section>\n <h2>All Findings</h2>\n ${findingsHtml}\n</section>\n\n${recsHtml}\n\n<footer>\n <p>Generated by AWS Security MCP Server v${VERSION}</p>\n <p>This report is for informational purposes only.</p>\n</footer>\n\n</div>\n</body>\n</html>`;\n}\n\n// ---------------------------------------------------------------------------\n// MLPS Level 3 HTML Report (等保三级)\n// ---------------------------------------------------------------------------\n\nexport function generateMlps3HtmlReport(\n scanResults: FullScanResult,\n history?: DashboardHistoryEntry[],\n): string {\n const { accountId, region, scanStart } = scanResults;\n const date = scanStart.split(\"T\")[0];\n const scanTime = scanStart.replace(\"T\", \" \").replace(/\\.\\d+Z$/, \" UTC\");\n\n const allFindings: Finding[] = scanResults.modules.flatMap((m) =>\n m.findings.map((f) => ({ ...f, module: f.module ?? m.module })),\n );\n\n const scanModules = scanResults.modules.map((m) => ({\n module: m.module,\n status: m.status,\n }));\n const results = MLPS_CHECKS.map((check) =>\n evaluateCheck(check, allFindings, scanModules),\n );\n\n const passCount = results.filter((r) => r.status === \"pass\").length;\n const failCount = results.filter((r) => r.status === \"fail\").length;\n const unknownCount = results.filter((r) => r.status === \"unknown\").length;\n const checkedTotal = passCount + failCount;\n const percent =\n checkedTotal > 0 ? Math.round((passCount / checkedTotal) * 100) : 0;\n\n // --- Trend Charts ---\n let trendHtml = \"\";\n if (history && history.length >= 2) {\n trendHtml = `\n <section class=\"trend-section\">\n <h2>30日趋势</h2>\n <div class=\"trend-chart\">\n <div class=\"trend-title\">按严重性分类的发现</div>\n ${findingsTrendChart(history)}\n </div>\n <div class=\"trend-chart\">\n <div class=\"trend-title\">安全评分</div>\n ${scoreTrendChart(history)}\n </div>\n </section>`;\n }\n\n // --- Category sections (folded) ---\n const categorySections = CATEGORY_ORDER.map((category) => {\n const sectionTitle = CATEGORY_SECTION[category];\n const categoryResults = results.filter(\n (r) => r.check.category === category,\n );\n if (categoryResults.length === 0) return \"\";\n\n const catPass = categoryResults.filter((r) => r.status === \"pass\").length;\n const catFail = categoryResults.filter((r) => r.status === \"fail\").length;\n const catUnknown = categoryResults.filter(\n (r) => r.status === \"unknown\",\n ).length;\n const byId = new Map<string, typeof categoryResults>();\n for (const r of categoryResults) {\n const existing = byId.get(r.check.id) ?? [];\n existing.push(r);\n byId.set(r.check.id, existing);\n }\n\n const groups = [...byId.entries()]\n .map(([checkId, checkResults]) => {\n const grpPass = checkResults.filter((r) => r.status === \"pass\").length;\n const grpFail = checkResults.filter((r) => r.status === \"fail\").length;\n const grpUnknown = checkResults.filter((r) => r.status === \"unknown\").length;\n\n const items = checkResults\n .map((r) => {\n const icon =\n r.status === \"pass\"\n ? \"&#10004;\"\n : r.status === \"fail\"\n ? \"&#10008;\"\n : \"&#9888;\";\n const cls = `check-${r.status}`;\n const label = r.status === \"unknown\" ? \" (未检查)\" : \"\";\n let findingsHtml = \"\";\n if (r.status === \"fail\" && r.relatedFindings.length > 0) {\n const items = r.relatedFindings\n .slice(0, 3)\n .map(\n (f) =>\n `<li>${esc(f.severity)}: ${esc(f.title)}</li>`,\n );\n if (r.relatedFindings.length > 3) {\n items.push(\n `<li>... 及其他 ${r.relatedFindings.length - 3} 项</li>`,\n );\n }\n findingsHtml = `<ul class=\"check-findings\">${items.join(\"\")}</ul>`;\n }\n return `<div class=\"check-item ${cls}\"><span class=\"check-icon\">${icon}</span><span class=\"check-name\">${esc(r.check.name)}${label}</span></div>${findingsHtml}`;\n })\n .join(\"\\n\");\n\n const statusBadges = [\n grpPass > 0 ? `<span class=\"category-stat-pass\">&#10003; ${grpPass}</span>` : \"\",\n grpFail > 0 ? `<span class=\"category-stat-fail\">&#10007; ${grpFail}</span>` : \"\",\n grpUnknown > 0 ? `<span class=\"category-stat-unknown\">? ${grpUnknown}</span>` : \"\",\n ].filter(Boolean).join(\" \");\n\n return `<details class=\"severity-group-fold\"><summary><h4>${esc(checkId)} ${esc(checkResults[0].check.name)} <span class=\"category-stats\">${statusBadges}</span></h4></summary>\\n${items}\\n</details>`;\n })\n .join(\"\\n\");\n\n const statsHtml = [\n catPass > 0\n ? `<span class=\"category-stat-pass\">&#10003; ${catPass}</span>`\n : \"\",\n catFail > 0\n ? `<span class=\"category-stat-fail\">&#10007; ${catFail}</span>`\n : \"\",\n catUnknown > 0\n ? `<span class=\"category-stat-unknown\">? ${catUnknown}</span>`\n : \"\",\n ]\n .filter(Boolean)\n .join(\"\");\n\n return `<details class=\"category-fold\">\n <summary>\n <span class=\"category-title\">${esc(sectionTitle)}</span>\n <span class=\"category-stats\">${statsHtml}</span>\n </summary>\n <div class=\"category-body\">${groups}</div>\n</details>`;\n })\n .filter(Boolean)\n .join(\"\\n\");\n\n // --- Remediation (deduplicated) ---\n const failedResults = results.filter((r) => r.status === \"fail\");\n let remediationHtml = \"\";\n if (failedResults.length > 0) {\n const mlpsRecMap = new Map<string, { text: string; severity: Severity; count: number }>();\n for (const r of failedResults) {\n for (const f of r.relatedFindings) {\n const rem = f.remediationSteps[0] ?? \"Review and remediate.\";\n const existing = mlpsRecMap.get(rem);\n if (existing) {\n existing.count++;\n if (SEVERITY_ORDER.indexOf(f.severity) < SEVERITY_ORDER.indexOf(existing.severity)) {\n existing.severity = f.severity;\n }\n } else {\n mlpsRecMap.set(rem, { text: rem, severity: f.severity, count: 1 });\n }\n }\n }\n const mlpsUniqueRecs = [...mlpsRecMap.values()].sort((a, b) => {\n const sevDiff = SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity);\n if (sevDiff !== 0) return sevDiff;\n return b.count - a.count;\n });\n\n const renderMlpsRec = (r: { text: string; severity: Severity; count: number }): string => {\n const sev = r.severity.toLowerCase();\n const countLabel = r.count > 1 ? ` (&times; ${r.count})` : \"\";\n return `<li><span class=\"badge badge-${esc(sev)}\">${esc(r.severity)}</span> ${esc(r.text)}${countLabel}</li>`;\n };\n\n const MLPS_TOP_N = 10;\n const mlpsTopItems = mlpsUniqueRecs.slice(0, MLPS_TOP_N).map(renderMlpsRec).join(\"\\n\");\n const mlpsRemaining = mlpsUniqueRecs.slice(MLPS_TOP_N);\n const mlpsMoreHtml = mlpsRemaining.length > 0\n ? `\\n<details><summary>显示其余 ${mlpsRemaining.length} 项&hellip;</summary>\\n${mlpsRemaining.map(renderMlpsRec).join(\"\\n\")}\\n</details>`\n : \"\";\n\n remediationHtml = `\n <details class=\"rec-fold\">\n <summary><h2 style=\"margin:0;border:0;display:inline\">建议整改项(${mlpsUniqueRecs.length} 项去重)</h2></summary>\n <div class=\"rec-body\">\n <ol>${mlpsTopItems}${mlpsMoreHtml}</ol>\n </div>\n </details>`;\n }\n\n const passRateColor =\n percent >= 80 ? \"#22c55e\" : percent >= 50 ? \"#eab308\" : \"#ef4444\";\n const unknownNote =\n unknownCount > 0\n ? `<div style=\"color:#94a3b8;font-size:12px;margin-top:8px\">(未检查项不计入通过率)</div>`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>等保三级预检报告 &mdash; ${esc(date)}</title>\n<style>${sharedCss()}</style>\n</head>\n<body>\n<div class=\"container\">\n\n<header>\n <h1>&#128737;&#65039; 等保三级预检报告</h1>\n <div class=\"disclaimer\">本报告为等保预检参考,仅覆盖 AWS 云平台配置检查。完整等保测评需由持证测评机构执行。</div>\n <div class=\"meta\">账户: ${esc(accountId)} | 区域: ${esc(region)} | 扫描时间: ${esc(scanTime)}</div>\n</header>\n\n<section class=\"summary\">\n <div class=\"score-card\">\n <div class=\"score-value\" style=\"color:${passRateColor}\">${percent}%</div>\n <div class=\"score-label\">通过率</div>\n </div>\n <div class=\"severity-stats\">\n <div class=\"stat-card\" style=\"border-color:#22c55e30\"><div class=\"stat-count\" style=\"color:#22c55e\">${passCount}</div><div class=\"stat-label\">通过</div></div>\n <div class=\"stat-card\" style=\"border-color:#ef444430\"><div class=\"stat-count\" style=\"color:#ef4444\">${failCount}</div><div class=\"stat-label\">不通过</div></div>\n ${unknownCount > 0 ? `<div class=\"stat-card\" style=\"border-color:#94a3b830\"><div class=\"stat-count\" style=\"color:#94a3b8\">${unknownCount}</div><div class=\"stat-label\">未检查</div></div>` : \"\"}\n </div>\n</section>\n${unknownNote}\n\n${trendHtml}\n\n${categorySections}\n\n${remediationHtml}\n\n<footer>\n <p>由 AWS Security MCP Server v${VERSION} 生成</p>\n <p>本报告仅供参考。完整等保测评需由持证测评机构执行。</p>\n</footer>\n\n</div>\n</body>\n</html>`;\n}\n","import { writeFileSync, readFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nimport type {\n FullScanResult,\n DashboardData,\n DashboardHistoryEntry,\n} from \"../types.js\";\n\nexport function calculateScore(summary: FullScanResult[\"summary\"]): number {\n const raw =\n 100 -\n summary.critical * 15 -\n summary.high * 5 -\n summary.medium * 2 -\n summary.low * 0.5;\n return Math.max(0, Math.min(100, raw));\n}\n\nexport function saveResults(\n scanResults: FullScanResult,\n outputDir?: string,\n): string {\n const baseDir = outputDir ?? join(homedir(), \".aws-security\");\n const today = scanResults.scanStart.slice(0, 10); // YYYY-MM-DD\n\n // Create directories\n const scanDir = join(baseDir, \"scans\", today);\n const dashboardDir = join(baseDir, \"dashboard\");\n mkdirSync(scanDir, { recursive: true });\n mkdirSync(dashboardDir, { recursive: true });\n\n // Write raw scan\n writeFileSync(join(scanDir, \"scan.json\"), JSON.stringify(scanResults, null, 2));\n\n // Read existing dashboard data\n const dataPath = join(dashboardDir, \"data.json\");\n let existing: DashboardData | null = null;\n if (existsSync(dataPath)) {\n try {\n existing = JSON.parse(readFileSync(dataPath, \"utf-8\")) as DashboardData;\n } catch {\n // Corrupt or invalid JSON — start fresh\n existing = null;\n }\n }\n\n // Build history entry for today\n const historyEntry: DashboardHistoryEntry = {\n date: today,\n score: calculateScore(scanResults.summary),\n critical: scanResults.summary.critical,\n high: scanResults.summary.high,\n medium: scanResults.summary.medium,\n low: scanResults.summary.low,\n totalFindings: scanResults.summary.totalFindings,\n };\n\n // Merge history: replace same-date entry or append\n let history = existing?.history ?? [];\n const idx = history.findIndex((h) => h.date === today);\n if (idx >= 0) {\n history[idx] = historyEntry;\n } else {\n history.push(historyEntry);\n }\n // Keep only last 30 entries\n history = history.slice(-30);\n\n // Build dashboard data\n const dashboardData: DashboardData = {\n lastScan: {\n scanStart: scanResults.scanStart,\n scanEnd: scanResults.scanEnd,\n region: scanResults.region,\n accountId: scanResults.accountId,\n summary: scanResults.summary,\n modules: scanResults.modules.map((m) => ({\n module: m.module,\n findingsCount: m.findingsCount,\n status: m.status,\n })),\n findings: scanResults.modules.flatMap((m) =>\n m.findings.map((f) => ({ ...f, module: m.module })),\n ),\n },\n history,\n meta: {\n generatedAt: new Date().toISOString(),\n version: \"1.0.0\",\n dataRetentionDays: 30,\n },\n };\n\n writeFileSync(dataPath, JSON.stringify(dashboardData, null, 2));\n return dataPath;\n}\n","export interface FindingsFilter {\n /** Filter Security Hub findings by category keywords (case-insensitive match on title/description/impact) */\n securityHubCategories?: string[];\n /** Filter GuardDuty findings by type prefix (matched against impact field) */\n guardDutyTypes?: string[];\n /** Filter Inspector findings by type (matched against impact field) */\n inspectorTypes?: string[];\n /** Filter by minimum severity */\n minSeverity?: string;\n}\n\nconst SEVERITY_ORDER: Record<string, number> = {\n LOW: 0,\n MEDIUM: 1,\n HIGH: 2,\n CRITICAL: 3,\n};\n\nexport function applyFindingsFilter(\n moduleName: string,\n findings: import(\"../types.js\").Finding[],\n filter: FindingsFilter,\n): import(\"../types.js\").Finding[] {\n let result = findings;\n\n // Apply severity filter\n if (filter.minSeverity) {\n const minLevel = SEVERITY_ORDER[filter.minSeverity.toUpperCase()] ?? 0;\n result = result.filter((f) => (SEVERITY_ORDER[f.severity] ?? 0) >= minLevel);\n }\n\n // Apply module-specific category filters\n if (moduleName === \"security_hub_findings\" && filter.securityHubCategories?.length) {\n const keywords = filter.securityHubCategories;\n result = result.filter((f) =>\n keywords.some((kw) => {\n const lower = kw.toLowerCase();\n return (\n f.title.toLowerCase().includes(lower) ||\n f.description.toLowerCase().includes(lower) ||\n f.impact.toLowerCase().includes(lower)\n );\n }),\n );\n }\n\n if (moduleName === \"guardduty_findings\" && filter.guardDutyTypes?.length) {\n const prefixes = filter.guardDutyTypes;\n result = result.filter((f) =>\n prefixes.some((prefix) => f.impact.includes(prefix)),\n );\n }\n\n if (moduleName === \"inspector_findings\" && filter.inspectorTypes?.length) {\n const types = filter.inspectorTypes;\n result = result.filter((f) =>\n types.some((t) => f.impact.includes(t)),\n );\n }\n\n return result;\n}\n\nexport const SCAN_GROUPS: Record<string, {\n name: string;\n description: string;\n modules: string[];\n reportType?: string;\n findingsFilter?: FindingsFilter;\n}> = {\n mlps3_precheck: {\n name: \"等保三级预检\",\n description: \"GB/T 22239-2019 等保三级 AWS 云租户层配置检查\",\n modules: [\"service_detection\", \"secret_exposure\", \"ssl_certificate\", \"dns_dangling\", \"network_reachability\", \"iam_privilege_escalation\", \"tag_compliance\", \"disaster_recovery\", \"security_hub_findings\", \"guardduty_findings\", \"inspector_findings\", \"trusted_advisor_findings\", \"config_rules_findings\", \"access_analyzer_findings\", \"patch_compliance_findings\"],\n reportType: \"mlps3\",\n },\n hw_defense: {\n name: \"护网蓝队加固\",\n description: \"护网前安全自查 — 攻击面+弱点评估\",\n modules: [\"service_detection\", \"secret_exposure\", \"network_reachability\", \"dns_dangling\", \"ssl_certificate\", \"iam_privilege_escalation\", \"security_hub_findings\", \"guardduty_findings\", \"inspector_findings\", \"config_rules_findings\", \"access_analyzer_findings\", \"patch_compliance_findings\"],\n findingsFilter: {\n guardDutyTypes: [\"Backdoor\", \"Trojan\", \"PenTest\", \"CryptoCurrency\"],\n minSeverity: \"MEDIUM\",\n },\n },\n exposure: {\n name: \"公网暴露面评估\",\n description: \"评估公网可达的资源和端口\",\n modules: [\"network_reachability\", \"dns_dangling\", \"public_access_verify\", \"ssl_certificate\", \"security_hub_findings\", \"access_analyzer_findings\"],\n findingsFilter: {\n securityHubCategories: [\"network\", \"public\", \"exposure\", \"port\"],\n },\n },\n data_encryption: {\n name: \"数据加密审计\",\n description: \"全面检查存储和传输加密状态\",\n modules: [\"ssl_certificate\", \"security_hub_findings\"],\n findingsFilter: {\n securityHubCategories: [\"encryption\", \"Encryption\"],\n },\n },\n least_privilege: {\n name: \"最小权限审计\",\n description: \"IAM 权限最小化评估\",\n modules: [\"iam_privilege_escalation\", \"security_hub_findings\", \"access_analyzer_findings\"],\n findingsFilter: {\n securityHubCategories: [\"IAM\", \"iam\", \"access\", \"privilege\"],\n },\n },\n log_integrity: {\n name: \"日志完整性审计\",\n description: \"审计日志完整性和保护\",\n modules: [\"service_detection\", \"security_hub_findings\"],\n findingsFilter: {\n securityHubCategories: [\"logging\", \"CloudTrail\", \"audit\"],\n },\n },\n disaster_recovery: {\n name: \"灾备评估\",\n description: \"备份和灾备能力评估\",\n modules: [\"disaster_recovery\", \"security_hub_findings\"],\n },\n idle_resources: {\n name: \"闲置资源清理\",\n description: \"发现未使用的资源\",\n modules: [\"idle_resources\", \"trusted_advisor_findings\"],\n },\n tag_compliance: {\n name: \"资源标签合规\",\n description: \"检查必需标签\",\n modules: [\"tag_compliance\"],\n },\n new_account_baseline: {\n name: \"新账户基线检查\",\n description: \"新 AWS 账户安全基线\",\n modules: [\"service_detection\", \"secret_exposure\", \"iam_privilege_escalation\", \"security_hub_findings\", \"guardduty_findings\", \"access_analyzer_findings\"],\n },\n aggregation: {\n name: \"安全服务聚合\",\n description: \"从 Security Hub / GuardDuty / Inspector / Trusted Advisor / Config Rules / Access Analyzer / Patch Compliance 聚合所有安全发现\",\n modules: [\"security_hub_findings\", \"guardduty_findings\", \"inspector_findings\", \"trusted_advisor_findings\", \"config_rules_findings\", \"access_analyzer_findings\", \"patch_compliance_findings\"],\n },\n};\n","export const SECURITY_RULES_CONTENT = `# AWS Security Scan Modules & Rules (17 modules)\n\n## 1. Service Detection (service_detection)\nDetects which AWS security services are enabled and assesses overall security maturity.\n- **Security Hub not enabled** — Risk 7.5: Provides 300+ automated security checks.\n- **GuardDuty not enabled** — Risk 7.5: Provides continuous threat detection.\n- **Inspector not enabled** — Risk 6.0: Scans for software vulnerabilities.\n- **AWS Config not enabled** — Risk 6.0: Tracks configuration changes.\n- **Macie not enabled** — Risk 5.0: Detects sensitive data in S3 (not available in China regions).\n- CloudTrail detection is included for coverage metrics.\n\n### Maturity Levels\n| Enabled Services | Level |\n|------------------|-------|\n| 0–1 | Basic |\n| 2–3 | Intermediate |\n| 4–5 | Advanced |\n| 6 | Comprehensive |\n\n## 2. Security Hub Findings (security_hub_findings)\nAggregates active findings from AWS Security Hub. Replaces individual config scanners (SG, S3, IAM, CloudTrail, RDS, EBS, VPC, etc.) with centralized compliance checks from FSBP, CIS, and PCI DSS standards.\n- Findings are filtered to ACTIVE + NEW/NOTIFIED workflow status.\n- Severity mapped: CRITICAL → 9.5, HIGH → 8.0, MEDIUM → 5.5, LOW → 3.0.\n- INFORMATIONAL findings are skipped.\n\n## 3. GuardDuty Findings (guardduty_findings)\nAggregates threat detection findings from Amazon GuardDuty.\n- Covers account compromise, instance compromise, and reconnaissance.\n- Severity mapped from GuardDuty 0–10 scale: ≥7 → HIGH, ≥4 → MEDIUM, <4 → LOW.\n- Only non-archived findings are included.\n\n## 4. Inspector Findings (inspector_findings)\nAggregates vulnerability findings from Amazon Inspector v2.\n- Covers CVEs in EC2 instances, Lambda functions, and container images.\n- Severity mapped: CRITICAL → 9.5, HIGH → 8.0, MEDIUM → 5.5, LOW → 3.0.\n- CVE IDs are included in finding titles when available.\n\n## 5. Trusted Advisor Findings (trusted_advisor_findings)\nAggregates security checks from AWS Trusted Advisor.\n- Requires AWS Business or Enterprise Support plan.\n- In China regions, uses cn-north-1 as the Support API endpoint.\n- Status mapped: error (RED) → 8.0, warning (YELLOW) → 5.5, ok (GREEN) → skip.\n\n## 6. Secret Exposure (secret_exposure)\nChecks Lambda env vars and EC2 userData for exposed secrets (AWS keys, private keys, passwords).\n\n## 7. SSL Certificate (ssl_certificate)\nChecks ACM certificates for expiry, failed status, and upcoming renewals.\n\n## 8. Dangling DNS (dns_dangling)\nChecks Route53 CNAME records for dangling DNS (subdomain takeover risk).\n\n## 9. Network Reachability (network_reachability)\nAnalyzes true network reachability by combining Security Group + NACL rules for public EC2 instances.\n\n## 10. IAM Privilege Escalation (iam_privilege_escalation)\nDetects IAM privilege escalation paths — users/roles that can escalate to admin via policy manipulation, role creation, or service abuse.\n\n## 11. Public Access Verify (public_access_verify)\nVerifies actual public accessibility of resources marked as public (S3 HTTP check, RDS DNS resolution).\n\n## 12. Tag Compliance (tag_compliance)\nChecks EC2, RDS, and S3 resources for required tags (Environment, Project, Owner).\n\n## 13. Idle Resources (idle_resources)\nFinds unused/idle AWS resources (unattached EBS volumes, unused EIPs, stopped instances, unused security groups).\n\n## 14. Disaster Recovery (disaster_recovery)\nAssesses disaster recovery readiness — RDS Multi-AZ & backups, EBS snapshot coverage, S3 versioning & cross-region replication.\n\n## 15. Config Rules Findings (config_rules_findings)\nPulls non-compliant AWS Config Rule evaluation results.\n- Lists all Config Rules and their compliance status.\n- For NON_COMPLIANT rules, retrieves specific non-compliant resources.\n- Security-related rules (encryption, IAM, public access, etc.) mapped to HIGH severity (7.5).\n- Other non-compliant rules mapped to MEDIUM severity (5.5).\n- Gracefully handles regions where AWS Config is not enabled.\n\n## 16. IAM Access Analyzer Findings (access_analyzer_findings)\nPulls active IAM Access Analyzer findings — resources accessible from outside the account.\n- Lists active analyzers (ACCOUNT or ORGANIZATION type).\n- Retrieves ACTIVE findings showing external access to resources.\n- Covers S3 buckets, IAM roles, SQS queues, Lambda functions, KMS keys, and more.\n- Severity mapped: CRITICAL → 9.5, HIGH → 8.0, MEDIUM → 5.5, LOW → 3.0.\n- Returns warning if no analyzer is configured.\n\n## 17. SSM Patch Compliance (patch_compliance_findings)\nChecks patch compliance status for SSM-managed instances.\n- Lists all managed instances via SSM.\n- Retrieves patch compliance state for each instance.\n- Missing security patches or failed patches → HIGH (7.5).\n- Missing non-security patches → MEDIUM (5.5).\n- Instances without patch data flagged as LOW (3.0) for visibility.\n- Includes platform info, missing/failed counts, and last scan time.\n`;\n\nexport const RISK_SCORING_CONTENT = `# Risk Scoring Model\n\n## Score Ranges\nEach finding is assigned a risk score from 0.0 to 10.0 based on potential impact and exploitability.\n\n| Score Range | Severity | Priority | Description |\n|-------------|----------|----------|-------------|\n| 9.0 – 10.0 | CRITICAL | P0 | Immediate action required. Active exploitation risk. |\n| 7.0 – 8.9 | HIGH | P1 | Address within 24-48 hours. Significant exposure. |\n| 4.0 – 6.9 | MEDIUM | P2 | Address within 1-2 weeks. Moderate risk. |\n| 0.0 – 3.9 | LOW | P3 | Address in next maintenance cycle. Minor risk. |\n\n## Severity Mapping\n\\`\\`\\`\nscore >= 9.0 → CRITICAL\nscore >= 7.0 → HIGH\nscore >= 4.0 → MEDIUM\nscore < 4.0 → LOW\n\\`\\`\\`\n\n## Priority Mapping\n\\`\\`\\`\nCRITICAL → P0 (Immediate)\nHIGH → P1 (Urgent)\nMEDIUM → P2 (Normal)\nLOW → P3 (Low)\n\\`\\`\\`\n\n## Scoring Factors\n- **Exploitability**: How easily can this misconfiguration be exploited?\n- **Blast radius**: What data or systems are at risk?\n- **Public exposure**: Is the resource internet-facing?\n- **Compliance**: Does this violate common compliance frameworks (CIS, SOC2)?\n- **Data sensitivity**: Could sensitive data be exposed or lost?\n\n## Examples\n- Root account without MFA → 10.0 (total account compromise risk)\n- Public S3 ACL → 9.5 (data breach via public access)\n- Missing encryption at rest → 6.0 (data exposure if storage is compromised)\n- Versioning disabled → 3.0 (data loss risk, low exploitability)\n`;\n","#!/usr/bin/env node\n\nimport { startServer } from \"../src/index.js\";\nimport { VERSION } from \"../src/version.js\";\n\nconst args = process.argv.slice(2);\nconst subcommand = args[0];\n\nconst HELP = `Usage: aws-security-mcp [command] [options]\n\nCommands:\n (default) Start MCP server (stdio, for Kiro/Claude Code)\n dashboard Start local HTTP server serving the security dashboard\n deploy-dashboard Deploy dashboard to an S3 bucket as a static website\n\nOptions:\n --region <region> AWS region (default: AWS_REGION env or us-east-1)\n --version Print version and exit\n --help, -h Show this help message\n\nDashboard options:\n --port <port> Port for local dashboard server (default: 3000)\n\nDeploy options:\n --bucket <name> S3 bucket name (required)\n --region <region> AWS region for the S3 bucket\n\nEnvironment variables:\n AWS_REGION Default AWS region\n AWS_DEFAULT_REGION Fallback default region\n\nThe MCP server communicates over stdio using the MCP protocol.`;\n\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n console.log(HELP);\n process.exit(0);\n}\n\nif (args.includes(\"--version\")) {\n console.log(`aws-security-mcp ${VERSION}`);\n process.exit(0);\n}\n\nfunction getArg(name: string): string | undefined {\n const idx = args.indexOf(name);\n if (idx !== -1 && args[idx + 1]) return args[idx + 1];\n return undefined;\n}\n\nfunction getRegion(): string {\n return (\n getArg(\"--region\") ??\n process.env.AWS_REGION ??\n process.env.AWS_DEFAULT_REGION ??\n \"us-east-1\"\n );\n}\n\nif (subcommand === \"dashboard\") {\n const port = Number(getArg(\"--port\")) || 3000;\n import(\"../src/commands/dashboard.js\").then(({ startDashboard }) => {\n startDashboard(port);\n });\n} else if (subcommand === \"deploy-dashboard\") {\n const bucket = getArg(\"--bucket\");\n if (!bucket) {\n console.error(\"Error: --bucket <name> is required for deploy-dashboard\");\n process.exit(1);\n }\n const region = getRegion();\n import(\"../src/commands/deploy-dashboard.js\").then(({ deployDashboard }) => {\n deployDashboard(bucket, region).catch((err) => {\n console.error(\"Deploy failed:\", err.message || err);\n process.exit(1);\n });\n });\n} else if (subcommand && !subcommand.startsWith(\"--\")) {\n console.error(`Unknown command: ${subcommand}`);\n console.error('Run \"aws-security-mcp --help\" for usage.');\n process.exit(1);\n} else {\n // Default: start MCP server\n const region = getRegion();\n startServer(region).catch((err) => {\n console.error(\"Fatal:\", err);\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA,SAAS,gBAAAA,qBAAoB;AAC7B,SAAS,gBAAgB;AACzB,SAAS,QAAAC,OAAM,SAAS,eAAe;AACvC,SAAS,cAAAC,aAAY,oBAAoB;AACzC,SAAS,iBAAAC,sBAAqB;AAC9B,SAAS,YAAY;AAiBd,SAAS,eAAe,OAAO,KAAY;AAEhD,QAAM,eAAeF,MAAK,WAAW,sBAAsB;AAE3D,MAAI,CAACC,YAAW,YAAY,GAAG;AAC7B,YAAQ;AAAA,MACN;AAAA,YACe,YAAY;AAAA,IAC7B;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,aAAaD;AAAA,IACjB,QAAQ,IAAI,QAAQ,QAAQ,IAAI,eAAe;AAAA,IAC/C;AAAA,EACF;AACA,QAAM,WAAWA,MAAK,cAAc,WAAW;AAC/C,MAAIC,YAAW,UAAU,GAAG;AAC1B,iBAAa,YAAY,QAAQ;AACjC,YAAQ,IAAI,yBAAyB,UAAU,EAAE;AAAA,EACnD,OAAO;AACL,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,QAAQ,YAAY;AAEzC,QAAM,SAASF,cAAa,OAAO,KAAK,QAAQ;AAC9C,UAAM,MAAM,IAAI,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK;AACtC,QAAI,WAAW;AAAA,MACbC,MAAK,cAAc,QAAQ,MAAM,eAAe,GAAG;AAAA,IACrD;AAGA,QAAI,CAAC,SAAS,WAAW,eAAe,GAAG,KAAK,aAAa,cAAc;AACzE,UAAI,UAAU,GAAG;AACjB,UAAI,IAAI,WAAW;AACnB;AAAA,IACF;AAGA,QAAI,CAACC,YAAW,QAAQ,GAAG;AACzB,iBAAWD,MAAK,cAAc,YAAY;AAAA,IAC5C;AAEA,QAAI;AACF,YAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,YAAM,MAAM,QAAQ,QAAQ;AAC5B,UAAI,UAAU,KAAK;AAAA,QACjB,gBAAgB,WAAW,GAAG,KAAK;AAAA,MACrC,CAAC;AACD,UAAI,IAAI,OAAO;AAAA,IACjB,QAAQ;AACN,UAAI,UAAU,GAAG;AACjB,UAAI,IAAI,WAAW;AAAA,IACrB;AAAA,EACF,CAAC;AAED,SAAO,OAAO,MAAM,MAAM;AACxB,UAAM,MAAM,oBAAoB,IAAI;AACpC,YAAQ,IAAI;AAAA,0BAA6B,GAAG;AAAA,CAAI;AAChD,YAAQ,IAAI,yBAAyB;AAGrC,UAAM,MACJ,QAAQ,aAAa,WACjB,SACA,QAAQ,aAAa,UACnB,UACA;AACR,SAAK,GAAG,GAAG,IAAI,GAAG,IAAI,MAAM;AAAA,IAE5B,CAAC;AAAA,EACH,CAAC;AAED,SAAO,GAAG,SAAS,CAAC,QAA+B;AACjD,QAAI,IAAI,SAAS,cAAc;AAC7B,cAAQ,MAAM,QAAQ,IAAI,wCAAwC;AAClE,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM;AAAA,EACR,CAAC;AACH;AA1GA,IAOM,YACA,WAEA;AAVN;AAAA;AAAA;AAOA,IAAM,aAAaE,eAAc,YAAY,GAAG;AAChD,IAAM,YAAYF,MAAK,YAAY,IAAI;AAEvC,IAAM,aAAqC;AAAA,MACzC,SAAS;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,IACZ;AAAA;AAAA;;;ACpBA;AAAA;AAAA;AAAA;AAAA,SAAS,aAAa,gBAAAG,eAAc,cAAAC,aAAY,gBAAAC,qBAAoB;AACpE,SAAS,QAAAC,OAAM,WAAAC,UAAS,gBAAgB;AACxC,SAAS,iBAAAC,sBAAqB;AAC9B;AAAA,EACE,YAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAiBP,SAAS,aAAa,KAAuB;AAC3C,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;AAC7D,UAAM,OAAOH,MAAK,KAAK,MAAM,IAAI;AACjC,QAAI,MAAM,YAAY,GAAG;AACvB,YAAM,KAAK,GAAG,aAAa,IAAI,CAAC;AAAA,IAClC,OAAO;AACL,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,gBACpB,QACA,QACe;AACf,QAAM,eAAeA,MAAKI,YAAW,sBAAsB;AAE3D,MAAI,CAACN,YAAW,YAAY,GAAG;AAC7B,YAAQ;AAAA,MACN;AAAA,YACe,YAAY;AAAA,IAC7B;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,aAAaE;AAAA,IACjB,QAAQ,IAAI,QAAQ,QAAQ,IAAI,eAAe;AAAA,IAC/C;AAAA,EACF;AACA,QAAM,WAAWA,MAAK,cAAc,WAAW;AAC/C,MAAIF,YAAW,UAAU,GAAG;AAC1B,IAAAC,cAAa,YAAY,QAAQ;AACjC,YAAQ,IAAI,yBAAyB,UAAU,EAAE;AAAA,EACnD,OAAO;AACL,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,IAAII,UAAS,EAAE,OAAO,CAAC;AAGlC,UAAQ,IAAI,oBAAoB,MAAM,gCAAgC;AACtE,QAAM,GAAG;AAAA,IACP,IAAI,wBAAwB;AAAA,MAC1B,QAAQ;AAAA,MACR,sBAAsB;AAAA,QACpB,eAAe,EAAE,QAAQ,aAAa;AAAA,QACtC,eAAe,EAAE,KAAK,aAAa;AAAA;AAAA,MACrC;AAAA,IACF,CAAC;AAAA,EACH;AAGA,QAAM,YAAY,OAAO,WAAW,KAAK,IAAI,WAAW;AACxD,UAAQ,IAAI,6CAA6C,MAAM,KAAK;AACpE,QAAM,GAAG;AAAA,IACP,IAAI,uBAAuB;AAAA,MACzB,QAAQ;AAAA,MACR,QAAQ,KAAK,UAAU;AAAA,QACrB,SAAS;AAAA,QACT,WAAW;AAAA,UACT;AAAA,YACE,KAAK;AAAA,YACL,QAAQ;AAAA,YACR,WAAW;AAAA,YACX,QAAQ;AAAA,YACR,UAAU,OAAO,SAAS,SAAS,MAAM;AAAA,UAC3C;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAGA,QAAM,QAAQ,aAAa,YAAY;AACvC,UAAQ,IAAI,aAAa,MAAM,MAAM,kBAAkB,MAAM,KAAK;AAElE,aAAW,YAAY,OAAO;AAC5B,UAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,UAAM,MAAMF,SAAQ,QAAQ;AAC5B,UAAM,cAAc,cAAc,GAAG,KAAK;AAC1C,UAAM,OAAOJ,cAAa,QAAQ;AAElC,UAAM,GAAG;AAAA,MACP,IAAI,iBAAiB;AAAA,QACnB,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,MAAM;AAAA,QACN,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AACA,YAAQ,IAAI,KAAK,GAAG,EAAE;AAAA,EACxB;AAEA,QAAM,SAAS,OAAO,WAAW,KAAK,IAAI,qBAAqB;AAC/D,QAAM,aAAa,UAAU,MAAM,eAAe,MAAM,IAAI,MAAM;AAClE,UAAQ,IAAI;AAAA,iCAAoC;AAChD,UAAQ,IAAI,gBAAgB,UAAU,EAAE;AACxC,UAAQ;AAAA,IACN;AAAA,EACF;AACF;AAlIA,IAUMQ,aACAD,YAEA;AAbN;AAAA;AAAA;AAUA,IAAMC,cAAaH,eAAc,YAAY,GAAG;AAChD,IAAME,aAAYJ,MAAKK,aAAY,IAAI;AAEvC,IAAM,gBAAwC;AAAA,MAC5C,SAAS;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,IACZ;AAAA;AAAA;;;ACvBA,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,SAAS;;;ACFX,IAAM,UAAU;;;ACAvB,SAAS,WAAW,gCAAgC;AAEpD,IAAI;AAEG,SAAS,aAAa,QAAwB;AACnD,MAAI,OAAO,WAAW,KAAK,EAAG,QAAO;AACrC,MAAI,OAAO,WAAW,SAAS,EAAG,QAAO;AACzC,SAAO;AACT;AAEO,SAAS,aAAa,QAAwB;AAEnD,MAAI,OAAO,WAAW,KAAK,EAAG,QAAO;AACrC,SAAO;AACT;AAEA,eAAsB,aAAa,QAAkC;AACnE,MAAI,gBAAiB,QAAO;AAE5B,QAAM,YAAY,UAAU;AAC5B,QAAM,MAAM,IAAI,UAAU,EAAE,QAAQ,UAAU,CAAC;AAC/C,QAAM,WAAW,MAAM,IAAI,KAAK,IAAI,yBAAyB,CAAC,CAAC,CAAC;AAChE,oBAAkB,SAAS,WAAW;AACtC,SAAO;AACT;AAEO,SAAS,aACd,aACA,QACA,aACG;AACH,QAAM,SAAc,EAAE,QAAQ,UAAU,YAAY;AACpD,MAAI,YAAa,QAAO,cAAc;AACtC,SAAO,IAAI,YAAY,MAAM;AAC/B;;;AClCA,SAAS,aAAAC,YAAW,mBAAmB,4BAAAC,iCAAgC;AAQhE,IAAM,sBAAsB;AAEnC,eAAsB,WAAW,SAAiB,QAAgB,SAO/D;AACD,QAAM,cAAc,SAAS,eAAe;AAC5C,QAAM,aAAa,SAAS,cAAc;AAC1C,QAAM,MAAM,IAAIC,WAAU,EAAE,OAAO,CAAC;AACpC,QAAM,SAAS,MAAM,IAAI,KAAK,IAAI,kBAAkB;AAAA,IAClD,SAAS;AAAA,IACT,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,iBAAiB;AAAA,EACnB,CAAC,CAAC;AACF,SAAO;AAAA,IACL,aAAa,OAAO,YAAa;AAAA,IACjC,iBAAiB,OAAO,YAAa;AAAA,IACrC,cAAc,OAAO,YAAa;AAAA,EACpC;AACF;AAEO,SAAS,aAAa,WAAmB,UAAkB,YAAY,OAAe;AAC3F,SAAO,OAAO,SAAS,SAAS,SAAS,SAAS,QAAQ;AAC5D;;;ACpCA,SAAS,qBAAqB,2BAA2B;AASzD,eAAsB,gBAAgB,QAAuC;AAG3E,QAAM,YAAY,OAAO,WAAW,KAAK,IAAI,mBAAmB;AAChE,QAAM,SAAS,IAAI,oBAAoB,EAAE,QAAQ,UAAU,CAAC;AAC5D,QAAM,WAAyB,CAAC;AAChC,MAAI;AAEJ,KAAG;AACD,UAAM,SAAS,MAAM,OAAO,KAAK,IAAI,oBAAoB,EAAE,WAAW,UAAU,CAAC,CAAC;AAClF,eAAW,QAAQ,OAAO,YAAY,CAAC,GAAG;AACxC,UAAI,KAAK,WAAW,UAAU;AAC5B,iBAAS,KAAK;AAAA,UACZ,IAAI,KAAK;AAAA,UACT,MAAM,KAAK,QAAQ;AAAA,UACnB,OAAO,KAAK,SAAS;AAAA,UACrB,QAAQ,KAAK;AAAA,QACf,CAAC;AAAA,MACH;AAAA,IACF;AACA,gBAAY,OAAO;AAAA,EACrB,SAAS;AAET,SAAO;AACT;;;AC1BA,IAAM,sBAAsB,oBAAI,IAAI;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,aAAa,SAAuB;AAC3C,MAAI,WAAW;AACf,MAAI,OAAO;AACX,MAAI,SAAS;AACb,MAAI,MAAM;AACV,MAAI,iBAAiB;AACrB,MAAI,eAAe;AAEnB,aAAW,KAAK,SAAS;AACvB,QAAI,EAAE,WAAW,WAAW;AAC1B;AAAA,IACF,OAAO;AACL;AAAA,IACF;AACA,eAAW,KAAK,EAAE,UAAU;AAC1B,cAAQ,EAAE,UAAU;AAAA,QAClB,KAAK;AAAY;AAAY;AAAA,QAC7B,KAAK;AAAQ;AAAQ;AAAA,QACrB,KAAK;AAAU;AAAU;AAAA,QACzB,KAAK;AAAO;AAAO;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe,WAAW,OAAO,SAAS;AAAA,IAC1C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,uBACb,UACA,KACuB;AACvB,QAAM,UAAU,MAAM,QAAQ,WAAW,SAAS,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,CAAC,CAAC;AAEzE,SAAO,QAAQ,IAAI,CAAC,QAAQ,MAAM;AAChC,QAAI,OAAO,WAAW,aAAa;AAEjC,iBAAW,KAAK,OAAO,MAAM,UAAU;AACrC,YAAI,CAAC,EAAE,UAAW,GAAE,YAAY,IAAI;AACpC,YAAI,CAAC,EAAE,gBAAgB,IAAI,aAAc,GAAE,eAAe,IAAI;AAAA,MAChE;AACA,aAAO,OAAO;AAAA,IAChB;AACA,WAAO;AAAA,MACL,QAAQ,SAAS,CAAC,EAAE;AAAA,MACpB,QAAQ;AAAA,MACR,OAAO,OAAO,kBAAkB,QAAQ,OAAO,OAAO,UAAU,OAAO,OAAO,MAAM;AAAA,MACpF,kBAAkB;AAAA,MAClB,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,UAAU,CAAC;AAAA,IACb;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,eACpB,UACA,QACyB;AACzB,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AAGzC,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,aAAa,MAAM;AAAA,EACvC,QAAQ;AACN,gBAAY;AAAA,EACd;AAEA,QAAM,YAAY,aAAa,MAAM;AACrC,QAAM,MAAmB,EAAE,QAAQ,WAAW,UAAU;AAExD,QAAM,UAAU,MAAM,uBAAuB,UAAU,GAAG;AAE1D,QAAM,WAAU,oBAAI,KAAK,GAAE,YAAY;AAEvC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,aAAa,OAAO;AAAA,EAC/B;AACF;AAQA,eAAsB,wBACpB,UACA,QACA,MACyB;AACzB,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,QAAM,YAAY,aAAa,MAAM;AAGrC,MAAI;AACJ,MAAI;AACF,qBAAiB,MAAM,aAAa,MAAM;AAAA,EAC5C,QAAQ;AACN,qBAAiB;AAAA,EACnB;AAGA,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,gBAAgB,MAAM;AAAA,EACzC,SAAS,KAAK;AACZ,UAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAE9D,UAAM,SAAS,MAAM,eAAe,UAAU,MAAM;AACpD,QAAI,OAAO,QAAQ,SAAS,GAAG;AAC7B,UAAI,CAAC,OAAO,QAAQ,CAAC,EAAE,SAAU,QAAO,QAAQ,CAAC,EAAE,WAAW,CAAC;AAC/D,aAAO,QAAQ,CAAC,EAAE,SAAS,QAAQ,sDAAsD,MAAM,kCAAkC;AAAA,IACnI;AACA,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,YAAY,QAAQ;AAC3B,UAAM,QAAQ,IAAI,IAAI,KAAK,UAAU;AACrC,eAAW,SAAS,OAAO,CAAC,MAAM,MAAM,IAAI,EAAE,EAAE,CAAC;AAAA,EACnD;AAGA,QAAM,sBAAsB,SAAS,OAAO,CAAC,MAAM,oBAAoB,IAAI,EAAE,UAAU,CAAC;AACxF,QAAM,qBAAqB,SAAS,OAAO,CAAC,MAAM,CAAC,oBAAoB,IAAI,EAAE,UAAU,CAAC;AAExF,QAAM,aAA2B,CAAC;AAGlC,MAAI,oBAAoB,SAAS,GAAG;AAClC,UAAM,WAAwB,EAAE,QAAQ,WAAW,WAAW,eAAe;AAC7E,UAAM,aAAa,MAAM,uBAAuB,qBAAqB,QAAQ;AAC7E,eAAW,KAAK,GAAG,UAAU;AAAA,EAC/B;AAGA,aAAW,WAAW,UAAU;AAC9B,QAAI;AACJ,QAAI,eAAe,QAAQ;AAG3B,QAAI,QAAQ,OAAO,gBAAgB;AACjC,UAAI;AACF,cAAM,UAAU,aAAa,QAAQ,IAAI,KAAK,UAAU,SAAS;AACjE,sBAAc,MAAM,WAAW,SAAS,MAAM;AAAA,MAChD,SAAS,KAAK;AAEZ,mBAAW,KAAK;AAAA,UACd,QAAQ,eAAe,QAAQ,EAAE;AAAA,UACjC,QAAQ;AAAA,UACR,OAAO,oCAAoC,QAAQ,EAAE,KAAK,QAAQ,IAAI,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,UAC5H,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY;AAAA,UACZ,UAAU,CAAC;AAAA,QACb,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAEA,UAAM,MAAmB;AAAA,MACvB;AAAA,MACA;AAAA,MACA,WAAW,QAAQ;AAAA,MACnB;AAAA,MACA;AAAA,IACF;AAEA,UAAM,iBAAiB,MAAM,uBAAuB,oBAAoB,GAAG;AAC3E,eAAW,KAAK,GAAG,cAAc;AAAA,EACnC;AAEA,QAAM,WAAU,oBAAI,KAAK,GAAE,YAAY;AAGvC,MAAI,KAAK,YAAY,QAAQ;AAC3B,UAAM,QAAQ,IAAI,IAAI,KAAK,UAAU;AACrC,eAAW,OAAO,YAAY;AAC5B,UAAI,oBAAoB,IAAI,IAAI,MAAM,GAAG;AACvC,YAAI,WAAW,IAAI,SAAS,OAAO,CAAC,MAAM,CAAC,EAAE,aAAa,MAAM,IAAI,EAAE,SAAS,CAAC;AAChF,YAAI,gBAAgB,IAAI,SAAS;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,SAAS;AAAA,IACT,SAAS,aAAa,UAAU;AAAA,EAClC;AACF;;;AC5NA;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;;;ACrBA,SAAS,kBAAkB,OAAyB;AACzD,MAAI,SAAS,EAAK,QAAO;AACzB,MAAI,SAAS,EAAK,QAAO;AACzB,MAAI,SAAS,EAAK,QAAO;AACzB,SAAO;AACT;AAEO,SAAS,qBAAqB,UAA8B;AACjE,UAAQ,UAAU;AAAA,IAChB,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAO,aAAO;AAAA,EACrB;AACF;;;AD2BA,SAAS,YAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAEA,SAAS,eAAe,KAAuB;AAC7C,MAAI,EAAE,eAAe,OAAQ,QAAO;AACpC,QAAM,OAAQ,IAAkC,QAAQ;AACxD,QAAM,OAAQ,IAAkC,QAAQ;AACxD,SACE,SAAS,2BACT,SAAS,wBACT,SAAS,kBACT,SAAS,2BACT,SAAS,kBACT,SAAS;AAAA,GAER,IAAI,SAAS,SAAS,8BAA8B,KAAK,WACzD,IAAI,SAAS,SAAS,eAAe,KAAK;AAE/C;AAEA,SAAS,aAAa,KAAuB;AAC3C,MAAI,EAAE,eAAe,OAAQ,QAAO;AACpC,SACE,IAAI,SAAS;AAAA,EACb,IAAI,SAAS,uBACb,IAAI,QAAQ,SAAS,aAAa,KAClC,IAAI,QAAQ,SAAS,gBAAgB;AAEzC;AAEA,SAAS,qBACP,cACyD;AACzD,MAAI,gBAAgB,EAAG,QAAO;AAC9B,MAAI,gBAAgB,EAAG,QAAO;AAC9B,MAAI,gBAAgB,EAAG,QAAO;AAC9B,SAAO;AACT;AAEO,IAAM,0BAAN,MAAiD;AAAA,EAC7C,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,UAAM,WAA4B,CAAC;AAGnC,QAAI;AACF,YAAM,KAAK,aAAa,kBAAkB,QAAQ,IAAI,WAAW;AACjE,YAAM,OAAO,MAAM,GAAG,KAAK,IAAI,sBAAsB,CAAC,CAAC,CAAC;AACxD,YAAM,SAAS,KAAK,aAAa,CAAC;AAClC,UAAI,OAAO,SAAS,GAAG;AACrB,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,GAAG,OAAO,MAAM;AAAA,QAC3B,CAAC;AAAA,MACH,OAAO;AACL,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,gBAAgB;AAAA,QAClB,CAAC;AAAA,MAEH;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,eAAe,GAAG,GAAG;AACvB,iBAAS,KAAK,sDAAsD;AACpE,iBAAS,KAAK,EAAE,MAAM,cAAc,SAAS,MAAM,SAAS,gBAAgB,CAAC;AAAA,MAC/E,WAAW,aAAa,GAAG,GAAG;AAC5B,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,gBAAgB;AAAA,QAClB,CAAC;AAAA,MAEH,OAAO;AACL,iBAAS,KAAK,gCAAgC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAChG,iBAAS,KAAK,EAAE,MAAM,cAAc,SAAS,MAAM,SAAS,kBAAkB,CAAC;AAAA,MACjF;AAAA,IACF;AAGA,QAAI;AACF,YAAM,KAAK,aAAa,mBAAmB,QAAQ,IAAI,WAAW;AAClE,YAAM,GAAG,KAAK,IAAI,mBAAmB,CAAC,CAAC,CAAC;AACxC,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,KAAK;AACZ,UAAI,eAAe,GAAG,GAAG;AACvB,iBAAS,KAAK,wDAAwD;AACtE,iBAAS,KAAK,EAAE,MAAM,gBAAgB,SAAS,MAAM,SAAS,gBAAgB,CAAC;AAAA,MACjF,WAAW,aAAa,GAAG,GAAG;AAC5B,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,oBAAoB;AAAA,QACtB,CAAC;AACD,iBAAS;AAAA,UACP,YAAY;AAAA,YACV,WAAW;AAAA,YACX,OAAO;AAAA,YACP,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,aAAa,OAAO,SAAS,gBAAgB,MAAM,IAAI,SAAS;AAAA,YAChE;AAAA,YACA,aACE;AAAA,YACF,QACE;AAAA,YACF,kBAAkB;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,iBAAS,KAAK,kCAAkC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAClG,iBAAS,KAAK,EAAE,MAAM,gBAAgB,SAAS,MAAM,SAAS,kBAAkB,CAAC;AAAA,MACnF;AAAA,IACF;AAGA,QAAI;AACF,YAAM,KAAK,aAAa,iBAAiB,QAAQ,IAAI,WAAW;AAChE,YAAM,OAAO,MAAM,GAAG,KAAK,IAAI,qBAAqB,CAAC,CAAC,CAAC;AACvD,YAAM,YAAY,KAAK,eAAe,CAAC;AACvC,UAAI,UAAU,SAAS,GAAG;AACxB,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,GAAG,UAAU,MAAM;AAAA,QAC9B,CAAC;AAAA,MACH,OAAO;AACL,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,oBAAoB;AAAA,QACtB,CAAC;AACD,iBAAS;AAAA,UACP,YAAY;AAAA,YACV,WAAW;AAAA,YACX,OAAO;AAAA,YACP,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,aAAa,OAAO,SAAS,cAAc,MAAM,IAAI,SAAS;AAAA,YAC9D;AAAA,YACA,aACE;AAAA,YACF,QACE;AAAA,YACF,kBAAkB;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,eAAe,GAAG,GAAG;AACvB,iBAAS,KAAK,qDAAqD;AACnE,iBAAS,KAAK,EAAE,MAAM,aAAa,SAAS,MAAM,SAAS,gBAAgB,CAAC;AAAA,MAC9E,WAAW,aAAa,GAAG,GAAG;AAC5B,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,oBAAoB;AAAA,QACtB,CAAC;AACD,iBAAS;AAAA,UACP,YAAY;AAAA,YACV,WAAW;AAAA,YACX,OAAO;AAAA,YACP,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,aAAa,OAAO,SAAS,cAAc,MAAM,IAAI,SAAS;AAAA,YAC9D;AAAA,YACA,aACE;AAAA,YACF,QACE;AAAA,YACF,kBAAkB;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,iBAAS,KAAK,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC/F,iBAAS,KAAK,EAAE,MAAM,aAAa,SAAS,MAAM,SAAS,kBAAkB,CAAC;AAAA,MAChF;AAAA,IACF;AAGA,QAAI;AACF,YAAM,OAAO,aAAa,kBAAkB,QAAQ,IAAI,WAAW;AACnE,YAAM,OAAO,MAAM,KAAK,KAAK,IAAI,6BAA6B,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC;AAC1F,YAAM,WAAW,KAAK,YAAY,CAAC;AACnC,YAAM,SAAS,SAAS;AAAA,QACtB,CAAC,MACC,EAAE,OAAO,WAAW,aACpB,EAAE,OAAO,WAAW;AAAA,MACxB;AACA,UAAI,QAAQ;AACV,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS;AAAA,QACX,CAAC;AAAA,MACH,OAAO;AACL,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,oBAAoB;AAAA,QACtB,CAAC;AACD,iBAAS;AAAA,UACP,YAAY;AAAA,YACV,WAAW;AAAA,YACX,OAAO;AAAA,YACP,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,aAAa,OAAO,SAAS,eAAe,MAAM,IAAI,SAAS;AAAA,YAC/D;AAAA,YACA,aACE;AAAA,YACF,QACE;AAAA,YACF,kBAAkB;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,eAAe,GAAG,GAAG;AACvB,iBAAS,KAAK,qDAAqD;AACnE,iBAAS,KAAK,EAAE,MAAM,aAAa,SAAS,MAAM,SAAS,gBAAgB,CAAC;AAAA,MAC9E,WAAW,aAAa,GAAG,GAAG;AAC5B,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,oBAAoB;AAAA,QACtB,CAAC;AACD,iBAAS;AAAA,UACP,YAAY;AAAA,YACV,WAAW;AAAA,YACX,OAAO;AAAA,YACP,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,aAAa,OAAO,SAAS,eAAe,MAAM,IAAI,SAAS;AAAA,YAC/D;AAAA,YACA,aACE;AAAA,YACF,QACE;AAAA,YACF,kBAAkB;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,iBAAS,KAAK,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC/F,iBAAS,KAAK,EAAE,MAAM,aAAa,SAAS,MAAM,SAAS,kBAAkB,CAAC;AAAA,MAChF;AAAA,IACF;AAGA,QAAI;AACF,YAAM,MAAM,aAAa,qBAAqB,QAAQ,IAAI,WAAW;AACrE,YAAM,OAAO,MAAM,IAAI,KAAK,IAAI,sCAAsC,CAAC,CAAC,CAAC;AACzE,YAAM,YAAY,KAAK,0BAA0B,CAAC;AAClD,UAAI,UAAU,SAAS,GAAG;AACxB,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS,GAAG,UAAU,MAAM;AAAA,QAC9B,CAAC;AAAA,MACH,OAAO;AACL,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,gBAAgB;AAAA,QAClB,CAAC;AACD,iBAAS;AAAA,UACP,YAAY;AAAA,YACV,WAAW;AAAA,YACX,OAAO;AAAA,YACP,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,aAAa,OAAO,SAAS,WAAW,MAAM,IAAI,SAAS;AAAA,YAC3D;AAAA,YACA,aACE;AAAA,YACF,QACE;AAAA,YACF,kBAAkB;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,eAAe,GAAG,GAAG;AACvB,iBAAS,KAAK,sDAAsD;AACpE,iBAAS,KAAK,EAAE,MAAM,cAAc,SAAS,MAAM,SAAS,gBAAgB,CAAC;AAAA,MAC/E,WAAW,aAAa,GAAG,GAAG;AAC5B,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,gBAAgB;AAAA,QAClB,CAAC;AACD,iBAAS;AAAA,UACP,YAAY;AAAA,YACV,WAAW;AAAA,YACX,OAAO;AAAA,YACP,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,aAAa,OAAO,SAAS,WAAW,MAAM,IAAI,SAAS;AAAA,YAC3D;AAAA,YACA,aACE;AAAA,YACF,QACE;AAAA,YACF,kBAAkB;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,iBAAS,KAAK,gCAAgC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAChG,iBAAS,KAAK,EAAE,MAAM,cAAc,SAAS,MAAM,SAAS,kBAAkB,CAAC;AAAA,MACjF;AAAA,IACF;AAGA,QAAI,OAAO,WAAW,KAAK,GAAG;AAC5B,eAAS,KAAK,EAAE,MAAM,SAAS,SAAS,MAAM,SAAS,iCAAiC,CAAC;AACzF,eAAS,KAAK,8CAA8C;AAAA,IAC9D,OAAO;AACL,UAAI;AACF,cAAM,KAAK,aAAa,cAAc,QAAQ,IAAI,WAAW;AAC7D,cAAM,GAAG,KAAK,IAAI,uBAAuB,CAAC,CAAC,CAAC;AAC5C,iBAAS,KAAK;AAAA,UACZ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS;AAAA,QACX,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,YAAI,eAAe,GAAG,GAAG;AACvB,mBAAS,KAAK,iDAAiD;AAC/D,mBAAS,KAAK,EAAE,MAAM,SAAS,SAAS,MAAM,SAAS,gBAAgB,CAAC;AAAA,QAC1E,WAAW,aAAa,GAAG,GAAG;AAC5B,mBAAS,KAAK;AAAA,YACZ,MAAM;AAAA,YACN,SAAS;AAAA,YACT,gBAAgB;AAAA,YAChB,oBAAoB;AAAA,UACtB,CAAC;AACD,mBAAS;AAAA,YACP,YAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO;AAAA,cACP,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa,OAAO,SAAS,WAAW,MAAM,IAAI,SAAS;AAAA,cAC3D;AAAA,cACA,aACE;AAAA,cACF,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,OAAO;AACL,mBAAS,KAAK,2BAA2B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAC3F,mBAAS,KAAK,EAAE,MAAM,SAAS,SAAS,MAAM,SAAS,kBAAkB,CAAC;AAAA,QAC5E;AAAA,MACF;AAAA,IACF;AAGA,UAAM,gBAAgB,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI;AAC/D,UAAM,eAAe,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE;AAChE,UAAM,kBAAkB,cAAc,SAAS,IAAI,KAAK,MAAO,eAAe,cAAc,SAAU,GAAG,IAAI;AAC7G,UAAM,gBAAgB,qBAAqB,YAAY;AAEvD,UAAM,kBAA0C;AAAA,MAC9C;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL,QAAQ,KAAK;AAAA,MACb,QAAQ;AAAA,MACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,MAC3C,kBAAkB,SAAS;AAAA,MAC3B,eAAe,SAAS;AAAA,MACxB,YAAY,KAAK,IAAI,IAAI;AAAA,MACzB;AAAA;AAAA,MAEA,GAAI,EAAE,kBAAkB,gBAAgB;AAAA,IAC1C;AAAA,EACF;AACF;;;AE5eA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAMP,IAAM,kBAAyF;AAAA,EAC7F,EAAE,MAAM,kBAAkB,SAAS,oBAAoB,WAAW,QAAQ;AAAA,EAC1E,EAAE,MAAM,eAAe,SAAS,gCAAgC,WAAW,QAAQ;AAAA,EACnF,EAAE,MAAM,uBAAuB,SAAS,2EAA2E,WAAW,OAAO;AACvI;AAEA,SAASC,aAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAEO,IAAM,wBAAN,MAA+C;AAAA,EAC3C,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AAEF,UAAI;AACF,cAAM,SAAS,aAAa,cAAc,QAAQ,IAAI,WAAW;AACjE,cAAM,YAAqC,CAAC;AAC5C,YAAI;AACJ,WAAG;AACD,gBAAM,OAAO,MAAM,OAAO;AAAA,YACxB,IAAI,qBAAqB,EAAE,QAAQ,OAAO,CAAC;AAAA,UAC7C;AACA,cAAI,KAAK,UAAW,WAAU,KAAK,GAAG,KAAK,SAAS;AACpD,mBAAS,KAAK;AAAA,QAChB,SAAS;AAET,4BAAoB,UAAU;AAE9B,mBAAW,MAAM,WAAW;AAC1B,gBAAM,SAAS,GAAG,gBAAgB;AAClC,gBAAM,QACJ,GAAG,eACH,OAAO,SAAS,WAAW,MAAM,IAAI,SAAS,aAAa,MAAM;AACnE,gBAAM,UAAU,GAAG,aAAa,aAAa,CAAC;AAE9C,qBAAW,CAAC,SAAS,QAAQ,KAAK,OAAO,QAAQ,OAAO,GAAG;AACzD,uBAAW,MAAM,iBAAiB;AAChC,kBAAI,GAAG,cAAc,QAAQ;AAC3B,oBAAI,GAAG,QAAQ,KAAK,OAAO,GAAG;AAC5B,2BAAS;AAAA,oBACPA,aAAY;AAAA,sBACV,WAAW;AAAA,sBACX,OAAO,UAAU,MAAM,4BAA4B,OAAO;AAAA,sBAC1D,cAAc;AAAA,sBACd,YAAY;AAAA,sBACZ,aAAa;AAAA,sBACb;AAAA,sBACA,aAAa,oBAAoB,MAAM,wCAAwC,OAAO;AAAA,sBACtF,QACE;AAAA,sBACF,kBAAkB;AAAA,wBAChB;AAAA,wBACA;AAAA,wBACA;AAAA,sBACF;AAAA,oBACF,CAAC;AAAA,kBACH;AAAA,gBACF;AAAA,cACF,OAAO;AAEL,oBAAI,GAAG,QAAQ,KAAK,QAAQ,GAAG;AAC7B,wBAAM,YAAY,GAAG,SAAS,mBAAmB,MAAM;AACvD,2BAAS;AAAA,oBACPA,aAAY;AAAA,sBACV;AAAA,sBACA,OAAO,UAAU,MAAM,qBAAqB,GAAG,IAAI;AAAA,sBACnD,cAAc;AAAA,sBACd,YAAY;AAAA,sBACZ,aAAa;AAAA,sBACb;AAAA,sBACA,aAAa,oBAAoB,MAAM,8CAA8C,GAAG,IAAI;AAAA,sBAC5F,QACE;AAAA,sBACF,kBAAkB;AAAA,wBAChB;AAAA,wBACA;AAAA,wBACA;AAAA,wBACA;AAAA,sBACF;AAAA,oBACF,CAAC;AAAA,kBACH;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,GAAY;AACnB,iBAAS,KAAK,sBAAsB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,EAAE;AAAA,MAClF;AAGA,UAAI;AACF,cAAM,MAAM,aAAa,WAAW,QAAQ,IAAI,WAAW;AAC3D,cAAM,YAAwB,CAAC;AAC/B,YAAI;AACJ,WAAG;AACD,gBAAM,OAAO,MAAM,IAAI;AAAA,YACrB,IAAI,yBAAyB,EAAE,WAAW,UAAU,CAAC;AAAA,UACvD;AACA,qBAAW,OAAO,KAAK,gBAAgB,CAAC,GAAG;AACzC,gBAAI,IAAI,UAAW,WAAU,KAAK,GAAG,IAAI,SAAS;AAAA,UACpD;AACA,sBAAY,KAAK;AAAA,QACnB,SAAS;AAET,4BAAoB,UAAU;AAE9B,mBAAW,QAAQ,WAAW;AAC5B,gBAAM,SAAS,KAAK,cAAc;AAClC,gBAAM,UAAU,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,aAAa,MAAM;AAE9E,cAAI;AACJ,cAAI;AACF,kBAAM,WAAW,MAAM,IAAI;AAAA,cACzB,IAAI,iCAAiC;AAAA,gBACnC,YAAY;AAAA,gBACZ,WAAW;AAAA,cACb,CAAC;AAAA,YACH;AACA,kBAAM,MAAM,SAAS,UAAU;AAC/B,gBAAI,KAAK;AACP,yBAAW,OAAO,KAAK,KAAK,QAAQ,EAAE,SAAS,OAAO;AAAA,YACxD;AAAA,UACF,SAAS,GAAY;AACnB,qBAAS,KAAK,+BAA+B,MAAM,KAAK,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,EAAE;AACpG;AAAA,UACF;AAEA,cAAI,CAAC,SAAU;AAEf,qBAAW,MAAM,iBAAiB;AAChC,gBAAI,GAAG,cAAc,OAAQ;AAC7B,gBAAI,GAAG,QAAQ,KAAK,QAAQ,GAAG;AAC7B,oBAAM,YAAY,GAAG,SAAS,mBAAmB,MAAM;AACvD,uBAAS;AAAA,gBACPA,aAAY;AAAA,kBACV;AAAA,kBACA,OAAO,OAAO,MAAM,sBAAsB,GAAG,IAAI;AAAA,kBACjD,cAAc;AAAA,kBACd,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb;AAAA,kBACA,aAAa,iBAAiB,MAAM,gCAAgC,GAAG,IAAI;AAAA,kBAC3E,QACE;AAAA,kBACF,kBAAkB;AAAA,oBAChB;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,GAAY;AACnB,iBAAS,KAAK,4BAA4B,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,EAAE;AAAA,MACxF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;ACzNA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAMP,SAASC,aAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAEO,IAAM,wBAAN,MAA+C;AAAA,EAC3C,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAE5B,QAAI;AACF,YAAM,SAAS,aAAa,WAAW,QAAQ,IAAI,WAAW;AAG9D,YAAM,QAA8B,CAAC;AACrC,UAAI;AACJ,SAAG;AACD,cAAM,OAAO,MAAM,OAAO;AAAA,UACxB,IAAI,wBAAwB,EAAE,WAAW,UAAU,CAAC;AAAA,QACtD;AACA,YAAI,KAAK,wBAAwB;AAC/B,gBAAM,KAAK,GAAG,KAAK,sBAAsB;AAAA,QAC3C;AACA,oBAAY,KAAK;AAAA,MACnB,SAAS;AAET,iBAAW,QAAQ,OAAO;AACxB,cAAM,UAAU,KAAK,kBAAkB;AACvC,cAAM,aAAa,KAAK,cAAc;AAEtC,YAAI;AACJ,YAAI;AACF,gBAAM,WAAW,MAAM,OAAO;AAAA,YAC5B,IAAI,2BAA2B,EAAE,gBAAgB,QAAQ,CAAC;AAAA,UAC5D;AACA,mBAAS,SAAS;AAAA,QACpB,SAAS,GAAY;AACnB,mBAAS,KAAK,kCAAkC,OAAO,KAAK,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,EAAE;AACxG;AAAA,QACF;AAEA,YAAI,CAAC,OAAQ;AAEb,cAAM,SAAS,OAAO,UAAU;AAChC,cAAM,UAAU,OAAO,WAAW,CAAC;AACnC,cAAM,WAAW,QAAQ,SAAS,IAAI,cAAc,QAAQ,MAAM,kBAAkB;AAGpF,YAAI,WAAW,UAAU;AACvB,mBAAS;AAAA,YACPA,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,mBAAmB,UAAU;AAAA,cACpC,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb;AAAA,cACA,aAAa,wBAAwB,UAAU,uBAAuB,QAAQ;AAAA,cAC9E,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AACA;AAAA,QACF;AAGA,YAAI,WAAW,YAAY,OAAO,UAAU;AAC1C,gBAAM,MAAM,oBAAI,KAAK;AACrB,gBAAM,aAAa,IAAI,KAAK,OAAO,QAAQ;AAC3C,gBAAM,kBAAkB,KAAK;AAAA,aAC1B,WAAW,QAAQ,IAAI,IAAI,QAAQ,MAAM,MAAO,KAAK,KAAK;AAAA,UAC7D;AAEA,cAAI,kBAAkB,GAAG;AACvB,qBAAS;AAAA,cACPA,aAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,mBAAmB,UAAU;AAAA,gBACpC,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,wBAAwB,UAAU,aAAa,KAAK,IAAI,eAAe,CAAC,aAAa,QAAQ;AAAA,gBAC1G,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF,WAAW,kBAAkB,IAAI;AAC/B,qBAAS;AAAA,cACPA,aAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,mBAAmB,UAAU,eAAe,eAAe;AAAA,gBAClE,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,wBAAwB,UAAU,gBAAgB,eAAe,UAAU,WAAW,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,QAAQ;AAAA,gBAC3I,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF,WAAW,kBAAkB,IAAI;AAC/B,qBAAS;AAAA,cACPA,aAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,mBAAmB,UAAU,eAAe,eAAe;AAAA,gBAClE,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,wBAAwB,UAAU,gBAAgB,eAAe,UAAU,WAAW,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,QAAQ;AAAA,gBAC3I,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB,MAAM;AAAA,QACxB,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AC1LA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY,WAAW;AAMhC,SAASC,aAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAEA,SAAS,oBAAoB,QAA+B;AAG1D,QAAM,YAAY;AAClB,QAAM,IAAI,OAAO,MAAM,SAAS;AAChC,SAAO,IAAI,EAAE,CAAC,IAAI;AACpB;AAEA,SAAS,eAAe,QAAoD;AAC1E,MAAI,2CAA2C,KAAK,MAAM,EAAG,QAAO;AACpE,MAAI,mCAAmC,KAAK,MAAM,EAAG,QAAO;AAC5D,MAAI,wBAAwB,KAAK,MAAM,EAAG,QAAO;AACjD,SAAO;AACT;AAEA,eAAe,YAAY,UAAoC;AAC7D,MAAI;AAEF,UAAM,IAAI,SAAS,SAAS,GAAG,IAAI,SAAS,MAAM,GAAG,EAAE,IAAI;AAC3D,UAAM,IAAI,QAAQ,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,qBAAN,MAA4C;AAAA,EACxC,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AACF,YAAM,UAAU,aAAa,eAAe,QAAQ,IAAI,WAAW;AAGnE,YAAM,QAAsB,CAAC;AAC7B,UAAI;AACJ,SAAG;AACD,cAAM,OAAO,MAAM,QAAQ;AAAA,UACzB,IAAI,uBAAuB,EAAE,QAAQ,OAAO,CAAC;AAAA,QAC/C;AACA,YAAI,KAAK,YAAa,OAAM,KAAK,GAAG,KAAK,WAAW;AACpD,iBAAS,KAAK,cAAc,KAAK,aAAa;AAAA,MAChD,SAAS;AAET,iBAAW,QAAQ,OAAO;AACxB,cAAM,SAAS,KAAK,MAAM;AAC1B,cAAM,WAAW,KAAK,QAAQ;AAC9B,cAAM,cAAc,OAAO,QAAQ,gBAAgB,EAAE;AAGrD,cAAM,UAA+B,CAAC;AACtC,YAAI;AACJ,YAAI;AACJ,WAAG;AACD,gBAAM,OAAO,MAAM,QAAQ;AAAA,YACzB,IAAI,8BAA8B;AAAA,cAChC,cAAc;AAAA,cACd,iBAAiB;AAAA,cACjB,iBAAiB;AAAA,YACnB,CAAC;AAAA,UACH;AACA,cAAI,KAAK,mBAAoB,SAAQ,KAAK,GAAG,KAAK,kBAAkB;AACpE,cAAI,KAAK,aAAa;AACpB,uBAAW,KAAK;AAChB,uBAAW,KAAK;AAAA,UAClB,OAAO;AACL,uBAAW;AACX,uBAAW;AAAA,UACb;AAAA,QACF,SAAS;AAGT,cAAM,eAAe,QAAQ;AAAA,UAC3B,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,mBAAmB,EAAE,gBAAgB,SAAS;AAAA,QAC/E;AAEA,4BAAoB,aAAa;AAEjC,mBAAW,UAAU,cAAc;AACjC,gBAAM,aAAa,OAAO,QAAQ;AAClC,gBAAM,SAAS,OAAO,gBAAiB,CAAC,EAAE,SAAS;AACnD,gBAAM,YAAY,OAAO,SAAS,yBAAyB,WAAW;AACtE,gBAAM,aAAa,eAAe,MAAM;AAExC,cAAI,eAAe,MAAM;AAEvB,kBAAM,aAAa,oBAAoB,MAAM;AAC7C,gBAAI,YAAY;AACd,kBAAI,eAAe;AACnB,kBAAI;AACF,sBAAM,KAAK,aAAa,UAAU,QAAQ,IAAI,WAAW;AACzD,sBAAM,GAAG,KAAK,IAAI,kBAAkB,EAAE,QAAQ,WAAW,CAAC,CAAC;AAC3D,+BAAe;AAAA,cACjB,SAAS,GAAY;AACnB,sBAAM,UAAW,EAAwB,QAAQ;AAEjD,oBAAI,YAAY,eAAe,YAAY,kBAAkB,YAAY,OAAO;AAC9E,iCAAe;AAAA,gBACjB;AAAA,cACF;AAEA,kBAAI,CAAC,cAAc;AACjB,yBAAS;AAAA,kBACPA,aAAY;AAAA,oBACV,WAAW;AAAA,oBACX,OAAO,SAAS,UAAU,sCAAsC,UAAU;AAAA,oBAC1E,cAAc;AAAA,oBACd,YAAY;AAAA,oBACZ,aAAa;AAAA,oBACb;AAAA,oBACA,aAAa,eAAe,UAAU,cAAc,QAAQ,+BAA+B,UAAU;AAAA,oBACrG,QACE;AAAA,oBACF,kBAAkB;AAAA,sBAChB;AAAA,sBACA;AAAA,sBACA;AAAA,oBACF;AAAA,kBACF,CAAC;AAAA,gBACH;AAAA,cACF;AAAA,YACF;AAAA,UACF,WAAW,eAAe,OAAO;AAC/B,kBAAM,WAAW,MAAM,YAAY,MAAM;AACzC,gBAAI,CAAC,UAAU;AACb,uBAAS;AAAA,gBACPA,aAAY;AAAA,kBACV,WAAW;AAAA,kBACX,OAAO,SAAS,UAAU;AAAA,kBAC1B,cAAc;AAAA,kBACd,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb;AAAA,kBACA,aAAa,eAAe,UAAU,cAAc,QAAQ,yBAAyB,MAAM;AAAA,kBAC3F,QACE;AAAA,kBACF,kBAAkB;AAAA,oBAChB;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF,WAAW,eAAe,cAAc;AACtC,kBAAM,WAAW,MAAM,YAAY,MAAM;AACzC,gBAAI,CAAC,UAAU;AACb,uBAAS;AAAA,gBACPA,aAAY;AAAA,kBACV,WAAW;AAAA,kBACX,OAAO,SAAS,UAAU;AAAA,kBAC1B,cAAc;AAAA,kBACd,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb;AAAA,kBACA,aAAa,eAAe,UAAU,cAAc,QAAQ,gCAAgC,MAAM;AAAA,kBAClG,QACE;AAAA,kBACF,kBAAkB;AAAA,oBAChB;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF,WAAW,eAAe,MAAM;AAE9B,kBAAM,WAAW,MAAM,YAAY,MAAM;AACzC,gBAAI,CAAC,UAAU;AACb,uBAAS;AAAA,gBACPA,aAAY;AAAA,kBACV,WAAW;AAAA,kBACX,OAAO,SAAS,UAAU;AAAA,kBAC1B,cAAc;AAAA,kBACd,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb;AAAA,kBACA,aAAa,eAAe,UAAU,cAAc,QAAQ,qBAAqB,MAAM;AAAA,kBACvF,QACE;AAAA,kBACF,kBAAkB;AAAA,oBAChB;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AC7PA;AAAA,EACE,aAAAC;AAAA,EACA,4BAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAMK;AAMP,IAAM,kBAA0C;AAAA,EAC9C,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,SAASC,aAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAEA,SAAS,aAAa,KAAsB,MAAuB;AACjE,aAAW,MAAM,KAAK;AACpB,eAAW,QAAQ,GAAG,iBAAiB,CAAC,GAAG;AACzC,UAAI,0BAA0B,MAAM,IAAI,EAAG,QAAO;AAAA,IACpD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,KAA+B;AACvD,aAAW,MAAM,KAAK;AACpB,eAAW,QAAQ,GAAG,iBAAiB,CAAC,GAAG;AACzC,UAAI,WAAW,IAAI,KAAK,aAAa,IAAI,EAAG,QAAO;AAAA,IACrD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,0BAA0B,MAAoB,MAAuB;AAC5E,MAAI,CAAC,aAAa,IAAI,EAAG,QAAO;AAChC,QAAM,OAAO,KAAK,YAAY;AAC9B,QAAM,KAAK,KAAK,UAAU;AAC1B,MAAI,SAAS,MAAM,OAAO,GAAI,QAAO;AACrC,SAAO,QAAQ,QAAQ,QAAQ;AACjC;AAEA,SAAS,aAAa,MAA6B;AACjD,QAAM,WAAW,KAAK,YAAY,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,WAAW,WAAW;AAC1E,QAAM,WAAW,KAAK,cAAc,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,aAAa,MAAM;AACzE,SAAO,WAAW;AACpB;AAEA,SAAS,WAAW,MAA6B;AAC/C,QAAM,OAAO,KAAK,YAAY;AAC9B,QAAM,KAAK,KAAK,UAAU;AAC1B,SAAQ,SAAS,MAAM,OAAO,MAAQ,SAAS,KAAK,OAAO;AAC7D;AAEA,SAAS,eAAe,MAAkB,MAAuB;AAG/D,QAAM,gBAAgB,KAAK,WAAW,CAAC,GACpC,OAAO,CAAC,MAAM,EAAE,WAAW,KAAK,EAChC,KAAK,CAAC,GAAG,OAAO,EAAE,cAAc,MAAM,EAAE,cAAc,EAAE;AAE3D,aAAW,QAAQ,cAAc;AAC/B,QAAI,oBAAoB,MAAM,IAAI,KAAK,yBAAyB,IAAI,GAAG;AAErE,aAAO,KAAK,eAAe;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,oBAAoB,MAAuB,MAAuB;AAEzE,MAAI,KAAK,aAAa,KAAM,QAAO;AAEnC,MAAI,KAAK,aAAa,OAAO,KAAK,aAAa,KAAM,QAAO;AAC5D,QAAM,OAAO,KAAK,WAAW,QAAQ;AACrC,QAAM,KAAK,KAAK,WAAW,MAAM;AACjC,SAAO,QAAQ,QAAQ,QAAQ;AACjC;AAEA,SAAS,yBAAyB,MAAgC;AAChE,SAAO,KAAK,cAAc,eAAe,KAAK,kBAAkB;AAClE;AAEO,IAAM,6BAAN,MAAoD;AAAA,EAChD,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAE5B,QAAI;AACF,YAAM,SAAS,aAAaC,YAAW,QAAQ,IAAI,WAAW;AAG9D,YAAM,SAAS,oBAAI,IAAoB;AACvC,UAAI;AACF,cAAM,UAAU,MAAM,OAAO,KAAK,IAAI,yBAAyB,CAAC,CAAC,CAAC;AAClE,mBAAW,QAAQ,QAAQ,aAAa,CAAC,GAAG;AAC1C,cAAI,KAAK,cAAc,KAAK,UAAU;AACpC,mBAAO,IAAI,KAAK,YAAY,KAAK,QAAQ;AAAA,UAC3C;AAAA,QACF;AAAA,MACF,SAAS,GAAY;AACnB,iBAAS,KAAK,+BAA+B,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC,EAAE;AAAA,MAC3F;AAGA,YAAM,YAAwB,CAAC;AAC/B,UAAI;AACJ,SAAG;AACD,cAAM,OAAO,MAAM,OAAO;AAAA,UACxB,IAAIC,0BAAyB,EAAE,WAAW,UAAU,CAAC;AAAA,QACvD;AACA,mBAAW,OAAO,KAAK,gBAAgB,CAAC,GAAG;AACzC,cAAI,IAAI,UAAW,WAAU,KAAK,GAAG,IAAI,SAAS;AAAA,QACpD;AACA,oBAAY,KAAK;AAAA,MACnB,SAAS;AAGT,YAAM,kBAAkB,UAAU,OAAO,CAAC,SAAS;AACjD,cAAM,SAAS,KAAK,cAAc;AAClC,eAAO,KAAK,mBAAmB,OAAO,IAAI,MAAM;AAAA,MAClD,CAAC;AAGD,YAAM,QAAQ,oBAAI,IAAY;AAC9B,YAAM,YAAY,oBAAI,IAAY;AAClC,iBAAW,QAAQ,iBAAiB;AAClC,mBAAW,MAAM,KAAK,kBAAkB,CAAC,GAAG;AAC1C,cAAI,GAAG,QAAS,OAAM,IAAI,GAAG,OAAO;AAAA,QACtC;AACA,YAAI,KAAK,SAAU,WAAU,IAAI,KAAK,QAAQ;AAAA,MAChD;AAGA,YAAM,QAAQ,oBAAI,IAA2B;AAC7C,UAAI,MAAM,OAAO,GAAG;AAClB,cAAM,SAAS,MAAM,OAAO;AAAA,UAC1B,IAAI,8BAA8B;AAAA,YAChC,UAAU,CAAC,GAAG,KAAK;AAAA,UACrB,CAAC;AAAA,QACH;AACA,mBAAW,MAAM,OAAO,kBAAkB,CAAC,GAAG;AAC5C,cAAI,GAAG,QAAS,OAAM,IAAI,GAAG,SAAS,EAAE;AAAA,QAC1C;AAAA,MACF;AAGA,YAAM,gBAAgB,oBAAI,IAAwB;AAClD,UAAI,UAAU,OAAO,GAAG;AACtB,YAAI;AACJ,cAAM,WAAyB,CAAC;AAChC,WAAG;AACD,gBAAM,WAAW,MAAM,OAAO;AAAA,YAC5B,IAAI,2BAA2B;AAAA,cAC7B,SAAS,CAAC,EAAE,MAAM,yBAAyB,QAAQ,CAAC,GAAG,SAAS,EAAE,CAAC;AAAA,cACnE,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AACA,cAAI,SAAS,YAAa,UAAS,KAAK,GAAG,SAAS,WAAW;AAC/D,sBAAY,SAAS;AAAA,QACvB,SAAS;AAET,mBAAW,QAAQ,UAAU;AAC3B,qBAAW,SAAS,KAAK,gBAAgB,CAAC,GAAG;AAC3C,gBAAI,MAAM,UAAU;AAClB,4BAAc,IAAI,MAAM,UAAU,IAAI;AAAA,YACxC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,iBAAW,QAAQ,iBAAiB;AAClC,cAAM,SAAS,KAAK,cAAc;AAClC,cAAM,UAAU,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,aAAa,MAAM;AAC9E,cAAM,WAAW,KAAK,mBAAmB,OAAO,IAAI,MAAM,KAAK;AAC/D,cAAM,WAAW,KAAK,YAAY;AAGlC,cAAM,UAA2B,CAAC;AAClC,mBAAW,MAAM,KAAK,kBAAkB,CAAC,GAAG;AAC1C,cAAI,GAAG,SAAS;AACd,kBAAM,SAAS,MAAM,IAAI,GAAG,OAAO;AACnC,gBAAI,OAAQ,SAAQ,KAAK,MAAM;AAAA,UACjC;AAAA,QACF;AAEA,cAAM,OAAO,cAAc,IAAI,QAAQ;AAGvC,mBAAW,CAAC,SAAS,QAAQ,KAAK,OAAO,QAAQ,eAAe,GAAG;AACjE,gBAAM,OAAO,OAAO,OAAO;AAC3B,gBAAM,WAAW,aAAa,SAAS,IAAI;AAC3C,gBAAM,aAAa,OAAO,eAAe,MAAM,IAAI,IAAI;AAEvD,cAAI,YAAY,YAAY;AAC1B,qBAAS;AAAA,cACPF,aAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,OAAO,MAAM,KAAK,QAAQ,MAAM,QAAQ,KAAK,IAAI;AAAA,gBACxD,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,iBAAiB,MAAM,mBAAmB,QAAQ,iEAAiE,QAAQ,UAAU,IAAI;AAAA,gBACtJ,QACE,GAAG,QAAQ;AAAA,gBACb,kBAAkB;AAAA,kBAChB,kDAAkD,IAAI;AAAA,kBACtD;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF,WAAW,YAAY,CAAC,YAAY;AAClC,qBAAS;AAAA,cACPA,aAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,OAAO,MAAM,KAAK,QAAQ,KAAK,IAAI;AAAA,gBAC1C,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,iBAAiB,MAAM,MAAM,QAAQ,uCAAuC,QAAQ,UAAU,IAAI;AAAA,gBAC/G,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB,6CAA6C,IAAI;AAAA,kBACjD;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAGA,YAAI,iBAAiB,OAAO,GAAG;AAE7B,gBAAM,WAAW,OAAO,eAAe,MAAM,EAAE,IAAI;AACnD,cAAI,UAAU;AACZ,qBAAS;AAAA,cACPA,aAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,OAAO,MAAM,KAAK,QAAQ;AAAA,gBACjC,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,iBAAiB,MAAM,mBAAmB,QAAQ;AAAA,gBAC/D,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB,gBAAgB;AAAA,QAClC,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AC/TA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAMP,SAASG,aAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAQA,SAAS,eAAe,KAAwB;AAC9C,QAAM,UAAoB,CAAC;AAC3B,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,SAAS;AACf,QAAM,QAAQ,MAAM,QAAQ,OAAO,SAAS,IACxC,OAAO,YACP,OAAO,YACL,CAAC,OAAO,SAAS,IACjB,CAAC;AAEP,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,WAAW,QAAS;AAC7B,UAAM,OAAO,MAAM,QAAQ,KAAK,MAAM,IAClC,KAAK,SACL,KAAK,SACH,CAAC,KAAK,MAAM,IACZ,CAAC;AACP,YAAQ,KAAK,GAAG,IAAI;AAAA,EACtB;AACA,SAAO,QAAQ,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;AAC3C;AAEA,SAAS,UAAU,SAAmB,SAA0B;AAC9D,QAAM,MAAM,QAAQ,YAAY;AAChC,SAAO,QAAQ,KAAK,CAAC,MAAM;AACzB,QAAI,MAAM,IAAK,QAAO;AACtB,QAAI,MAAM,IAAK,QAAO;AAEtB,QAAI,EAAE,SAAS,GAAG,GAAG;AACnB,YAAM,SAAS,EAAE,MAAM,GAAG,EAAE;AAC5B,UAAI,IAAI,WAAW,MAAM,EAAG,QAAO;AAAA,IACrC;AACA,WAAO;AAAA,EACT,CAAC;AACH;AAEO,IAAM,gCAAN,MAAuD;AAAA,EACnD,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,UAAM,YAAY,aAAa,MAAM;AAErC,aAAS;AAAA,MACP;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,aAAa,WAAW,WAAW,IAAI,WAAW;AAGjE,YAAM,QAAgB,CAAC;AACvB,UAAI;AACJ,SAAG;AACD,cAAM,OAAO,MAAM,OAAO;AAAA,UACxB,IAAI,iBAAiB,EAAE,QAAQ,OAAO,CAAC;AAAA,QACzC;AACA,YAAI,KAAK,MAAO,OAAM,KAAK,GAAG,KAAK,KAAK;AACxC,iBAAS,KAAK,cAAc,KAAK,SAAS;AAAA,MAC5C,SAAS;AAET,iBAAW,QAAQ,OAAO;AACxB,cAAM,WAAW,KAAK,YAAY;AAClC,cAAM,UACJ,KAAK,OACL,OAAO,SAAS,SAAS,SAAS,SAAS,QAAQ;AAGrD,cAAM,aAAuB,CAAC;AAG9B,YAAI;AACF,gBAAM,eAAe,MAAM,OAAO;AAAA,YAChC,IAAI,gCAAgC,EAAE,UAAU,SAAS,CAAC;AAAA,UAC5D;AACA,qBAAW,UAAU,aAAa,oBAAoB,CAAC,GAAG;AACxD,kBAAM,YAAY,OAAO;AACzB,gBAAI,CAAC,UAAW;AAChB,gBAAI;AACF,oBAAM,aAAa,MAAM,OAAO;AAAA,gBAC9B,IAAI,iBAAiB,EAAE,WAAW,UAAU,CAAC;AAAA,cAC/C;AACA,oBAAM,YACJ,WAAW,QAAQ,oBAAoB;AACzC,oBAAM,cAAc,MAAM,OAAO;AAAA,gBAC/B,IAAI,wBAAwB;AAAA,kBAC1B,WAAW;AAAA,kBACX,WAAW;AAAA,gBACb,CAAC;AAAA,cACH;AACA,oBAAM,MAAM,YAAY,eAAe;AACvC,kBAAI,KAAK;AACP,sBAAM,SAAS,KAAK,MAAM,mBAAmB,GAAG,CAAC;AACjD,2BAAW,KAAK,GAAG,eAAe,MAAM,CAAC;AAAA,cAC3C;AAAA,YACF,SAAS,GAAY;AACnB,oBAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,uBAAS;AAAA,gBACP,yBAAyB,SAAS,aAAa,QAAQ,KAAK,GAAG;AAAA,cACjE;AAAA,YACF;AAAA,UACF;AAAA,QACF,SAAS,GAAY;AACnB,gBAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,mBAAS;AAAA,YACP,6CAA6C,QAAQ,KAAK,GAAG;AAAA,UAC/D;AAAA,QACF;AAGA,YAAI;AACF,gBAAM,aAAa,MAAM,OAAO;AAAA,YAC9B,IAAI,wBAAwB,EAAE,UAAU,SAAS,CAAC;AAAA,UACpD;AACA,qBAAW,cAAc,WAAW,eAAe,CAAC,GAAG;AACrD,gBAAI;AACF,oBAAM,mBAAmB,MAAM,OAAO;AAAA,gBACpC,IAAI,qBAAqB;AAAA,kBACvB,UAAU;AAAA,kBACV,YAAY;AAAA,gBACd,CAAC;AAAA,cACH;AACA,oBAAM,MAAM,iBAAiB;AAC7B,kBAAI,KAAK;AACP,sBAAM,SAAS,KAAK,MAAM,mBAAmB,GAAG,CAAC;AACjD,2BAAW,KAAK,GAAG,eAAe,MAAM,CAAC;AAAA,cAC3C;AAAA,YACF,SAAS,GAAY;AACnB,oBAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,uBAAS;AAAA,gBACP,gCAAgC,UAAU,aAAa,QAAQ,KAAK,GAAG;AAAA,cACzE;AAAA,YACF;AAAA,UACF;AAAA,QACF,SAAS,GAAY;AACnB,gBAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,mBAAS;AAAA,YACP,2CAA2C,QAAQ,KAAK,GAAG;AAAA,UAC7D;AAAA,QACF;AAEA,YAAI,WAAW,WAAW,EAAG;AAG7B,YACE,UAAU,YAAY,OAAO,KAC7B,WAAW,SAAS,GAAG,GACvB;AACA,mBAAS;AAAA,YACPA,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,YAAY,QAAQ;AAAA,cAC3B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb,QAAQ;AAAA,cACR,aAAa,SAAS,QAAQ;AAAA,cAC9B,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB,8CAA8C,QAAQ;AAAA,gBACtD;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAEA;AAAA,QACF;AAGA,YACE,UAAU,YAAY,mBAAmB,KACzC,UAAU,YAAY,sBAAsB,GAC5C;AACA,mBAAS;AAAA,YACPA,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,YAAY,QAAQ;AAAA,cAC3B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb,QAAQ;AAAA,cACR,aAAa,SAAS,QAAQ;AAAA,cAC9B,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB,gEAAgE,QAAQ;AAAA,gBACxE;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAGA,YACE,UAAU,YAAY,gBAAgB,KACtC,UAAU,YAAY,sBAAsB,GAC5C;AACA,mBAAS;AAAA,YACPA,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,YAAY,QAAQ;AAAA,cAC3B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb,QAAQ;AAAA,cACR,aAAa,SAAS,QAAQ;AAAA,cAC9B,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB,uFAAuF,QAAQ;AAAA,gBAC/F;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAGA,YACE,UAAU,YAAY,cAAc,KACpC,UAAU,YAAY,uBAAuB,GAC7C;AACA,mBAAS;AAAA,YACPA,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,YAAY,QAAQ;AAAA,cAC3B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb,QAAQ;AAAA,cACR,aAAa,SAAS,QAAQ;AAAA,cAC9B,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB,yDAAyD,QAAQ;AAAA,gBACjE;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAGA,YAAI,UAAU,YAAY,qBAAqB,GAAG;AAChD,mBAAS;AAAA,YACPA,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,YAAY,QAAQ;AAAA,cAC3B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb,QAAQ;AAAA,cACR,aAAa,SAAS,QAAQ;AAAA,cAC9B,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAGA,YAAI,UAAU,YAAY,gBAAgB,GAAG;AAC3C,mBAAS;AAAA,YACPA,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,YAAY,QAAQ;AAAA,cAC3B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb,QAAQ;AAAA,cACR,aAAa,SAAS,QAAQ;AAAA,cAC9B,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB,2DAA2D,QAAQ;AAAA,gBACnE;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB,MAAM;AAAA,QACxB,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AC/VA;AAAA,EACE,YAAAC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,OAAOC,UAAS;AAMhB,SAASC,aAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAEA,SAAS,WAAW,QAAgB,QAAwB;AAC1D,QAAM,SAAS,OAAO,WAAW,KAAK,IAClC,qBACA;AACJ,SAAO,WAAW,MAAM,OAAO,MAAM,IAAI,MAAM;AACjD;AAEA,eAAe,gBACb,QACA,YACA,eACA,UACiB;AACjB,MAAI;AACF,UAAM,OAAO,MAAM,OAAO;AAAA,MACxB,IAAI,yBAAyB,EAAE,QAAQ,WAAW,CAAC;AAAA,IACrD;AACA,UAAM,MAAM,OAAO,KAAK,sBAAsB,EAAE,KAAK;AACrD,WAAO;AAAA,EACT,SAAS,GAAY;AACnB,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,aAAS,KAAK,sCAAsC,UAAU,WAAW,aAAa,KAAK,GAAG,EAAE;AAChG,WAAO;AAAA,EACT;AACF;AAEA,eAAe,qBACb,QACA,YACA,UAC2B;AAE3B,MAAI,YAAY;AAChB,MAAI;AACF,UAAM,MAAM,MAAM,OAAO;AAAA,MACvB,IAAI,4BAA4B,EAAE,QAAQ,WAAW,CAAC;AAAA,IACxD;AACA,UAAM,MAAM,IAAI;AAChB,gBAAY,CAAC,EACX,KAAK,mBACL,KAAK,oBACL,KAAK,qBACL,KAAK;AAAA,EAET,SAAS,GAAY;AACnB,QACE,aAAa,SACb,EAAE,SAAS,wCACX;AACA,kBAAY;AAAA,IACd,OAAO;AACL,YAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,eAAS,KAAK,4CAA4C,UAAU,KAAK,GAAG,EAAE;AAC9E,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,UAAW,QAAO;AAGtB,MAAI;AACF,UAAM,MAAM,MAAM,OAAO;AAAA,MACvB,IAAI,oBAAoB,EAAE,QAAQ,WAAW,CAAC;AAAA,IAChD;AACA,eAAW,SAAS,IAAI,UAAU,CAAC,GAAG;AACpC,YAAM,MAAM,MAAM,SAAS,OAAO;AAClC,UAAI,IAAI,SAAS,UAAU,KAAK,IAAI,SAAS,oBAAoB,GAAG;AAClE,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,SAAS,GAAY;AACnB,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,aAAS,KAAK,kCAAkC,UAAU,KAAK,GAAG,EAAE;AAAA,EACtE;AAGA,MAAI;AACF,UAAM,eAAe,MAAM,OAAO;AAAA,MAChC,IAAI,6BAA6B,EAAE,QAAQ,WAAW,CAAC;AAAA,IACzD;AACA,QAAI,aAAa,cAAc,SAAU,QAAO;AAAA,EAClD,SAAS,GAAY;AAEnB,QAAI,aAAa,SAAS,CAAC,EAAE,KAAK,SAAS,oBAAoB,GAAG;AAChE,YAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,eAAS,KAAK,4CAA4C,UAAU,KAAK,GAAG,EAAE;AAAA,IAChF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,YAAY,IAAqB;AACxC,MAAI,GAAG,WAAW,KAAK,EAAG,QAAO;AACjC,MAAI,GAAG,WAAW,UAAU,EAAG,QAAO;AACtC,MAAI,GAAG,WAAW,MAAM,GAAG;AACzB,UAAM,SAAS,SAAS,GAAG,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE;AAC5C,WAAO,UAAU,MAAM,UAAU;AAAA,EACnC;AACA,MAAI,GAAG,WAAW,MAAM,EAAG,QAAO;AAClC,SAAO;AACT;AAEO,IAAM,4BAAN,MAAmD;AAAA,EAC/C,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AAEF,UAAI;AACF,cAAM,WAAW,aAAaC,WAAU,QAAQ,IAAI,WAAW;AAC/D,cAAM,WAAW,MAAM,SAAS,KAAK,IAAI,mBAAmB,CAAC,CAAC,CAAC;AAC/D,cAAM,UAAU,SAAS,WAAW,CAAC;AAErC,mBAAW,UAAU,SAAS;AAC5B,gBAAM,OAAO,OAAO,QAAQ;AAC5B,gBAAM,MAAM,OAAO,SAAS,SAAS,IAAI;AAEzC,gBAAM,eAAe,MAAM,gBAAgB,UAAU,MAAM,QAAQ,QAAQ;AAC3E,gBAAM,eACJ,iBAAiB,SACb,WACA,aAAaA,WAAU,cAAc,IAAI,WAAW;AAE1D,gBAAM,eAAe,MAAM,qBAAqB,cAAc,MAAM,QAAQ;AAC5E,cAAI,iBAAiB,UAAU,CAAC,aAAc;AAE9C;AACA,gBAAM,MAAM,WAAW,MAAM,YAAY;AAEzC,cAAI;AACF,kBAAM,OAAO,MAAM,MAAM,KAAK;AAAA,cAC5B,QAAQ;AAAA,cACR,QAAQ,YAAY,QAAQ,GAAI;AAAA,YAClC,CAAC;AAED,gBAAI,KAAK,MAAM,KAAK,WAAW,KAAK;AAClC,uBAAS;AAAA,gBACPD,aAAY;AAAA,kBACV,WAAW;AAAA,kBACX,OAAO,aAAa,IAAI;AAAA,kBACxB,cAAc;AAAA,kBACd,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb,QAAQ;AAAA,kBACR,aAAa,gBAAgB,GAAG,oBAAoB,KAAK,MAAM;AAAA,kBAC/D,QACE;AAAA,kBACF,kBAAkB;AAAA,oBAChB;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF,WAAW,KAAK,WAAW,KAAK;AAC9B,uBAAS;AAAA,gBACPA,aAAY;AAAA,kBACV,WAAW;AAAA,kBACX,OAAO,aAAa,IAAI;AAAA,kBACxB,cAAc;AAAA,kBACd,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb,QAAQ;AAAA,kBACR,aAAa,WAAW,IAAI;AAAA,kBAC5B,QACE;AAAA,kBACF,kBAAkB;AAAA,oBAChB;AAAA,oBACA;AAAA,kBACF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF,SAAS,GAAY;AACnB,kBAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,qBAAS,KAAK,yBAAyB,IAAI,YAAY,GAAG,EAAE;AAAA,UAC9D;AAAA,QACF;AAAA,MACF,SAAS,GAAY;AACnB,cAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,iBAAS,KAAK,yCAAyC,GAAG,EAAE;AAAA,MAC9D;AAGA,UAAI;AACF,cAAM,YAAY,aAAa,WAAW,QAAQ,IAAI,WAAW;AACjE,cAAM,YAA0B,CAAC;AACjC,YAAI;AACJ,WAAG;AACD,gBAAM,OAAO,MAAM,UAAU;AAAA,YAC3B,IAAI,2BAA2B,EAAE,QAAQ,OAAO,CAAC;AAAA,UACnD;AACA,cAAI,KAAK,YAAa,WAAU,KAAK,GAAG,KAAK,WAAW;AACxD,mBAAS,KAAK;AAAA,QAChB,SAAS;AAET,mBAAW,MAAM,WAAW;AAC1B,cAAI,CAAC,GAAG,mBAAoB;AAE5B,gBAAM,OAAO,GAAG,wBAAwB;AACxC,gBAAM,QACJ,GAAG,iBACH,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,OAAO,IAAI;AACxD,gBAAM,WAAW,GAAG,UAAU;AAC9B,cAAI,CAAC,SAAU;AAEf;AAEA,cAAI;AACF,kBAAM,YAAY,MAAME,KAAI,SAAS,SAAS,QAAQ;AACtD,kBAAM,cAAc,UAAU,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;AAE3D,gBAAI,aAAa;AACf,uBAAS;AAAA,gBACPF,aAAY;AAAA,kBACV,WAAW;AAAA,kBACX,OAAO,gBAAgB,IAAI;AAAA,kBAC3B,cAAc;AAAA,kBACd,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb;AAAA,kBACA,aAAa,gBAAgB,QAAQ,8BAA8B,UAAU,KAAK,IAAI,CAAC;AAAA,kBACvF,QACE;AAAA,kBACF,kBAAkB;AAAA,oBAChB;AAAA,oBACA;AAAA,oBACA;AAAA,oBACA;AAAA,kBACF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF,SAAS,GAAY;AACnB,kBAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,qBAAS,KAAK,0BAA0B,IAAI,KAAK,QAAQ,aAAa,GAAG,EAAE;AAAA,UAC7E;AAAA,QACF;AAAA,MACF,SAAS,GAAY;AACnB,cAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,iBAAS,KAAK,0CAA0C,GAAG,EAAE;AAAA,MAC/D;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AClTA;AAAA,EACE,aAAAG;AAAA,EACA,4BAAAC;AAAA,OAEK;AACP;AAAA,EACE,aAAAC;AAAA,EACA,8BAAAC;AAAA,OAEK;AACP;AAAA,EACE,YAAAC;AAAA,EACA,sBAAAC;AAAA,EACA;AAAA,OACK;AAMP,IAAM,wBAAwB,CAAC,eAAe,WAAW,OAAO;AAEhE,SAASC,aAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAEA,SAAS,eACP,MACA,cACU;AACV,QAAM,UAAU,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;AACpD,SAAO,aAAa,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;AACrD;AAEO,IAAM,uBAAN,MAA8C;AAAA,EAC1C,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AACvB,UAAM,eAAe;AAErB,QAAI;AAEF,UAAI;AACF,cAAM,YAAY,aAAaC,YAAW,QAAQ,IAAI,WAAW;AACjE,cAAM,YAAwB,CAAC;AAC/B,YAAI;AACJ,WAAG;AACD,gBAAM,OAAO,MAAM,UAAU;AAAA,YAC3B,IAAIC,0BAAyB,EAAE,WAAW,UAAU,CAAC;AAAA,UACvD;AACA,qBAAW,OAAO,KAAK,gBAAgB,CAAC,GAAG;AACzC,gBAAI,IAAI,UAAW,WAAU,KAAK,GAAG,IAAI,SAAS;AAAA,UACpD;AACA,sBAAY,KAAK;AAAA,QACnB,SAAS;AAET,4BAAoB,UAAU;AAE9B,mBAAW,YAAY,WAAW;AAChC,gBAAM,KAAK,SAAS,cAAc;AAClC,gBAAM,MAAM,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,aAAa,EAAE;AACtE,gBAAM,OAAO,SAAS,QAAQ,CAAC;AAC/B,gBAAM,UAAU,eAAe,MAAM,YAAY;AAEjD,cAAI,QAAQ,SAAS,GAAG;AACtB,qBAAS;AAAA,cACPF,aAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,gBAAgB,EAAE,2BAA2B,QAAQ,KAAK,IAAI,CAAC;AAAA,gBACtE,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,iBAAiB,EAAE,6CAA6C,QAAQ,KAAK,IAAI,CAAC;AAAA,gBAC/F,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB,yBAAyB,QAAQ,KAAK,IAAI,CAAC,iBAAiB,EAAE;AAAA,kBAC9D;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,GAAY;AACnB,cAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,iBAAS,KAAK,oCAAoC,GAAG,EAAE;AAAA,MACzD;AAGA,UAAI;AACF,cAAM,YAAY,aAAaG,YAAW,QAAQ,IAAI,WAAW;AACjE,cAAM,cAA4B,CAAC;AACnC,YAAI;AACJ,WAAG;AACD,gBAAM,OAAO,MAAM,UAAU;AAAA,YAC3B,IAAIC,4BAA2B,EAAE,QAAQ,OAAO,CAAC;AAAA,UACnD;AACA,cAAI,KAAK,YAAa,aAAY,KAAK,GAAG,KAAK,WAAW;AAC1D,mBAAS,KAAK;AAAA,QAChB,SAAS;AAET,4BAAoB,YAAY;AAEhC,mBAAW,MAAM,aAAa;AAC5B,gBAAM,OAAO,GAAG,wBAAwB;AACxC,gBAAM,QACJ,GAAG,iBACH,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,OAAO,IAAI;AACxD,gBAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,IAAI,CAAC,OAAO;AAAA,YAC1C,KAAK,EAAE;AAAA,YACP,OAAO,EAAE;AAAA,UACX,EAAE;AACF,gBAAM,UAAU,eAAe,MAAM,YAAY;AAEjD,cAAI,QAAQ,SAAS,GAAG;AACtB,qBAAS;AAAA,cACPJ,aAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,gBAAgB,IAAI,2BAA2B,QAAQ,KAAK,IAAI,CAAC;AAAA,gBACxE,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,iBAAiB,IAAI,6CAA6C,QAAQ,KAAK,IAAI,CAAC;AAAA,gBACjG,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB,yBAAyB,QAAQ,KAAK,IAAI,CAAC,qBAAqB,IAAI;AAAA,kBACpE;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,GAAY;AACnB,cAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,iBAAS,KAAK,oCAAoC,GAAG,EAAE;AAAA,MACzD;AAGA,UAAI;AACF,cAAM,WAAW,aAAaK,WAAU,QAAQ,IAAI,WAAW;AAC/D,cAAM,WAAW,MAAM,SAAS,KAAK,IAAIC,oBAAmB,CAAC,CAAC,CAAC;AAC/D,cAAM,UAAU,SAAS,WAAW,CAAC;AACrC,4BAAoB,QAAQ;AAE5B,mBAAW,UAAU,SAAS;AAC5B,gBAAM,OAAO,OAAO,QAAQ;AAC5B,gBAAM,MAAM,OAAO,SAAS,SAAS,IAAI;AAEzC,cAAI;AACF,kBAAM,cAAc,MAAM,SAAS;AAAA,cACjC,IAAI,wBAAwB,EAAE,QAAQ,KAAK,CAAC;AAAA,YAC9C;AACA,kBAAM,QAAQ,YAAY,UAAU,CAAC,GAAG,IAAI,CAAC,OAAO;AAAA,cAClD,KAAK,EAAE;AAAA,cACP,OAAO,EAAE;AAAA,YACX,EAAE;AACF,kBAAM,UAAU,eAAe,MAAM,YAAY;AAEjD,gBAAI,QAAQ,SAAS,GAAG;AACtB,uBAAS;AAAA,gBACPN,aAAY;AAAA,kBACV,WAAW;AAAA,kBACX,OAAO,aAAa,IAAI,2BAA2B,QAAQ,KAAK,IAAI,CAAC;AAAA,kBACrE,cAAc;AAAA,kBACd,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb,QAAQ;AAAA,kBACR,aAAa,cAAc,IAAI,6CAA6C,QAAQ,KAAK,IAAI,CAAC;AAAA,kBAC9F,QACE;AAAA,kBACF,kBAAkB;AAAA,oBAChB,yBAAyB,QAAQ,KAAK,IAAI,CAAC,eAAe,IAAI;AAAA,oBAC9D;AAAA,oBACA;AAAA,kBACF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF,SAAS,GAAY;AACnB,gBACE,aAAa,SACb,EAAE,SAAS,gBACX;AAEA,uBAAS;AAAA,gBACPA,aAAY;AAAA,kBACV,WAAW;AAAA,kBACX,OAAO,aAAa,IAAI,2BAA2B,aAAa,KAAK,IAAI,CAAC;AAAA,kBAC1E,cAAc;AAAA,kBACd,YAAY;AAAA,kBACZ,aAAa;AAAA,kBACb,QAAQ;AAAA,kBACR,aAAa,cAAc,IAAI,wDAAwD,aAAa,KAAK,IAAI,CAAC;AAAA,kBAC9G,QACE;AAAA,kBACF,kBAAkB;AAAA,oBAChB,0BAA0B,aAAa,KAAK,IAAI,CAAC,eAAe,IAAI;AAAA,oBACpE;AAAA,oBACA;AAAA,kBACF;AAAA,gBACF,CAAC;AAAA,cACH;AAAA,YACF,OAAO;AACL,oBAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,uBAAS,KAAK,oBAAoB,IAAI,YAAY,GAAG,EAAE;AAAA,YACzD;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,GAAY;AACnB,cAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,iBAAS,KAAK,mCAAmC,GAAG,EAAE;AAAA,MACxD;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AChQA;AAAA,EACE,aAAAO;AAAA,EACA;AAAA,EACA,4BAAAC;AAAA,EACA,4BAAAC;AAAA,EACA;AAAA,EACA,iCAAAC;AAAA,OAKK;AAMP,IAAM,iBAAiB,KAAK,KAAK,KAAK,KAAK;AAE3C,SAASC,aAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAEO,IAAM,uBAAN,MAA8C;AAAA,EAC1C,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAE5B,QAAI;AACF,YAAM,SAAS,aAAaC,YAAW,QAAQ,IAAI,WAAW;AAC9D,UAAI,mBAAmB;AAGvB,YAAM,UAAoB,CAAC;AAC3B,UAAI;AACJ,SAAG;AACD,cAAM,OAAO,MAAM,OAAO;AAAA,UACxB,IAAI,uBAAuB,EAAE,WAAW,SAAS,CAAC;AAAA,QACpD;AACA,YAAI,KAAK,QAAS,SAAQ,KAAK,GAAG,KAAK,OAAO;AAC9C,mBAAW,KAAK;AAAA,MAClB,SAAS;AAET,0BAAoB,QAAQ;AAE5B,iBAAW,OAAO,SAAS;AACzB,YAAI,IAAI,UAAU,aAAa;AAC7B,gBAAM,QAAQ,IAAI,YAAY;AAC9B,mBAAS;AAAA,YACPD,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,cAAc,KAAK;AAAA,cAC1B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,WAAW,KAAK;AAAA,cACxE;AAAA,cACA,aAAa,eAAe,KAAK,MAAM,IAAI,QAAQ,GAAG,OAAO,IAAI,cAAc,SAAS;AAAA,cACxF,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAGA,UAAI,YAAuB,CAAC;AAC5B,UAAI;AACF,cAAM,WAAW,MAAM,OAAO,KAAK,IAAIE,0BAAyB,CAAC,CAAC,CAAC;AACnE,oBAAY,SAAS,aAAa,CAAC;AAAA,MACrC,SAAS,GAAY;AACnB,cAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,iBAAS,KAAK,4BAA4B,GAAG,EAAE;AAAA,MACjD;AAEA,0BAAoB,UAAU;AAE9B,iBAAW,QAAQ,WAAW;AAC5B,YAAI,CAAC,KAAK,eAAe;AACvB,gBAAM,UAAU,KAAK,gBAAgB;AACrC,gBAAM,WAAW,KAAK,YAAY;AAClC,mBAAS;AAAA,YACPF,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,cAAc,QAAQ;AAAA,cAC7B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,eAAe,OAAO;AAAA,cAC9E;AAAA,cACA,aAAa,cAAc,QAAQ,KAAK,OAAO;AAAA,cAC/C,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAGA,YAAM,YAAwB,CAAC;AAC/B,UAAI;AACJ,SAAG;AACD,cAAM,WAAW,MAAM,OAAO;AAAA,UAC5B,IAAIG,0BAAyB,EAAE,WAAW,UAAU,CAAC;AAAA,QACvD;AACA,mBAAW,OAAO,SAAS,gBAAgB,CAAC,GAAG;AAC7C,cAAI,IAAI,UAAW,WAAU,KAAK,GAAG,IAAI,SAAS;AAAA,QACpD;AACA,oBAAY,SAAS;AAAA,MACvB,SAAS;AAET,0BAAoB,UAAU;AAC9B,YAAM,MAAM,KAAK,IAAI;AAErB,iBAAW,QAAQ,WAAW;AAC5B,YAAI,KAAK,OAAO,SAAS,WAAW;AAClC,gBAAM,SAAS,KAAK,cAAc;AAClC,gBAAM,SAAS,KAAK,yBAAyB;AAC7C,gBAAM,cAAc,SAAS,cAAc,MAAM,IAAI;AAErD,cAAI,CAAC,aAAa;AAChB,qBAAS;AAAA,cACP,8CAA8C,MAAM,4BAA4B,MAAM;AAAA,YACxF;AACA;AAAA,UACF;AAEA,gBAAM,cAAc,KAAK;AAAA,aACtB,MAAM,gBAAgB,KAAK,KAAK,KAAK;AAAA,UACxC;AAEA,cAAI,cAAc,IAAI;AACpB,qBAAS;AAAA,cACPH,aAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,gBAAgB,MAAM,yBAAyB,WAAW;AAAA,gBACjE,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,aAAa,MAAM;AAAA,gBAC3E;AAAA,gBACA,aAAa,iBAAiB,MAAM,MAAM,KAAK,gBAAgB,SAAS,6BAA6B,WAAW;AAAA,gBAChH,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,YAAM,iBAAkC,CAAC;AACzC,UAAI;AACJ,SAAG;AACD,cAAM,SAAS,MAAM,OAAO;AAAA,UAC1B,IAAII,+BAA8B,EAAE,WAAW,QAAQ,CAAC;AAAA,QAC1D;AACA,YAAI,OAAO,eAAgB,gBAAe,KAAK,GAAG,OAAO,cAAc;AACvE,kBAAU,OAAO;AAAA,MACnB,SAAS;AAGT,YAAM,YAAY,oBAAI,IAAY;AAClC,UAAI;AACJ,SAAG;AACD,cAAM,UAAU,MAAM,OAAO;AAAA,UAC3B,IAAI,iCAAiC,EAAE,WAAW,SAAS,CAAC;AAAA,QAC9D;AACA,mBAAW,OAAO,QAAQ,qBAAqB,CAAC,GAAG;AACjD,qBAAW,SAAS,IAAI,UAAU,CAAC,GAAG;AACpC,gBAAI,MAAM,QAAS,WAAU,IAAI,MAAM,OAAO;AAAA,UAChD;AAAA,QACF;AACA,mBAAW,QAAQ;AAAA,MACrB,SAAS;AAET,0BAAoB,eAAe;AAEnC,iBAAW,MAAM,gBAAgB;AAC/B,cAAM,OAAO,GAAG,WAAW;AAE3B,YAAI,GAAG,cAAc,UAAW;AAEhC,YAAI,CAAC,UAAU,IAAI,IAAI,GAAG;AACxB,mBAAS;AAAA,YACPJ,aAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,kBAAkB,IAAI;AAAA,cAC7B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa,OAAO,SAAS,QAAQ,MAAM,IAAI,GAAG,WAAW,SAAS,mBAAmB,IAAI;AAAA,cAC7F;AAAA,cACA,aAAa,mBAAmB,GAAG,SAAS,MAAM,IAAI;AAAA,cACtD,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;AAMA,SAAS,cAAc,QAA+B;AACpD,QAAM,QAAQ,OAAO,MAAM,iDAAiD;AAC5E,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,SAAS,KAAK,MAAM,MAAM,CAAC,CAAC;AAClC,SAAO,MAAM,MAAM,IAAI,OAAO;AAChC;;;ACvQA;AAAA,EACE,aAAAK;AAAA,EACA,8BAAAC;AAAA,OAEK;AACP;AAAA,EACE,aAAAC;AAAA,EACA,0BAAAC;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE,YAAAC;AAAA,EACA,sBAAAC;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAMP,IAAM,gBAAgB,IAAI,KAAK,KAAK,KAAK;AAEzC,SAASC,cAAY,MAUT;AACV,QAAM,WAAW,kBAAkB,KAAK,SAAS;AACjD,SAAO,EAAE,GAAG,MAAM,UAAU,UAAU,qBAAqB,QAAQ,EAAE;AACvE;AAEO,IAAM,0BAAN,MAAiD;AAAA,EAC7C,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAE5B,QAAI;AACF,UAAI,mBAAmB;AAGvB,YAAM,YAAY,aAAaC,YAAW,QAAQ,IAAI,WAAW;AACjE,YAAM,YAA0B,CAAC;AACjC,UAAI;AACJ,SAAG;AACD,cAAM,OAAO,MAAM,UAAU;AAAA,UAC3B,IAAIC,4BAA2B,EAAE,QAAQ,OAAO,CAAC;AAAA,QACnD;AACA,YAAI,KAAK,YAAa,WAAU,KAAK,GAAG,KAAK,WAAW;AACxD,iBAAS,KAAK;AAAA,MAChB,SAAS;AAET,0BAAoB,UAAU;AAE9B,iBAAW,MAAM,WAAW;AAC1B,cAAM,OAAO,GAAG,wBAAwB;AACxC,cAAM,QACJ,GAAG,iBACH,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,OAAO,IAAI;AACxD,cAAM,SAAS,GAAG,UAAU;AAG5B,YAAI,CAAC,GAAG,SAAS;AACf,mBAAS;AAAA,YACPF,cAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,gBAAgB,IAAI;AAAA,cAC3B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb;AAAA,cACA,aAAa,iBAAiB,IAAI,MAAM,MAAM;AAAA,cAC9C,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAGA,cAAM,YAAY,GAAG,yBAAyB;AAC9C,YAAI,cAAc,GAAG;AACnB,mBAAS;AAAA,YACPA,cAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,gBAAgB,IAAI;AAAA,cAC3B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb;AAAA,cACA,aAAa,iBAAiB,IAAI,MAAM,MAAM;AAAA,cAC9C,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,WAAW,YAAY,GAAG;AACxB,mBAAS;AAAA,YACPA,cAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,gBAAgB,IAAI,6BAA6B,SAAS;AAAA,cACjE,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb;AAAA,cACA,aAAa,iBAAiB,IAAI,MAAM,MAAM,oCAAoC,SAAS;AAAA,cAC3F,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAGA,YAAM,YAAY,aAAaG,YAAW,QAAQ,IAAI,WAAW;AAEjE,YAAM,UAAoB,CAAC;AAC3B,UAAI;AACJ,SAAG;AACD,cAAM,OAAO,MAAM,UAAU;AAAA,UAC3B,IAAIC,wBAAuB,EAAE,WAAW,SAAS,CAAC;AAAA,QACpD;AACA,YAAI,KAAK,QAAS,SAAQ,KAAK,GAAG,KAAK,OAAO;AAC9C,mBAAW,KAAK;AAAA,MAClB,SAAS;AAGT,YAAM,YAAwB,CAAC;AAC/B,UAAI;AACJ,SAAG;AACD,cAAM,OAAO,MAAM,UAAU;AAAA,UAC3B,IAAI,yBAAyB;AAAA,YAC3B,UAAU,CAAC,MAAM;AAAA,YACjB,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA,YAAI,KAAK,UAAW,WAAU,KAAK,GAAG,KAAK,SAAS;AACpD,oBAAY,KAAK;AAAA,MACnB,SAAS;AAGT,YAAM,yBAAyB,oBAAI,IAAoB;AACvD,iBAAW,QAAQ,WAAW;AAC5B,YAAI,CAAC,KAAK,YAAY,KAAK,UAAU,YAAa;AAClD,cAAM,WAAW,KAAK,WAAW,QAAQ,KAAK;AAC9C,cAAM,WAAW,uBAAuB,IAAI,KAAK,QAAQ,KAAK;AAC9D,YAAI,WAAW,UAAU;AACvB,iCAAuB,IAAI,KAAK,UAAU,QAAQ;AAAA,QACpD;AAAA,MACF;AAGA,YAAM,eAAe,QAAQ,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ;AAC/D,0BAAoB,aAAa;AACjC,YAAM,MAAM,KAAK,IAAI;AAErB,iBAAW,OAAO,cAAc;AAC9B,cAAM,QAAQ,IAAI,YAAY;AAC9B,cAAM,SAAS,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,WAAW,KAAK;AAC1E,cAAM,aAAa,uBAAuB,IAAI,KAAK;AAEnD,YAAI,eAAe,QAAW;AAE5B,mBAAS;AAAA,YACPJ,cAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,cAAc,KAAK;AAAA,cAC1B,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb;AAAA,cACA,aAAa,eAAe,KAAK,MAAM,IAAI,QAAQ,GAAG,OAAO,IAAI,cAAc,SAAS;AAAA,cACxF,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,WAAW,MAAM,aAAa,eAAe;AAC3C,gBAAM,YAAY,KAAK,OAAO,MAAM,eAAe,KAAK,KAAK,KAAK,IAAK;AACvE,mBAAS;AAAA,YACPA,cAAY;AAAA,cACV,WAAW;AAAA,cACX,OAAO,cAAc,KAAK,4BAA4B,SAAS;AAAA,cAC/D,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa;AAAA,cACb;AAAA,cACA,aAAa,eAAe,KAAK,MAAM,IAAI,QAAQ,GAAG,+BAA+B,SAAS;AAAA,cAC9F,QACE;AAAA,cACF,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAGA,YAAM,WAAW,aAAaK,WAAU,QAAQ,IAAI,WAAW;AAE/D,UAAI,cAAwB,CAAC;AAC7B,UAAI;AACF,cAAM,WAAW,MAAM,SAAS,KAAK,IAAIC,oBAAmB,CAAC,CAAC,CAAC;AAC/D,uBAAe,SAAS,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,MAAmB,CAAC,CAAC,CAAC;AAAA,MAC1F,SAAS,GAAY;AACnB,cAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,iBAAS,KAAK,0BAA0B,GAAG,EAAE;AAAA,MAC/C;AAEA,0BAAoB,YAAY;AAEhC,iBAAW,QAAQ,aAAa;AAC9B,cAAM,MAAM,OAAO,SAAS,SAAS,IAAI;AAGzC,YAAI;AACF,gBAAM,MAAM,MAAM,SAAS;AAAA,YACzB,IAAI,2BAA2B,EAAE,QAAQ,KAAK,CAAC;AAAA,UACjD;AACA,cAAI,IAAI,WAAW,WAAW;AAC5B,qBAAS;AAAA,cACPN,cAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,aAAa,IAAI;AAAA,gBACxB,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,WAAW,IAAI,mBAAmB,IAAI,UAAU,SAAS;AAAA,gBACtE,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF,SAAS,GAAY;AACnB,gBAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,mBAAS,KAAK,UAAU,IAAI,6BAA6B,GAAG,EAAE;AAAA,QAChE;AAGA,YAAI;AACF,gBAAM,SAAS;AAAA,YACb,IAAI,4BAA4B,EAAE,QAAQ,KAAK,CAAC;AAAA,UAClD;AAAA,QAEF,SAAS,GAAY;AACnB,cACE,aAAa,SACb,EAAE,SAAS,yCACX;AACA,qBAAS;AAAA,cACPA,cAAY;AAAA,gBACV,WAAW;AAAA,gBACX,OAAO,aAAa,IAAI;AAAA,gBACxB,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,WAAW,IAAI;AAAA,gBAC5B,QACE;AAAA,gBACF,kBAAkB;AAAA,kBAChB;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF,OAAO;AACL,kBAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,qBAAS,KAAK,UAAU,IAAI,8BAA8B,GAAG,EAAE;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACtD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C,kBAAkB;AAAA,QAClB,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;ACxUA;AAAA,EACE,qBAAAO;AAAA,EACA;AAAA,OACK;AAMP,SAAS,kBAAkB,OAA8B;AACvD,UAAQ,OAAO;AAAA,IACb,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAO,aAAO;AAAA,IACnB,KAAK;AAAiB,aAAO;AAAA;AAAA,IAC7B;AAAS,aAAO;AAAA,EAClB;AACF;AAEO,IAAM,6BAAN,MAAoD;AAAA,EAChD,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AACF,YAAM,SAAS,aAAaC,oBAAmB,QAAQ,IAAI,WAAW;AACtE,UAAI;AAEJ,SAAG;AACD,cAAM,OAAO,MAAM,OAAO;AAAA,UACxB,IAAI,mBAAmB;AAAA,YACrB,SAAS;AAAA,cACP,gBAAgB;AAAA,gBACd,EAAE,OAAO,OAAO,YAAY,SAAS;AAAA,gBACrC,EAAE,OAAO,YAAY,YAAY,SAAS;AAAA,cAC5C;AAAA,cACA,aAAa,CAAC,EAAE,OAAO,UAAU,YAAY,SAAS,CAAC;AAAA,YACzD;AAAA,YACA,YAAY;AAAA,YACZ,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAEA,cAAM,aAAa,KAAK,YAAY,CAAC;AACrC,4BAAoB,WAAW;AAE/B,mBAAW,KAAK,YAAY;AAC1B,gBAAM,gBAAgB,EAAE,UAAU,SAAS;AAC3C,gBAAM,QAAQ,kBAAkB,aAAa;AAC7C,cAAI,UAAU,KAAM;AAEpB,gBAAM,WAAW,kBAAkB,KAAK;AACxC,gBAAM,aAAa,EAAE,YAAY,CAAC,GAAG,MAAM;AAC3C,gBAAM,eAAe,EAAE,YAAY,CAAC,GAAG,QAAQ;AAC/C,gBAAM,cAAc,WAAW,WAAW,MAAM,IAC5C,aACA,OAAO,SAAS,gBAAgB,MAAM,IAAI,SAAS,YAAY,EAAE,MAAM,SAAS;AAEpF,gBAAM,mBAA6B,CAAC;AACpC,cAAI,EAAE,aAAa,gBAAgB,MAAM;AACvC,6BAAiB,KAAK,EAAE,YAAY,eAAe,IAAI;AAAA,UACzD;AACA,cAAI,EAAE,aAAa,gBAAgB,KAAK;AACtC,6BAAiB,KAAK,cAAc,EAAE,YAAY,eAAe,GAAG,EAAE;AAAA,UACxE;AACA,cAAI,iBAAiB,WAAW,GAAG;AACjC,6BAAiB,KAAK,4FAA4F;AAAA,UACpH;AAEA,mBAAS,KAAK;AAAA,YACZ;AAAA,YACA,OAAO,EAAE,SAAS;AAAA,YAClB;AAAA,YACA;AAAA,YACA;AAAA,YACA,QAAQ,EAAE,UAAU;AAAA,YACpB,aAAa,EAAE,eAAe,EAAE,SAAS;AAAA,YACzC,QAAQ,WAAW,EAAE,eAAe,cAAc,KAAK,EAAE,eAAe,SAAS;AAAA,YACjF,WAAW;AAAA,YACX;AAAA,YACA,UAAU,qBAAqB,QAAQ;AAAA,YACvC,QAAQ,KAAK;AAAA,YACb,WAAW,EAAE,gBAAgB;AAAA,UAC/B,CAAC;AAAA,QACH;AAEA,oBAAY,KAAK;AAAA,MACnB,SAAS;AAET,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAMC,gBACH,eAAe,SAAS,IAAI,SAAS,4BACtC,IAAI,SAAS,gBAAgB,KAC7B,IAAI,SAAS,aAAa;AAE5B,UAAIA,eAAc;AAChB,iBAAS,KAAK,uFAAuF;AACrG,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,sCAAsC,GAAG;AAAA,QAChD,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;ACxIA;AAAA,EACE,mBAAAC;AAAA,EACA,wBAAAC;AAAA,EACA;AAAA,EACA,sBAAAC;AAAA,OACK;AAMP,SAAS,kBAAkB,UAA0B;AACnD,MAAI,YAAY,EAAK,QAAO;AAC5B,MAAI,YAAY,EAAK,QAAO;AAC5B,SAAO;AACT;AAEO,IAAM,2BAAN,MAAkD;AAAA,EAC9C,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AACF,YAAM,SAAS,aAAaC,kBAAiB,QAAQ,IAAI,WAAW;AAGpE,YAAM,gBAAgB,MAAM,OAAO,KAAK,IAAIC,sBAAqB,CAAC,CAAC,CAAC;AACpE,YAAM,cAAc,cAAc,eAAe,CAAC;AAElD,UAAI,YAAY,WAAW,GAAG;AAC5B,iBAAS,KAAK,+DAA+D;AAC7E,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAEA,YAAM,aAAa,YAAY,CAAC;AAGhC,UAAI;AACJ,YAAM,aAAuB,CAAC;AAE9B,SAAG;AACD,cAAM,WAAW,MAAM,OAAO;AAAA,UAC5B,IAAI,oBAAoB;AAAA,YACtB,YAAY;AAAA,YACZ,iBAAiB;AAAA,cACf,WAAW;AAAA,gBACT,oBAAoB;AAAA,kBAClB,IAAI,CAAC,OAAO;AAAA,gBACd;AAAA,cACF;AAAA,YACF;AAAA,YACA,YAAY;AAAA,YACZ,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA,mBAAW,KAAK,GAAI,SAAS,cAAc,CAAC,CAAE;AAC9C,oBAAY,SAAS;AAAA,MACvB,SAAS;AAET,yBAAmB,WAAW;AAE9B,UAAI,WAAW,WAAW,GAAG;AAC3B,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,UAC3C,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAGA,eAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,IAAI;AAC9C,cAAM,QAAQ,WAAW,MAAM,GAAG,IAAI,EAAE;AACxC,cAAM,cAAc,MAAM,OAAO;AAAA,UAC/B,IAAIC,oBAAmB;AAAA,YACrB,YAAY;AAAA,YACZ,YAAY;AAAA,UACd,CAAC;AAAA,QACH;AAEA,mBAAW,OAAO,YAAY,YAAY,CAAC,GAAG;AAC5C,gBAAM,aAAa,IAAI,YAAY;AACnC,gBAAM,QAAQ,kBAAkB,UAAU;AAC1C,gBAAM,WAAW,kBAAkB,KAAK;AAExC,gBAAM,eAAe,IAAI,UAAU,gBAAgB;AACnD,gBAAM,aAAa,IAAI,UAAU,iBAAiB,cAC7C,IAAI,UAAU,kBAAkB,eAChC,IAAI,OACJ;AACL,gBAAM,cAAc,IAAI,OACnB,OAAO,SAAS,cAAc,MAAM,IAAI,SAAS,aAAa,UAAU,YAAY,IAAI,MAAM,SAAS;AAE5G,mBAAS,KAAK;AAAA,YACZ;AAAA,YACA,OAAO,eAAe,IAAI,SAAS,IAAI,QAAQ,SAAS;AAAA,YACxD;AAAA,YACA;AAAA,YACA;AAAA,YACA,QAAQ,IAAI,UAAU;AAAA,YACtB,aAAa,IAAI,eAAe,IAAI,SAAS;AAAA,YAC7C,QAAQ,0BAA0B,IAAI,QAAQ,SAAS,cAAc,UAAU;AAAA,YAC/E,WAAW;AAAA,YACX,kBAAkB;AAAA,cAChB;AAAA,cACA,iBAAiB,IAAI,QAAQ,SAAS;AAAA,cACtC;AAAA,YACF;AAAA,YACA,UAAU,qBAAqB,QAAQ;AAAA,YACvC,QAAQ,KAAK;AAAA,YACb,WAAW,IAAI,aAAa;AAAA,UAC9B,CAAC;AAAA,QACH;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,mCAAmC,GAAG;AAAA,QAC7C,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AC1JA;AAAA,EACE,oBAAAC;AAAA,EACA,uBAAAC;AAAA,OAEK;AAMP,SAAS,yBAAyB,OAA8B;AAC9D,UAAQ,OAAO;AAAA,IACb,KAAK;AAAY,aAAO;AAAA,IACxB,KAAK;AAAQ,aAAO;AAAA,IACpB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAO,aAAO;AAAA,IACnB,KAAK;AAAiB,aAAO;AAAA,IAC7B,KAAK;AAAa,aAAO;AAAA,IACzB;AAAS,aAAO;AAAA,EAClB;AACF;AAEO,IAAM,2BAAN,MAAkD;AAAA,EAC9C,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AACF,YAAM,SAAS,aAAaC,mBAAkB,QAAQ,IAAI,WAAW;AACrE,UAAI;AAEJ,YAAM,iBAAiC;AAAA,QACrC,eAAe,CAAC,EAAE,YAAY,UAAU,OAAO,SAAS,CAAC;AAAA,MAC3D;AAEA,SAAG;AACD,cAAM,OAAO,MAAM,OAAO;AAAA,UACxB,IAAIC,qBAAoB;AAAA,YACtB;AAAA,YACA,YAAY;AAAA,YACZ;AAAA,UACF,CAAC;AAAA,QACH;AAEA,cAAM,eAAe,KAAK,YAAY,CAAC;AACvC,4BAAoB,aAAa;AAEjC,mBAAW,KAAK,cAAc;AAC5B,gBAAM,gBAAgB,EAAE,YAAY;AACpC,gBAAM,QAAQ,yBAAyB,aAAa;AACpD,cAAI,UAAU,KAAM;AAEpB,gBAAM,WAAW,kBAAkB,KAAK;AAGxC,gBAAM,QAAQ,EAAE,6BAA6B;AAC7C,gBAAM,YAAY,EAAE,SAAS;AAC7B,gBAAM,QAAQ,QAAQ,IAAI,KAAK,KAAK,SAAS,KAAK;AAElD,gBAAM,aAAa,EAAE,YAAY,CAAC,GAAG,MAAM;AAC3C,gBAAM,eAAe,EAAE,YAAY,CAAC,GAAG,QAAQ;AAC/C,gBAAM,cAAc,WAAW,WAAW,MAAM,IAC5C,aACA,OAAO,SAAS,eAAe,MAAM,IAAI,SAAS,YAAY,EAAE,cAAc,SAAS;AAE3F,gBAAM,mBAA6B,CAAC;AACpC,cAAI,EAAE,aAAa,gBAAgB,MAAM;AACvC,6BAAiB,KAAK,EAAE,YAAY,eAAe,IAAI;AAAA,UACzD;AACA,cAAI,EAAE,aAAa,gBAAgB,KAAK;AACtC,6BAAiB,KAAK,cAAc,EAAE,YAAY,eAAe,GAAG,EAAE;AAAA,UACxE;AACA,cAAI,EAAE,6BAA6B,eAAe,QAAQ;AACxD,6BAAiB,KAAK,mBAAmB,EAAE,4BAA4B,cAAc,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,UAC/G;AACA,cAAI,iBAAiB,WAAW,GAAG;AACjC,6BAAiB,KAAK,+FAA+F;AAAA,UACvH;AAEA,gBAAM,cAAc,EAAE,eAAe;AACrC,gBAAM,SAAS,QACX,iBAAiB,KAAK,iBAAY,EAAE,6BAA6B,OAAO,CAAC,GAAG,aAAa,KAAK,KAC9F,2BAA2B,EAAE,QAAQ,SAAS;AAElD,mBAAS,KAAK;AAAA,YACZ;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,WAAW;AAAA,YACX;AAAA,YACA,UAAU,qBAAqB,QAAQ;AAAA,YACvC,QAAQ,KAAK;AAAA,YACb,WAAW,EAAE,gBAAgB;AAAA,UAC/B,CAAC;AAAA,QACH;AAEA,oBAAY,KAAK;AAAA,MACnB,SAAS;AAET,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAM,UAAU,eAAe,QAAQ,IAAI,OAAO;AAElD,YAAMC,kBAAiB,YAAY,2BAA2B,IAAI,SAAS,uBAAuB;AAClG,YAAMC,gBAAe,IAAI,SAAS,aAAa,KAAK,IAAI,SAAS,gBAAgB;AAEjF,UAAID,iBAAgB;AAClB,iBAAS,KAAK,0GAA0G;AACxH,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAEA,UAAIC,eAAc;AAChB,iBAAS,KAAK,0FAA0F;AACxG,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,mCAAmC,GAAG;AAAA,QAC7C,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;ACnKA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAKP,SAAS,gBAAgB,QAA+B;AACtD,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAS,aAAO;AAAA;AAAA,IACrB,KAAK;AAAW,aAAO;AAAA;AAAA,IACvB,KAAK;AAAM,aAAO;AAAA;AAAA,IAClB,KAAK;AAAiB,aAAO;AAAA,IAC7B;AAAS,aAAO;AAAA,EAClB;AACF;AAEO,IAAM,gCAAN,MAAuD;AAAA,EACnD,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AAEF,YAAM,gBAAgB,OAAO,WAAW,KAAK,IAAI,eAAe;AAChE,YAAM,eAAoB,EAAE,QAAQ,cAAc;AAClD,UAAI,IAAI,YAAa,cAAa,cAAc,IAAI;AACpD,YAAM,SAAS,IAAI,cAAc,YAAY;AAG7C,YAAM,aAAa,MAAM,OAAO;AAAA,QAC9B,IAAI,oCAAoC,EAAE,UAAU,KAAK,CAAC;AAAA,MAC5D;AACA,YAAM,YAAY,WAAW,UAAU,CAAC;AACxC,YAAM,iBAAiB,UAAU,OAAO,CAAC,MAAM,EAAE,aAAa,UAAU;AAExE,UAAI,eAAe,WAAW,GAAG;AAC/B,iBAAS,KAAK,2CAA2C;AACzD,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAGA,iBAAW,SAAS,gBAAgB;AAClC,YAAI,CAAC,MAAM,GAAI;AAEf,YAAI;AACF,gBAAM,aAAa,MAAM,OAAO;AAAA,YAC9B,IAAI,yCAAyC;AAAA,cAC3C,SAAS,MAAM;AAAA,YACjB,CAAC;AAAA,UACH;AAEA,gBAAM,SAAS,WAAW;AAC1B,cAAI,CAAC,OAAQ;AAEb,gBAAM,SAAS,OAAO,UAAU;AAChC,gBAAM,QAAQ,gBAAgB,MAAM;AAEpC;AAEA,cAAI,UAAU,KAAM;AAGpB,gBAAM,mBAAmB,OAAO,oBAAoB,CAAC;AAErD,cAAI,iBAAiB,WAAW,GAAG;AAEjC,kBAAM,WAAW,kBAAkB,KAAK;AACxC,qBAAS,KAAK;AAAA,cACZ;AAAA,cACA,OAAO,qBAAqB,MAAM,QAAQ,gBAAgB;AAAA,cAC1D,cAAc;AAAA,cACd,YAAY,MAAM;AAAA,cAClB,aAAa,OAAO,SAAS,mBAAmB,MAAM,IAAI,SAAS,UAAU,MAAM,EAAE;AAAA,cACrF;AAAA,cACA,aAAa,MAAM,eAAe,MAAM,QAAQ;AAAA,cAChD,QAAQ,2BAA2B,MAAM;AAAA,cACzC,WAAW;AAAA,cACX,kBAAkB;AAAA,gBAChB;AAAA,gBACA;AAAA,cACF;AAAA,cACA,UAAU,qBAAqB,QAAQ;AAAA,cACvC,QAAQ,KAAK;AAAA,cACb;AAAA,YACF,CAAC;AACD;AAAA,UACF;AAGA,gBAAM,WAAW,MAAM,YAAY,CAAC;AACpC,qBAAW,MAAM,iBAAiB,MAAM,GAAG,EAAE,GAAG;AAC9C,gBAAI,GAAG,aAAc;AAErB,kBAAM,WAAW,kBAAkB,KAAK;AACxC,kBAAM,eAAe,GAAG,YAAY,CAAC;AAGrC,kBAAM,gBAAgB,SAAS,QAAQ,aAAa;AACpD,kBAAM,YAAY,SAAS,QAAQ,QAAQ;AAC3C,kBAAM,oBAAoB,iBAAiB,KAAK,aAAa,aAAa,IACtE,aAAa,aAAa,IAC1B,GAAG,cAAc;AACrB,kBAAM,gBAAgB,aAAa,KAAK,aAAa,SAAS,IAC1D,aAAa,SAAS,IACtB;AAEJ,qBAAS,KAAK;AAAA,cACZ;AAAA,cACA,OAAO,qBAAqB,MAAM,QAAQ,gBAAgB,KAAK,iBAAiB;AAAA,cAChF,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,aAAa,OAAO,SAAS,mBAAmB,aAAa,IAAI,SAAS,UAAU,MAAM,EAAE,IAAI,GAAG,cAAc,SAAS;AAAA,cAC1H,QAAQ;AAAA,cACR,aAAa,GAAG,MAAM,IAAI,KAAK,aAAa,KAAK,KAAK,CAAC;AAAA,cACvD,QAAQ,2BAA2B,MAAM,WAAM,MAAM,QAAQ,gBAAgB;AAAA,cAC7E,WAAW;AAAA,cACX,kBAAkB;AAAA,gBAChB,iCAAiC,MAAM,IAAI;AAAA,gBAC3C;AAAA,cACF;AAAA,cACA,UAAU,qBAAqB,QAAQ;AAAA,cACvC,QAAQ,KAAK;AAAA,cACb;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,SAAS,UAAU;AACjB,gBAAM,WAAW,oBAAoB,QAAQ,SAAS,UAAU,OAAO,QAAQ;AAC/E,mBAAS,KAAK,yBAAyB,MAAM,QAAQ,MAAM,EAAE,YAAY,QAAQ,EAAE;AAAA,QACrF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAM,yBACJ,IAAI,SAAS,+BAA+B,KAC5C,IAAI,SAAS,cAAc,KAC3B,IAAI,SAAS,qBAAqB,KACjC,eAAe,SAAS,IAAI,SAAS;AAExC,UAAI,wBAAwB;AAC1B,iBAAS,KAAK,6EAA6E;AAC3F,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,gCAAgC,GAAG;AAAA,QAC1C,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AC7LA;AAAA,EACE,uBAAAC;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAOP,IAAM,yBAAyB;AAAA,EAC7B;AAAA,EAAiB;AAAA,EACjB;AAAA,EAAc;AAAA,EACd;AAAA,EAAU;AAAA,EACV;AAAA,EAAO;AAAA,EAAY;AAAA,EACnB;AAAA,EAAQ;AAAA,EACR;AAAA,EAAW;AAAA,EACX;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EACrB;AAAA,EAAY;AAAA,EAAa;AAC3B;AAEA,SAAS,sBAAsB,UAA2B;AACxD,QAAM,QAAQ,SAAS,YAAY;AACnC,SAAO,uBAAuB,KAAK,CAAC,QAAQ,MAAM,SAAS,GAAG,CAAC;AACjE;AAEO,IAAM,6BAAN,MAAoD;AAAA,EAChD,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AACF,YAAM,SAAS,aAAaC,sBAAqB,QAAQ,IAAI,WAAW;AAGxE,UAAI;AACJ,YAAM,oBAA8C,CAAC;AAErD,SAAG;AACD,cAAM,OAAO,MAAM,OAAO;AAAA,UACxB,IAAI,sCAAsC,EAAE,WAAW,UAAU,CAAC;AAAA,QACpE;AAEA,mBAAW,QAAQ,KAAK,2BAA2B,CAAC,GAAG;AACrD;AACA,cAAI,KAAK,YAAY,mBAAmB,iBAAiB;AACvD,8BAAkB,KAAK,IAAI;AAAA,UAC7B;AAAA,QACF;AAEA,oBAAY,KAAK;AAAA,MACnB,SAAS;AAET,UAAI,qBAAqB,GAAG;AAC1B,iBAAS,KAAK,0EAA0E;AACxF,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAGA,iBAAW,QAAQ,mBAAmB;AACpC,cAAM,WAAW,KAAK,kBAAkB;AAExC,YAAI;AACF,cAAI;AACJ,aAAG;AACD,kBAAM,aAAa,MAAM,OAAO;AAAA,cAC9B,IAAI,wCAAwC;AAAA,gBAC1C,gBAAgB;AAAA,gBAChB,iBAAiB,CAAC,eAAe;AAAA,gBACjC,WAAW;AAAA,cACb,CAAC;AAAA,YACH;AAEA,uBAAW,cAAc,WAAW,qBAAqB,CAAC,GAAG;AAC3D,oBAAM,YAAY,WAAW,4BAA4B;AACzD,oBAAM,eAAe,WAAW,gBAAgB;AAChD,oBAAM,aAAa,WAAW,cAAc;AAC5C,oBAAM,aAAa,WAAW;AAE9B,oBAAM,iBAAiB,sBAAsB,QAAQ;AACrD,oBAAM,YAAY,iBAAiB,MAAM;AACzC,oBAAM,WAAW,kBAAkB,SAAS;AAE5C,oBAAM,YAAY,CAAC,gBAAgB,QAAQ,IAAI,kBAAkB,YAAY,EAAE;AAC/E,kBAAI,WAAY,WAAU,KAAK,eAAe,UAAU,EAAE;AAE1D,uBAAS,KAAK;AAAA,gBACZ;AAAA,gBACA,OAAO,gBAAgB,QAAQ,MAAM,YAAY,IAAI,UAAU;AAAA,gBAC/D;AAAA,gBACA;AAAA,gBACA,aAAa;AAAA,gBACb;AAAA,gBACA,aAAa,UAAU,KAAK,IAAI;AAAA,gBAChC,QAAQ,+CAA+C,QAAQ;AAAA,gBAC/D;AAAA,gBACA,kBAAkB;AAAA,kBAChB,2BAA2B,QAAQ;AAAA,kBACnC,kBAAkB,UAAU;AAAA,kBAC5B;AAAA,gBACF;AAAA,gBACA,UAAU,qBAAqB,QAAQ;AAAA,gBACvC,QAAQ,KAAK;AAAA,gBACb;AAAA,cACF,CAAC;AAAA,YACH;AAEA,0BAAc,WAAW;AAAA,UAC3B,SAAS;AAAA,QACX,SAAS,WAAW;AAClB,gBAAM,MAAM,qBAAqB,QAAQ,UAAU,UAAU,OAAO,SAAS;AAC7E,mBAAS,KAAK,kCAAkC,QAAQ,KAAK,GAAG,EAAE;AAAA,QACpE;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAG3D,UACE,IAAI,SAAS,6BAA6B,KAC1C,IAAI,SAAS,4BAA4B,KACzC,IAAI,SAAS,2BAA2B,GACxC;AACA,iBAAS,KAAK,2CAA2C;AACzD,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,6BAA6B,GAAG;AAAA,QACvC,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AC5KA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAOP,SAAS,mBAAmB,aAAyC;AACnE,QAAM,KAAK;AACX,UAAQ,IAAI;AAAA,IACV,KAAK;AAAkB,aAAO;AAAA,IAC9B,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAyB,aAAO;AAAA,IACrC,KAAK;AAAoB,aAAO;AAAA,IAChC;AAAS,aAAO;AAAA,EAClB;AACF;AAEA,IAAM,uBAAuB,oBAAI,IAAI;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,mBAAmB,aAA0C;AACpE,QAAM,KAAK;AACX,SAAO,OAAO,oBAAoB,qBAAqB,IAAI,MAAM,EAAE;AACrE;AAEA,SAAS,iBAAiB,aAA0C;AAClE,SAAQ,gBAAuC;AACjD;AAEO,IAAM,gCAAN,MAAuD;AAAA,EACnD,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AACF,YAAM,SAAS,aAAa,sBAAsB,QAAQ,IAAI,WAAW;AAGzE,UAAI;AACJ,YAAM,YAA+B,CAAC;AAEtC,SAAG;AACD,cAAM,OAAO,MAAM,OAAO;AAAA,UACxB,IAAI,qBAAqB,EAAE,WAAW,cAAc,CAAC;AAAA,QACvD;AACA,mBAAW,YAAY,KAAK,aAAa,CAAC,GAAG;AAC3C,cAAI,SAAS,WAAW,UAAU;AAChC,sBAAU,KAAK,QAAQ;AAAA,UACzB;AAAA,QACF;AACA,wBAAgB,KAAK;AAAA,MACvB,SAAS;AAET,UAAI,UAAU,WAAW,GAAG;AAC1B,iBAAS,KAAK,+FAA+F;AAC7G,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAGA,iBAAW,YAAY,WAAW;AAChC,cAAM,cAAc,SAAS,OAAO;AAEpC,YAAI;AACJ,WAAG;AACD,gBAAM,WAAW,MAAM,OAAO;AAAA,YAC5B,IAAI,sBAAsB;AAAA,cACxB;AAAA,cACA,QAAQ;AAAA,gBACN,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;AAAA,cAC3B;AAAA,cACA,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AAEA,qBAAW,OAAO,SAAS,YAAY,CAAC,GAAG;AAEzC,gBAAI,CAAC,mBAAmB,IAAI,WAAW,GAAG;AACxC;AAAA,YACF;AAEA;AACA,kBAAM,QAAQ,mBAAmB,IAAI,WAAW;AAChD,kBAAM,WAAW,kBAAkB,KAAK;AAExC,kBAAM,cAAc,IAAI,YAAY;AACpC,kBAAM,eAAe,IAAI,gBAAgB;AACzC,kBAAM,aAAa,YAAY,MAAM,GAAG,EAAE,IAAI,KAAK,YAAY,MAAM,GAAG,EAAE,IAAI,KAAK;AACnF,kBAAM,WAAW,iBAAiB,IAAI,WAAW;AAEjD,kBAAM,YAAY,CAAC,kBAAkB,YAAY,EAAE;AACnD,gBAAI,IAAI,qBAAsB,WAAU,KAAK,kBAAkB,IAAI,oBAAoB,EAAE;AACzF,gBAAI,IAAI,YAAa,WAAU,KAAK,iBAAiB,IAAI,WAAW,EAAE;AAEtE,kBAAM,QAAQ,kBAAkB,GAAG;AAEnC,kBAAM,SAAS,WACX,0DAA0D,IAAI,eAAe,SAAS,KACtF,oFAA+E,IAAI,eAAe,SAAS;AAE/G,kBAAM,mBAAmB,WACrB;AAAA,cACE;AAAA,cACA,kBAAkB,UAAU;AAAA,cAC5B;AAAA,YACF,IACA;AAAA,cACE;AAAA,cACA,kBAAkB,UAAU;AAAA,cAC5B;AAAA,YACF;AAEJ,qBAAS,KAAK;AAAA,cACZ;AAAA,cACA;AAAA,cACA,cAAc,gBAAgB,YAAY;AAAA,cAC1C;AAAA,cACA;AAAA,cACA;AAAA,cACA,aAAa,UAAU,KAAK,IAAI;AAAA,cAChC;AAAA,cACA,WAAW;AAAA,cACX;AAAA,cACA,UAAU,qBAAqB,QAAQ;AAAA,cACvC,QAAQ,KAAK;AAAA,cACb,WAAW,IAAI,wBAAwB;AAAA,YACzC,CAAC;AAAA,UACH;AAEA,yBAAe,SAAS;AAAA,QAC1B,SAAS;AAAA,MACX;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,gCAAgC,GAAG;AAAA,QAC1C,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,SAAmC;AAC5D,QAAM,eAAe,QAAQ,gBAAgB;AAC7C,QAAM,WAAW,QAAQ,WACpB,QAAQ,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK,QAAQ,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK,QAAQ,WACnF;AACJ,QAAM,QAAQ,iBAAiB,QAAQ,WAAW,IAC9C,6BACA;AACJ,SAAO,qBAAqB,YAAY,IAAI,QAAQ,WAAM,KAAK;AACjE;AAEA,SAAS,gBAAgB,QAAwB;AAC/C,QAAM,UAAkC;AAAA,IACtC,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,yBAAyB;AAAA,IACzB,6BAA6B;AAAA,IAC7B,iBAAiB;AAAA,IACjB,+BAA+B;AAAA,IAC/B,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,+BAA+B;AAAA,IAC/B,wBAAwB;AAAA,EAC1B;AACA,SAAO,QAAQ,MAAM,KAAK;AAC5B;;;ACjNA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAMA,IAAM,iCAAN,MAAwD;AAAA,EACpD,aAAa;AAAA,EAEtB,MAAM,KAAK,KAAuC;AAChD,UAAM,EAAE,QAAQ,WAAW,UAAU,IAAI;AACzC,UAAM,UAAU,KAAK,IAAI;AACzB,UAAM,WAAsB,CAAC;AAC7B,UAAM,WAAqB,CAAC;AAC5B,QAAI,mBAAmB;AAEvB,QAAI;AACF,YAAM,SAAS,aAAa,WAAW,QAAQ,IAAI,WAAW;AAG9D,UAAI;AACJ,YAAM,YAAmC,CAAC;AAE1C,SAAG;AACD,cAAM,OAAO,MAAM,OAAO;AAAA,UACxB,IAAI,mCAAmC;AAAA,YACrC,YAAY;AAAA,YACZ,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AACA,kBAAU,KAAK,GAAI,KAAK,2BAA2B,CAAC,CAAE;AACtD,oBAAY,KAAK;AAAA,MACnB,SAAS;AAET,UAAI,UAAU,WAAW,GAAG;AAC1B,iBAAS,KAAK,gDAAgD;AAC9D,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,QAAQ;AAAA,UACR;AAAA,UACA,kBAAkB;AAAA,UAClB,eAAe;AAAA,UACf,YAAY,KAAK,IAAI,IAAI;AAAA,UACzB,UAAU,CAAC;AAAA,QACb;AAAA,MACF;AAEA,yBAAmB,UAAU;AAG7B,YAAM,cAAc,UAAU,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,OAAO;AACrE,YAAM,gBAAgB,oBAAI,IAAgC;AAG1D,eAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK,IAAI;AAC/C,cAAM,QAAQ,YAAY,MAAM,GAAG,IAAI,EAAE;AACzC,YAAI;AAEJ,WAAG;AACD,gBAAM,YAAY,MAAM,OAAO;AAAA,YAC7B,IAAI,mCAAmC;AAAA,cACrC,aAAa;AAAA,cACb,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AAEA,qBAAW,MAAM,UAAU,uBAAuB,CAAC,GAAG;AACpD,gBAAI,GAAG,YAAY;AACjB,4BAAc,IAAI,GAAG,YAAY,EAAE;AAAA,YACrC;AAAA,UACF;AAEA,uBAAa,UAAU;AAAA,QACzB,SAAS;AAAA,MACX;AAGA,iBAAW,YAAY,WAAW;AAChC,cAAM,aAAa,SAAS,cAAc;AAC1C,cAAM,WAAW,SAAS,gBAAgB,SAAS,gBAAgB;AACnE,cAAM,cAAc,OAAO,SAAS,QAAQ,MAAM,IAAI,SAAS,aAAa,UAAU;AAEtF,cAAM,aAAa,cAAc,IAAI,UAAU;AAE/C,YAAI,CAAC,YAAY;AAEf,gBAAMC,aAAY;AAClB,gBAAMC,YAAW,kBAAkBD,UAAS;AAC5C,mBAAS,KAAK;AAAA,YACZ,UAAAC;AAAA,YACA,OAAO,YAAY,UAAU;AAAA,YAC7B,cAAc;AAAA,YACd,YAAY;AAAA,YACZ,aAAa;AAAA,YACb;AAAA,YACA,aAAa,YAAY,UAAU,KAAK,QAAQ;AAAA,YAChD,QAAQ;AAAA,YACR,WAAAD;AAAA,YACA,kBAAkB;AAAA,cAChB;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,YACA,UAAU,qBAAqBC,SAAQ;AAAA,YACvC,QAAQ,KAAK;AAAA,YACb;AAAA,UACF,CAAC;AACD;AAAA,QACF;AAEA,cAAM,eAAe,WAAW,gBAAgB;AAChD,cAAM,cAAc,WAAW,eAAe;AAC9C,cAAM,4BAA4B,WAAW,6BAA6B;AAC1E,cAAM,4BAA4B,WAAW,6BAA6B;AAC1E,cAAM,yBAAyB,WAAW,0BAA0B;AACpE,cAAM,eAAe,WAAW,kBAAkB,YAAY,KAAK;AAEnE,YACE,iBAAiB,KACjB,gBAAgB,KAChB,8BAA8B,KAC9B,8BAA8B,KAC9B,2BAA2B,GAC3B;AACA;AAAA,QACF;AAGA,YAAI;AACJ,YAAI,4BAA4B,KAAK,4BAA4B,KAAK,cAAc,GAAG;AACrF,sBAAY;AAAA,QACd,WAAW,yBAAyB,GAAG;AACrC,sBAAY;AAAA,QACd,OAAO;AACL,sBAAY;AAAA,QACd;AACA,cAAM,WAAW,kBAAkB,SAAS;AAE5C,cAAM,aAAuB,CAAC;AAC9B,YAAI,eAAe,EAAG,YAAW,KAAK,GAAG,YAAY,UAAU;AAC/D,YAAI,cAAc,EAAG,YAAW,KAAK,GAAG,WAAW,SAAS;AAC5D,YAAI,4BAA4B,EAAG,YAAW,KAAK,GAAG,yBAAyB,yBAAyB;AACxG,YAAI,4BAA4B,EAAG,YAAW,KAAK,GAAG,yBAAyB,yBAAyB;AACxG,YAAI,yBAAyB,EAAG,YAAW,KAAK,GAAG,sBAAsB,sBAAsB;AAE/F,cAAM,YAAY;AAAA,UAChB,aAAa,UAAU;AAAA,UACvB,aAAa,QAAQ;AAAA,UACrB,oBAAoB,YAAY;AAAA,UAChC,mBAAmB,WAAW;AAAA,UAC9B,2BAA2B,yBAAyB;AAAA,UACpD,2BAA2B,yBAAyB;AAAA,UACpD,wBAAwB,sBAAsB;AAAA,UAC9C,cAAc,YAAY;AAAA,QAC5B;AAEA,iBAAS,KAAK;AAAA,UACZ;AAAA,UACA,OAAO,YAAY,UAAU,QAAQ,WAAW,KAAK,IAAI,CAAC;AAAA,UAC1D,cAAc;AAAA,UACd,YAAY;AAAA,UACZ,aAAa;AAAA,UACb;AAAA,UACA,aAAa,UAAU,KAAK,IAAI;AAAA,UAChC,QAAQ,gBAAgB,YAAY,gBAAgB,WAAW;AAAA,UAC/D;AAAA,UACA,kBAAkB;AAAA,YAChB,wCAAwC,UAAU;AAAA,YAClD;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACA,UAAU,qBAAqB,QAAQ;AAAA,UACvC,QAAQ,KAAK;AAAA,UACb;AAAA,QACF,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe,SAAS;AAAA,QACxB,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,OAAO,iCAAiC,GAAG;AAAA,QAC3C,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,QAC3C;AAAA,QACA,eAAe;AAAA,QACf,YAAY,KAAK,IAAI,IAAI;AAAA,QACzB,UAAU,CAAC;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;;;AC7MA,IAAM,gBAA0C;AAAA,EAC9C,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AACP;AAEA,IAAM,iBAA6B,CAAC,YAAY,QAAQ,UAAU,KAAK;AAEvE,SAAS,eAAe,OAAe,KAAqB;AAC1D,QAAM,KAAK,IAAI,KAAK,GAAG,EAAE,QAAQ,IAAI,IAAI,KAAK,KAAK,EAAE,QAAQ;AAC7D,MAAI,KAAK,IAAM,QAAO,GAAG,EAAE;AAC3B,QAAM,OAAO,KAAK,MAAM,KAAK,GAAI;AACjC,MAAI,OAAO,GAAI,QAAO,GAAG,IAAI;AAC7B,QAAM,OAAO,KAAK,MAAM,OAAO,EAAE;AACjC,QAAM,aAAa,OAAO;AAC1B,SAAO,GAAG,IAAI,KAAK,UAAU;AAC/B;AAEA,SAAS,cAAc,GAAoB;AACzC,QAAM,QAAQ,EAAE,iBACb,IAAI,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,EAAE,EAChC,KAAK,IAAI;AAEZ,SAAO;AAAA,IACL,QAAQ,EAAE,KAAK;AAAA,IACf,mBAAmB,EAAE,UAAU,OAAO,EAAE,WAAW;AAAA,IACnD,sBAAsB,EAAE,WAAW;AAAA,IACnC,iBAAiB,EAAE,MAAM;AAAA,IACzB,qBAAqB,EAAE,SAAS;AAAA,IAChC;AAAA,IACA;AAAA,IACA,mBAAmB,EAAE,QAAQ;AAAA,EAC/B,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,uBAAuB,aAAqC;AAC1E,QAAM,EAAE,SAAS,SAAS,WAAW,QAAQ,WAAW,QAAQ,IAC9D;AACF,QAAM,OAAO,UAAU,MAAM,GAAG,EAAE,CAAC;AACnC,QAAM,WAAW,eAAe,WAAW,OAAO;AAElD,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,qCAAgC,IAAI,EAAE;AACjD,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,sBAAsB;AACjC,QAAM,KAAK,kBAAkB,SAAS,EAAE;AACxC,QAAM,KAAK,iBAAiB,MAAM,EAAE;AACpC,QAAM,KAAK,wBAAwB,QAAQ,EAAE;AAC7C,QAAM;AAAA,IACJ,yBAAyB,QAAQ,aAAa,eAAQ,QAAQ,QAAQ,yBAAkB,QAAQ,IAAI,qBAAc,QAAQ,MAAM,uBAAgB,QAAQ,GAAG;AAAA,EAC7J;AACA,QAAM,KAAK,EAAE;AAGb,MAAI,QAAQ,kBAAkB,GAAG;AAC/B,UAAM,KAAK,yBAAyB;AACpC,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,kCAA6B;AACxC,UAAM,KAAK,EAAE;AAAA,EACf,OAAO;AAEL,UAAM,cAAyB,QAAQ,QAAQ,CAAC,MAAM,EAAE,QAAQ;AAGhE,UAAM,UAAU,oBAAI,IAAyB;AAC7C,eAAW,OAAO,gBAAgB;AAChC,cAAQ,IAAI,KAAK,CAAC,CAAC;AAAA,IACrB;AACA,eAAW,KAAK,aAAa;AAC3B,cAAQ,IAAI,EAAE,QAAQ,EAAG,KAAK,CAAC;AAAA,IACjC;AAEA,UAAM,KAAK,yBAAyB;AACpC,UAAM,KAAK,EAAE;AAEb,eAAW,OAAO,gBAAgB;AAChC,YAAM,WAAW,QAAQ,IAAI,GAAG;AAChC,YAAM,OAAO,cAAc,GAAG;AAC9B,YAAM,KAAK,OAAO,IAAI,IAAI,IAAI,OAAO,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,EAAE,YAAY,CAAC,EAAE;AACtE,YAAM,KAAK,EAAE;AAEb,UAAI,SAAS,WAAW,GAAG;AACzB,cAAM,KAAK,MAAM,IAAI,YAAY,CAAC,YAAY;AAC9C,cAAM,KAAK,EAAE;AACb;AAAA,MACF;AAGA,eAAS,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AACjD,iBAAW,KAAK,UAAU;AACxB,cAAM,KAAK,cAAc,CAAC,CAAC;AAC3B,cAAM,KAAK,EAAE;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAGA,QAAM,KAAK,oBAAoB;AAC/B,QAAM;AAAA,IACJ;AAAA,EACF;AACA,QAAM,KAAK,mDAAmD;AAC9D,aAAW,KAAK,SAAS;AACvB,UAAM,SAAS,EAAE,WAAW,YAAY,WAAM;AAC9C,UAAM;AAAA,MACJ,KAAK,EAAE,MAAM,MAAM,EAAE,gBAAgB,MAAM,EAAE,aAAa,MAAM,MAAM;AAAA,IACxE;AAAA,EACF;AACA,QAAM,KAAK,EAAE;AAGb,MAAI,QAAQ,gBAAgB,GAAG;AAC7B,UAAM,cAAyB,QAAQ,QAAQ,CAAC,MAAM,EAAE,QAAQ;AAChE,gBAAY,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAEpD,UAAM,KAAK,qCAAqC;AAChD,aAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,YAAM,IAAI,YAAY,CAAC;AACvB,YAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,QAAQ,KAAK,EAAE,KAAK,KAAK,EAAE,iBAAiB,CAAC,KAAK,uBAAuB,EAAE;AAAA,IACxG;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACxHO,IAAM,cAA2B;AAAA;AAAA,EAEtC;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,mBAAmB,mBAAmB,cAAc,mBAAmB,oBAAoB,SAAS,QAAQ;AAAA,EAChI;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,oBAAoB,sBAAsB,SAAS,OAAO;AAAA,EAC9E;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,OAAO,SAAS,OAAO;AAAA,EAC3C;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,4BAA4B,uBAAuB;AAAA,IAC7D,iBAAiB;AAAA,MACf;AAAA,MAAuB;AAAA,MAAmB;AAAA,MAC1C;AAAA,MAAmB;AAAA,MACnB;AAAA,MAAc;AAAA,MAAS;AAAA,MAAgB;AAAA,MACvC;AAAA,MAAmB;AAAA,IACrB;AAAA,EACF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,wBAAwB,uBAAuB;AAAA,IACzD,iBAAiB,CAAC,oBAAoB,cAAc,cAAc,SAAS,cAAc,WAAW,SAAS,kBAAkB,kBAAkB,UAAU,QAAQ;AAAA,EACrK;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,cAAc,eAAe,gBAAgB,eAAe,cAAc;AAAA,EAC9F;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,uBAAuB,iBAAiB,kBAAkB,gBAAgB,cAAc;AAAA,EAC5G;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,cAAc,aAAa,cAAc,cAAc,uBAAuB,gBAAgB,cAAc;AAAA,EAChI;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,qBAAqB,oBAAoB;AAAA,IACnD,iBAAiB,CAAC,WAAW;AAAA,EAC/B;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,qBAAqB,oBAAoB;AAAA,IACnD,iBAAiB,CAAC,aAAa,MAAM;AAAA,EACvC;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,mBAAmB,uBAAuB;AAAA,IACpD,iBAAiB,CAAC,SAAS,OAAO,iBAAiB,eAAe,OAAO;AAAA,EAC3E;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,yBAAyB,iBAAiB,MAAM;AAAA,EACpE;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,0BAA0B,OAAO;AAAA,EACrD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,4BAA4B,OAAO;AAAA,EACvD;AAAA;AAAA,EAEA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,uBAAuB;AAAA,IACjC,iBAAiB,CAAC,eAAe,OAAO;AAAA,EAC1C;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,SAAS,CAAC,wBAAwB,uBAAuB;AAAA,IACzD,iBAAiB,CAAC,oBAAoB,cAAc,cAAc,kBAAkB,UAAU,QAAQ;AAAA,EACxG;AACF;AAEO,IAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,mBAA2C;AAAA,EACtD,4BAAQ;AAAA,EACR,4BAAQ;AAAA,EACR,4BAAQ;AAAA,EACR,4BAAQ;AAAA,EACR,4BAAQ;AAAA,EACR,4BAAQ;AACV;AAQO,SAAS,cACd,OACA,aACA,aACa;AAEb,QAAM,oBAAoB,MAAM,QAAQ;AAAA,IAAM,CAAC,QAC7C,YAAY,KAAK,CAAC,MAAM,EAAE,WAAW,OAAO,EAAE,WAAW,SAAS;AAAA,EACpE;AAEA,MAAI,CAAC,mBAAmB;AACtB,WAAO,EAAE,OAAO,QAAQ,WAAW,iBAAiB,CAAC,EAAE;AAAA,EACzD;AAGA,QAAM,kBAAkB,YAAY,OAAO,CAAC,MAAM;AAChD,UAAM,cAAc,MAAM,QAAQ,KAAK,CAAC,QAAQ,EAAE,WAAW,GAAG;AAChE,QAAI,CAAC,YAAa,QAAO;AAEzB,UAAM,OAAO,GAAG,EAAE,KAAK,IAAI,EAAE,WAAW,GAAG,YAAY;AACvD,WAAO,MAAM,gBAAgB;AAAA,MAAK,CAAC,YACjC,KAAK,SAAS,QAAQ,YAAY,CAAC;AAAA,IACrC;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,QAAQ,gBAAgB,WAAW,IAAI,SAAS;AAAA,IAChD;AAAA,EACF;AACF;AAEO,SAAS,oBAAoB,aAAqC;AACvE,QAAM,EAAE,WAAW,QAAQ,UAAU,IAAI;AACzC,QAAM,WAAW,UAAU,QAAQ,KAAK,GAAG,EAAE,QAAQ,WAAW,MAAM;AAGtE,QAAM,cAAyB,YAAY,QAAQ;AAAA,IAAQ,CAAC,MAC1D,EAAE,SAAS,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE;AAAA,EAChE;AAGA,QAAM,cAAc,YAAY,QAAQ,IAAI,CAAC,OAAO;AAAA,IAClD,QAAQ,EAAE;AAAA,IACV,QAAQ,EAAE;AAAA,EACZ,EAAE;AACF,QAAM,UAAU,YAAY;AAAA,IAAI,CAAC,UAC/B,cAAc,OAAO,aAAa,WAAW;AAAA,EAC/C;AAEA,QAAM,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAC7D,QAAM,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAC7D,QAAM,eAAe,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AACnE,QAAM,eAAe,YAAY;AACjC,QAAM,QAAQ,QAAQ;AACtB,QAAM,UAAU,eAAe,IAAI,KAAK,MAAO,YAAY,eAAgB,GAAG,IAAI;AAElF,QAAM,QAAkB,CAAC;AAGzB,QAAM,KAAK,oDAAY;AACvB,QAAM,KAAK,uPAAoD;AAC/D,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,6BAAS;AACpB,QAAM,KAAK,cAAc,SAAS,cAAc,MAAM,gCAAY,QAAQ,EAAE;AAC5E,QAAM,KAAK,EAAE;AAGb,QAAM,KAAK,6BAAS;AACpB,QAAM,KAAK,yBAAU,KAAK,oBAAU,SAAS,0BAAW,SAAS,GAAG,eAAe,IAAI,0BAAW,YAAY,KAAK,EAAE,EAAE;AACvH,QAAM,KAAK,yBAAU,OAAO,IAAI,eAAe,IAAI,6EAAiB,EAAE,EAAE;AACxE,QAAM,KAAK,EAAE;AAGb,aAAW,YAAY,gBAAgB;AACrC,UAAM,eAAe,iBAAiB,QAAQ;AAC9C,UAAM,kBAAkB,QAAQ,OAAO,CAAC,MAAM,EAAE,MAAM,aAAa,QAAQ;AAC3E,QAAI,gBAAgB,WAAW,EAAG;AAElC,UAAM,KAAK,MAAM,YAAY,EAAE;AAC/B,UAAM,KAAK,EAAE;AAGb,UAAM,OAAO,oBAAI,IAA2B;AAC5C,eAAW,KAAK,iBAAiB;AAC/B,YAAM,WAAW,KAAK,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC;AAC1C,eAAS,KAAK,CAAC;AACf,WAAK,IAAI,EAAE,MAAM,IAAI,QAAQ;AAAA,IAC/B;AAEA,eAAW,CAAC,SAAS,YAAY,KAAK,MAAM;AAC1C,YAAM,KAAK,OAAO,OAAO,IAAI,aAAa,CAAC,EAAE,MAAM,IAAI,EAAE;AACzD,iBAAW,KAAK,cAAc;AAC5B,cAAM,OAAO,EAAE,WAAW,SAAS,WAAW,EAAE,WAAW,SAAS,WAAW;AAC/E,cAAM,QAAQ,EAAE,WAAW,YAAY,wBAAS;AAChD,cAAM,KAAK,MAAM,IAAI,KAAK,EAAE,MAAM,IAAI,GAAG,KAAK,EAAE;AAChD,YAAI,EAAE,WAAW,UAAU,EAAE,gBAAgB,SAAS,GAAG;AACvD,qBAAW,KAAK,EAAE,gBAAgB,MAAM,GAAG,CAAC,GAAG;AAC7C,kBAAM,KAAK,OAAO,EAAE,QAAQ,KAAK,EAAE,KAAK,EAAE;AAAA,UAC5C;AACA,cAAI,EAAE,gBAAgB,SAAS,GAAG;AAChC,kBAAM,KAAK,8BAAe,EAAE,gBAAgB,SAAS,CAAC,SAAI;AAAA,UAC5D;AAAA,QACF;AAAA,MACF;AACA,YAAM,KAAK,EAAE;AAAA,IACf;AAAA,EACF;AAGA,QAAM,gBAAgB,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAC/D,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,KAAK,uEAAgB;AAC3B,UAAM,KAAK,EAAE;AAGb,UAAM,oBAAoB,oBAAI,IAAqB;AACnD,eAAW,KAAK,eAAe;AAC7B,iBAAW,KAAK,EAAE,iBAAiB;AACjC,cAAM,MAAM,GAAG,EAAE,UAAU,IAAI,EAAE,KAAK;AACtC,YAAI,CAAC,kBAAkB,IAAI,GAAG,GAAG;AAC/B,4BAAkB,IAAI,KAAK,CAAC;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,CAAC,GAAG,kBAAkB,OAAO,CAAC,EAAE;AAAA,MAC7C,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE;AAAA,IAC5B;AAEA,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,IAAI,OAAO,CAAC;AAClB,YAAM,WAAW,EAAE,aAAa,IAAM,OAAO,EAAE,aAAa,IAAM,OAAO,EAAE,aAAa,IAAM,OAAO;AACrG,YAAM,cAAc,EAAE,iBAAiB,CAAC,KAAK;AAC7C,YAAM,KAAK,GAAG,IAAI,CAAC,MAAM,QAAQ,KAAK,EAAE,KAAK,WAAM,WAAW,EAAE;AAAA,IAClE;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;;;ACjSA,SAAS,IAAI,GAAmB;AAC9B,SAAO,EACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,OAAO;AAC1B;AAEA,SAAS,UAAU,SAA4C;AAC7D,QAAM,MACJ,MACA,QAAQ,WAAW,KACnB,QAAQ,OAAO,IACf,QAAQ,SAAS,IACjB,QAAQ,MAAM;AAChB,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAM,GAAG,CAAC,CAAC;AACnD;AAEA,SAASC,gBAAe,OAAe,KAAqB;AAC1D,QAAM,KAAK,IAAI,KAAK,GAAG,EAAE,QAAQ,IAAI,IAAI,KAAK,KAAK,EAAE,QAAQ;AAC7D,MAAI,KAAK,IAAM,QAAO,GAAG,EAAE;AAC3B,QAAM,OAAO,KAAK,MAAM,KAAK,GAAI;AACjC,MAAI,OAAO,GAAI,QAAO,GAAG,IAAI;AAC7B,SAAO,GAAG,KAAK,MAAM,OAAO,EAAE,CAAC,KAAK,OAAO,EAAE;AAC/C;AAEA,IAAM,YAAsC;AAAA,EAC1C,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AACP;AAEA,IAAMC,kBAA6B,CAAC,YAAY,QAAQ,UAAU,KAAK;AAEvE,SAAS,WAAW,OAAuB;AACzC,MAAI,SAAS,GAAI,QAAO;AACxB,MAAI,SAAS,GAAI,QAAO;AACxB,SAAO;AACT;AAMA,SAAS,YAAoB;AAC3B,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoKT;AAMA,SAAS,WAAW,SAA4C;AAC9D,QAAM,QAAQ,QAAQ;AACtB,QAAM,IAAI;AACV,QAAM,OAAO,IAAI,KAAK,KAAK;AAE3B,MAAI,UAAU,GAAG;AACf,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AAEA,QAAM,WAAoD;AAAA,IACxD,EAAE,OAAO,QAAQ,UAAU,OAAO,UAAU,SAAS;AAAA,IACrD,EAAE,OAAO,QAAQ,MAAM,OAAO,UAAU,KAAK;AAAA,IAC7C,EAAE,OAAO,QAAQ,QAAQ,OAAO,UAAU,OAAO;AAAA,IACjD,EAAE,OAAO,QAAQ,KAAK,OAAO,UAAU,IAAI;AAAA,EAC7C,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC;AAE3B,MAAI,SAAS;AACb,QAAM,UAAU,SAAS,IAAI,CAAC,MAAM;AAClC,UAAM,MAAO,EAAE,QAAQ,QAAS;AAChC,UAAM,KAAK,wDAAwD,EAAE,KAAK,yCAAyC,IAAI,QAAQ,CAAC,CAAC,KAAK,OAAO,KAAK,QAAQ,CAAC,CAAC,yBAAyB,CAAC,QAAQ,QAAQ,CAAC,CAAC;AACxM,cAAU;AACV,WAAO;AAAA,EACT,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,GAAG,QAAQ,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AAAA,IAC9B,gGAAgG,KAAK;AAAA,IACrG;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,SAAS,SAA4C;AAC5D,QAAM,eAAe,QAClB,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACjC,KAAK,CAAC,GAAG,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAChD,MAAM,GAAG,EAAE;AAEd,MAAI,aAAa,WAAW,GAAG;AAC7B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AAEA,QAAM,WAAW,aAAa,CAAC,EAAE;AACjC,QAAM,OAAO;AACb,QAAM,MAAM;AACZ,QAAM,SAAS;AACf,QAAM,UAAU;AAChB,QAAM,SAAS,aAAa,UAAU,OAAO;AAE7C,QAAM,OAAO,aAAa,IAAI,CAAC,GAAG,MAAM;AACtC,UAAM,IAAI,KAAK,OAAO;AACtB,UAAM,IAAI,KAAK,IAAI,GAAI,EAAE,gBAAgB,WAAY,OAAO;AAC5D,UAAM,WAAW,EAAE,SAAS,OAAiB,CAAC,OAAO,MAAM;AACzD,YAAM,MAAMA,gBAAe,QAAQ,EAAE,QAAQ;AAC7C,aAAO,MAAMA,gBAAe,QAAQ,KAAK,IAAI,EAAE,WAAW;AAAA,IAC5D,GAAG,KAAK;AACR,UAAM,QAAQ,UAAU,QAAQ;AAChC,WAAO;AAAA,MACL,YAAY,SAAS,CAAC,QAAQ,IAAI,OAAO,IAAI,CAAC,qDAAqD,IAAI,EAAE,MAAM,CAAC;AAAA,MAChH,YAAY,MAAM,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,aAAa,IAAI,kBAAkB,KAAK;AAAA,MAC3F,YAAY,SAAS,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,CAAC,mCAAmC,EAAE,aAAa;AAAA,IACtG,EAAE,KAAK,IAAI;AAAA,EACb,CAAC;AAED,SAAO;AAAA,IACL,yBAAyB,MAAM;AAAA,IAC/B,GAAG;AAAA,IACH;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,mBAAmB,SAA0C;AACpE,QAAM,UAAU,QAAQ,MAAM,GAAG;AACjC,MAAI,QAAQ,SAAS,EAAG,QAAO;AAE/B,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,MAAM,EAAE,KAAK,IAAI,OAAO,IAAI,QAAQ,IAAI,MAAM,GAAG;AACvD,QAAM,QAAQ,IAAI,IAAI,OAAO,IAAI;AACjC,QAAM,QAAQ,IAAI,IAAI,MAAM,IAAI;AAEhC,QAAM,SAAS,KAAK;AAAA,IAClB;AAAA,IACA,GAAG,QAAQ,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC;AAAA,EACjE;AAEA,QAAM,OAAO,CAAC,MACZ,IAAI,OAAQ,IAAI,KAAK,IAAI,GAAG,QAAQ,SAAS,CAAC,IAAK;AACrD,QAAM,OAAO,CAAC,MAAc,IAAI,MAAM,QAAS,IAAI,SAAU;AAE7D,QAAM,QAID;AAAA,IACH,EAAE,KAAK,YAAY,OAAO,WAAW,OAAO,WAAW;AAAA,IACvD,EAAE,KAAK,QAAQ,OAAO,WAAW,OAAO,OAAO;AAAA,IAC/C,EAAE,KAAK,UAAU,OAAO,WAAW,OAAO,SAAS;AAAA,IACnD,EAAE,KAAK,OAAO,OAAO,WAAW,OAAO,MAAM;AAAA,EAC/C;AAEA,QAAM,YAAY,MACf,IAAI,CAAC,SAAS;AACb,UAAM,MAAM,QACT;AAAA,MACC,CAAC,GAAG,MACF,GAAG,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,KAAK,EAAE,KAAK,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,IACzD,EACC,KAAK,GAAG;AACX,WAAO,qBAAqB,GAAG,yBAAyB,KAAK,KAAK;AAAA,EACpE,CAAC,EACA,KAAK,MAAM;AAEd,QAAM,UAAU,QACb,IAAI,CAAC,GAAG,MAAM;AACb,QAAI,IAAI,MAAM,KAAK,MAAM,QAAQ,SAAS,EAAG,QAAO;AACpD,WAAO,YAAY,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI,CAAC,wDAAwD,EAAE,KAAK,MAAM,CAAC,CAAC;AAAA,EAC3H,CAAC,EACA,OAAO,OAAO,EACd,KAAK,MAAM;AAEd,QAAM,SAAS;AACf,QAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,SAAS,EAAE,GAAG,CAAC,GAAG,MAAM;AAC3D,UAAM,MAAM,KAAK,MAAO,SAAS,SAAU,CAAC;AAC5C,WAAO;AAAA,MACL,YAAY,IAAI,OAAO,CAAC,QAAQ,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC,gFAAgF,GAAG;AAAA,MACvI,aAAa,IAAI,IAAI,SAAS,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC,SAAS,IAAI,IAAI,KAAK,SAAS,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC;AAAA,IACvG,EAAE,KAAK,MAAM;AAAA,EACf,CAAC,EAAE,KAAK,MAAM;AAEd,QAAM,SAAS,MACZ,IAAI,CAAC,MAAM,MAAM;AAChB,UAAM,KAAK,IAAI,OAAO,IAAI;AAC1B,WAAO,YAAY,EAAE,8CAA8C,KAAK,KAAK,eAAe,KAAK,EAAE,0CAA0C,KAAK,KAAK;AAAA,EACzJ,CAAC,EACA,KAAK,MAAM;AAEd,SAAO;AAAA,IACL,qBAAqB,CAAC,IAAI,CAAC;AAAA,IAC3B,KAAK,MAAM;AAAA,IACX,KAAK,OAAO;AAAA,IACZ,KAAK,SAAS;AAAA,IACd,KAAK,OAAO;AAAA,IACZ;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,gBAAgB,SAA0C;AACjE,QAAM,UAAU,QAAQ,MAAM,GAAG;AACjC,MAAI,QAAQ,SAAS,EAAG,QAAO;AAE/B,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,MAAM,EAAE,KAAK,IAAI,OAAO,IAAI,QAAQ,IAAI,MAAM,GAAG;AACvD,QAAM,QAAQ,IAAI,IAAI,OAAO,IAAI;AACjC,QAAM,QAAQ,IAAI,IAAI,MAAM,IAAI;AAEhC,QAAM,OAAO,CAAC,MACZ,IAAI,OAAQ,IAAI,KAAK,IAAI,GAAG,QAAQ,SAAS,CAAC,IAAK;AACrD,QAAM,OAAO,CAAC,MAAc,IAAI,MAAM,QAAS,IAAI,MAAO;AAE1D,QAAM,MAAM,QACT,IAAI,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,EAAE,EACjE,KAAK,GAAG;AAEX,QAAM,QAAQ;AAAA,IACZ,YAAY,IAAI,IAAI,QAAQ,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC,YAAY,KAAK,cAAc,KAAK,EAAE,IAAI,KAAK,GAAG,GAAG,QAAQ,CAAC,CAAC;AAAA,IAC/G,YAAY,IAAI,IAAI,QAAQ,KAAK,EAAE,EAAE,QAAQ,CAAC,CAAC,YAAY,KAAK,cAAc,KAAK,EAAE,IAAI,KAAK,EAAE,GAAG,QAAQ,CAAC,CAAC;AAAA,IAC7G,YAAY,IAAI,IAAI,QAAQ,KAAK,EAAE,EAAE,QAAQ,CAAC,CAAC,YAAY,KAAK,cAAc,KAAK,CAAC,IAAI,KAAK,EAAE,GAAG,QAAQ,CAAC,CAAC;AAAA,EAC9G,EAAE,KAAK,MAAM;AAEb,QAAM,UAAU,QACb,IAAI,CAAC,GAAG,MAAM;AACb,QAAI,IAAI,MAAM,KAAK,MAAM,QAAQ,SAAS,EAAG,QAAO;AACpD,WAAO,YAAY,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,IAAI,CAAC,wDAAwD,EAAE,KAAK,MAAM,CAAC,CAAC;AAAA,EAC3H,CAAC,EACA,OAAO,OAAO,EACd,KAAK,MAAM;AAEd,QAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,IAAI,GAAG;AACjC,QAAM,UAAU,MACb;AAAA,IACC,CAAC,QACC,YAAY,IAAI,OAAO,CAAC,QAAQ,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC,gFAAgF,GAAG;AAAA,cAAwB,IAAI,IAAI,SAAS,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC,SAAS,IAAI,IAAI,KAAK,SAAS,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC;AAAA,EAC3P,EACC,KAAK,MAAM;AAEd,SAAO;AAAA,IACL,qBAAqB,CAAC,IAAI,CAAC;AAAA,IAC3B,KAAK,KAAK;AAAA,IACV,KAAK,OAAO;AAAA,IACZ,uBAAuB,GAAG;AAAA,IAC1B,KAAK,OAAO;AAAA,IACZ;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAMO,SAAS,mBACd,aACA,SACQ;AACR,QAAM,EAAE,SAAS,SAAS,WAAW,QAAQ,WAAW,QAAQ,IAC9D;AACF,QAAM,OAAO,UAAU,MAAM,GAAG,EAAE,CAAC;AACnC,QAAM,WAAWD,gBAAe,WAAW,OAAO;AAClD,QAAM,QAAQ,UAAU,OAAO;AAE/B,QAAM,cAAyB,QAAQ;AAAA,IAAQ,CAAC,MAC9C,EAAE,SAAS,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE;AAAA,EAChE;AAGA,MAAI,WAAW;AACf,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,OAAO,CAAC,GAAG,WAAW,EACzB,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS,EACxC,MAAM,GAAG,CAAC;AACb,UAAM,QAAQ,KACX;AAAA,MACC,CAAC,GAAG,MAAM;AAAA,kCACgB,IAAI,EAAE,SAAS,YAAY,CAAC,CAAC;AAAA,kCAC7B,IAAI,CAAC;AAAA;AAAA,qCAEF,IAAI,EAAE,SAAS,YAAY,CAAC,CAAC,KAAK,IAAI,EAAE,QAAQ,CAAC;AAAA,oCAClD,IAAI,EAAE,KAAK,CAAC;AAAA,gEACgB,IAAI,EAAE,UAAU,CAAC;AAAA,8DACnB,IAAI,EAAE,MAAM,CAAC;AAAA,kEACT,EAAE,SAAS;AAAA;AAAA,yCAEpC,EAAE,iBAAiB,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,IAG/F,EACC,KAAK,IAAI;AACZ,eAAW;AAAA;AAAA,gBAEC,KAAK,MAAM;AAAA,QACnB,KAAK;AAAA;AAAA,EAEX;AAGA,MAAI;AACJ,MAAI,QAAQ,kBAAkB,GAAG;AAC/B,mBAAe;AAAA,EACjB,OAAO;AACL,UAAM,iBAAiB;AAEvB,UAAM,aAAa,CAAC,MAAuB;AACzC,YAAM,MAAM,EAAE,SAAS,YAAY;AACnC,aAAO,gCAAgC,IAAI,GAAG,CAAC;AAAA,mCAClB,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE,QAAQ,CAAC;AAAA,2CACpB,IAAI,EAAE,KAAK,CAAC;AAAA,yCACd,IAAI,EAAE,eAAe,EAAE,UAAU,CAAC;AAAA;AAAA,eAE5D,IAAI,EAAE,WAAW,CAAC;AAAA;AAAA,gBAEjB,EAAE,iBAAiB,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,IAGxE;AAEA,UAAM,cAAc,CAAC,aAAgC;AACnD,UAAI,SAAS,UAAU,gBAAgB;AACrC,eAAO,SAAS,IAAI,UAAU,EAAE,KAAK,IAAI;AAAA,MAC3C;AACA,YAAM,QAAQ,SAAS,MAAM,GAAG,cAAc,EAAE,IAAI,UAAU,EAAE,KAAK,IAAI;AACzE,YAAM,OAAO,SAAS,MAAM,cAAc,EAAE,IAAI,UAAU,EAAE,KAAK,IAAI;AACrE,aAAO,GAAG,KAAK;AAAA,mCAAsC,SAAS,SAAS,cAAc;AAAA,EAA2B,IAAI;AAAA;AAAA,IACtH;AAEA,UAAM,YAAoC;AAAA,MACxC,UAAU;AAAA,MACV,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,KAAK;AAAA,IACP;AAGA,UAAM,YAAY,oBAAI,IAAuB;AAC7C,eAAW,KAAK,aAAa;AAC3B,YAAM,MAAM,EAAE,UAAU;AACxB,UAAI,CAAC,UAAU,IAAI,GAAG,EAAG,WAAU,IAAI,KAAK,CAAC,CAAC;AAC9C,gBAAU,IAAI,GAAG,EAAG,KAAK,CAAC;AAAA,IAC5B;AAGA,UAAM,gBAAgB,CAAC,GAAG,UAAU,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AAC5D,YAAM,eAAe,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,cAAc,EAAE,aAAa,MAAM;AACxF,YAAM,eAAe,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,aAAa,cAAc,EAAE,aAAa,MAAM;AACxF,UAAI,iBAAiB,aAAc,QAAO,eAAe,KAAK;AAC9D,aAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;AAAA,IAC5B,CAAC;AAED,mBAAe,cAAc,IAAI,CAAC,CAAC,SAAS,WAAW,MAAM;AAC3D,YAAM,YAAoC,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,EAAE;AACpF,iBAAW,KAAK,YAAa,WAAU,EAAE,QAAQ;AAEjD,YAAM,SAASC,gBACZ,OAAO,CAAC,QAAQ,UAAU,GAAG,IAAI,CAAC,EAClC,IAAI,CAAC,QAAQ,4BAA4B,IAAI,YAAY,CAAC,KAAK,UAAU,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,YAAY,CAAC,SAAS,EACpI,KAAK,GAAG;AAEX,YAAM,YAAYA,gBAAe,IAAI,CAAC,QAAQ;AAC5C,cAAM,WAAW,YAAY,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG;AAC7D,YAAI,SAAS,WAAW,EAAG,QAAO;AAClC,iBAAS,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAEjD,cAAM,QAAQ,UAAU,GAAG,KAAK;AAChC,cAAM,QAAQ,IAAI,OAAO,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,YAAY;AAEvD,eAAO;AAAA,yBACU,KAAK,IAAI,KAAK,KAAK,SAAS,MAAM;AAAA,YAC/C,YAAY,QAAQ,CAAC;AAAA;AAAA,MAE3B,CAAC,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AAE5B,aAAO;AAAA;AAAA,0BAEa,IAAI,OAAO,CAAC,KAAK,YAAY,MAAM;AAAA,wCACrB,MAAM;AAAA;AAAA;AAAA,YAGlC,SAAS;AAAA;AAAA;AAAA,IAGjB,CAAC,EAAE,KAAK,IAAI;AAAA,EACd;AAGA,MAAI,YAAY;AAChB,MAAI,WAAW,QAAQ,UAAU,GAAG;AAClC,gBAAY;AAAA;AAAA;AAAA;AAAA;AAAA,UAKN,mBAAmB,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA,UAI3B,gBAAgB,OAAO,CAAC;AAAA;AAAA;AAAA,EAGhC;AAGA,QAAM,YAAY,QACf;AAAA,IACC,CAAC,MACC,WAAW,IAAI,EAAE,MAAM,CAAC,YAAY,EAAE,gBAAgB,YAAY,EAAE,aAAa,YAAY,EAAE,WAAW,YAAY,aAAa,UAAU;AAAA,EACjJ,EACC,KAAK,IAAI;AAGZ,MAAI,WAAW;AACf,MAAI,QAAQ,gBAAgB,GAAG;AAC7B,UAAM,SAAS,oBAAI,IAAiE;AACpF,eAAW,KAAK,aAAa;AAC3B,YAAM,MAAM,EAAE,iBAAiB,CAAC,KAAK;AACrC,YAAM,WAAW,OAAO,IAAI,GAAG;AAC/B,UAAI,UAAU;AACZ,iBAAS;AACT,YAAIA,gBAAe,QAAQ,EAAE,QAAQ,IAAIA,gBAAe,QAAQ,SAAS,QAAQ,GAAG;AAClF,mBAAS,WAAW,EAAE;AAAA,QACxB;AAAA,MACF,OAAO;AACL,eAAO,IAAI,KAAK,EAAE,MAAM,KAAK,UAAU,EAAE,UAAU,OAAO,EAAE,CAAC;AAAA,MAC/D;AAAA,IACF;AACA,UAAM,aAAa,CAAC,GAAG,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AACrD,YAAM,UAAUA,gBAAe,QAAQ,EAAE,QAAQ,IAAIA,gBAAe,QAAQ,EAAE,QAAQ;AACtF,UAAI,YAAY,EAAG,QAAO;AAC1B,aAAO,EAAE,QAAQ,EAAE;AAAA,IACrB,CAAC;AAED,UAAM,YAAY,CAAC,MAAmE;AACpF,YAAM,MAAM,EAAE,SAAS,YAAY;AACnC,YAAM,aAAa,EAAE,QAAQ,IAAI,aAAa,EAAE,KAAK,MAAM;AAC3D,aAAO,gCAAgC,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE,QAAQ,CAAC,WAAW,IAAI,EAAE,IAAI,CAAC,GAAG,UAAU;AAAA,IACxG;AAEA,UAAM,QAAQ;AACd,UAAM,WAAW,WAAW,MAAM,GAAG,KAAK,EAAE,IAAI,SAAS,EAAE,KAAK,IAAI;AACpE,UAAM,YAAY,WAAW,MAAM,KAAK;AACxC,UAAM,WAAW,UAAU,SAAS,IAChC;AAAA,yBAA4B,UAAU,MAAM;AAAA,EAA4B,UAAU,IAAI,SAAS,EAAE,KAAK,IAAI,CAAC;AAAA,cAC3G;AAEJ,eAAW;AAAA;AAAA,iFAEkE,WAAW,MAAM;AAAA;AAAA,gBAElF,QAAQ,GAAG,QAAQ;AAAA;AAAA;AAAA,EAGjC;AAEA,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,0CAKiC,IAAI,IAAI,CAAC;AAAA,SAC1C,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAOW,IAAI,SAAS,CAAC,cAAc,IAAI,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,gBAAgB,IAAI,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,4CAKtE,WAAW,KAAK,CAAC,KAAK,KAAK;AAAA;AAAA;AAAA;AAAA,mEAIJ,QAAQ,QAAQ;AAAA,+DACpB,QAAQ,IAAI;AAAA,iEACV,QAAQ,MAAM;AAAA,8DACjB,QAAQ,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qCAOpC,WAAW,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA,MAIlD,SAAS,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA,EAIrB,SAAS;AAAA;AAAA,EAET,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAMG,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMlB,YAAY;AAAA;AAAA;AAAA,EAGd,QAAQ;AAAA;AAAA;AAAA,6CAGmC,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOpD;AAMO,SAAS,wBACd,aACA,SACQ;AACR,QAAM,EAAE,WAAW,QAAQ,UAAU,IAAI;AACzC,QAAM,OAAO,UAAU,MAAM,GAAG,EAAE,CAAC;AACnC,QAAM,WAAW,UAAU,QAAQ,KAAK,GAAG,EAAE,QAAQ,WAAW,MAAM;AAEtE,QAAM,cAAyB,YAAY,QAAQ;AAAA,IAAQ,CAAC,MAC1D,EAAE,SAAS,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE;AAAA,EAChE;AAEA,QAAM,cAAc,YAAY,QAAQ,IAAI,CAAC,OAAO;AAAA,IAClD,QAAQ,EAAE;AAAA,IACV,QAAQ,EAAE;AAAA,EACZ,EAAE;AACF,QAAM,UAAU,YAAY;AAAA,IAAI,CAAC,UAC/B,cAAc,OAAO,aAAa,WAAW;AAAA,EAC/C;AAEA,QAAM,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAC7D,QAAM,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAC7D,QAAM,eAAe,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AACnE,QAAM,eAAe,YAAY;AACjC,QAAM,UACJ,eAAe,IAAI,KAAK,MAAO,YAAY,eAAgB,GAAG,IAAI;AAGpE,MAAI,YAAY;AAChB,MAAI,WAAW,QAAQ,UAAU,GAAG;AAClC,gBAAY;AAAA;AAAA;AAAA;AAAA;AAAA,UAKN,mBAAmB,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA,UAI3B,gBAAgB,OAAO,CAAC;AAAA;AAAA;AAAA,EAGhC;AAGA,QAAM,mBAAmB,eAAe,IAAI,CAAC,aAAa;AACxD,UAAM,eAAe,iBAAiB,QAAQ;AAC9C,UAAM,kBAAkB,QAAQ;AAAA,MAC9B,CAAC,MAAM,EAAE,MAAM,aAAa;AAAA,IAC9B;AACA,QAAI,gBAAgB,WAAW,EAAG,QAAO;AAEzC,UAAM,UAAU,gBAAgB,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AACnE,UAAM,UAAU,gBAAgB,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AACnE,UAAM,aAAa,gBAAgB;AAAA,MACjC,CAAC,MAAM,EAAE,WAAW;AAAA,IACtB,EAAE;AACF,UAAM,OAAO,oBAAI,IAAoC;AACrD,eAAW,KAAK,iBAAiB;AAC/B,YAAM,WAAW,KAAK,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC;AAC1C,eAAS,KAAK,CAAC;AACf,WAAK,IAAI,EAAE,MAAM,IAAI,QAAQ;AAAA,IAC/B;AAEA,UAAM,SAAS,CAAC,GAAG,KAAK,QAAQ,CAAC,EAC9B,IAAI,CAAC,CAAC,SAAS,YAAY,MAAM;AAChC,YAAM,UAAU,aAAa,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAChE,YAAM,UAAU,aAAa,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAChE,YAAM,aAAa,aAAa,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AAEtE,YAAM,QAAQ,aACX,IAAI,CAAC,MAAM;AACV,cAAM,OACJ,EAAE,WAAW,SACT,aACA,EAAE,WAAW,SACX,aACA;AACR,cAAM,MAAM,SAAS,EAAE,MAAM;AAC7B,cAAM,QAAQ,EAAE,WAAW,YAAY,0BAAW;AAClD,YAAI,eAAe;AACnB,YAAI,EAAE,WAAW,UAAU,EAAE,gBAAgB,SAAS,GAAG;AACvD,gBAAMC,SAAQ,EAAE,gBACb,MAAM,GAAG,CAAC,EACV;AAAA,YACC,CAAC,MACC,OAAO,IAAI,EAAE,QAAQ,CAAC,KAAK,IAAI,EAAE,KAAK,CAAC;AAAA,UAC3C;AACF,cAAI,EAAE,gBAAgB,SAAS,GAAG;AAChC,YAAAA,OAAM;AAAA,cACJ,8BAAe,EAAE,gBAAgB,SAAS,CAAC;AAAA,YAC7C;AAAA,UACF;AACA,yBAAe,8BAA8BA,OAAM,KAAK,EAAE,CAAC;AAAA,QAC7D;AACA,eAAO,0BAA0B,GAAG,8BAA8B,IAAI,mCAAmC,IAAI,EAAE,MAAM,IAAI,CAAC,GAAG,KAAK,gBAAgB,YAAY;AAAA,MAChK,CAAC,EACA,KAAK,IAAI;AAEZ,YAAM,eAAe;AAAA,QACnB,UAAU,IAAI,6CAA6C,OAAO,YAAY;AAAA,QAC9E,UAAU,IAAI,6CAA6C,OAAO,YAAY;AAAA,QAC9E,aAAa,IAAI,yCAAyC,UAAU,YAAY;AAAA,MAClF,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAE1B,aAAO,qDAAqD,IAAI,OAAO,CAAC,IAAI,IAAI,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC,iCAAiC,YAAY;AAAA,EAA2B,KAAK;AAAA;AAAA,IAC1L,CAAC,EACA,KAAK,IAAI;AAEZ,UAAM,YAAY;AAAA,MAChB,UAAU,IACN,6CAA6C,OAAO,YACpD;AAAA,MACJ,UAAU,IACN,6CAA6C,OAAO,YACpD;AAAA,MACJ,aAAa,IACT,yCAAyC,UAAU,YACnD;AAAA,IACN,EACG,OAAO,OAAO,EACd,KAAK,EAAE;AAEV,WAAO;AAAA;AAAA,mCAEwB,IAAI,YAAY,CAAC;AAAA,mCACjB,SAAS;AAAA;AAAA,+BAEb,MAAM;AAAA;AAAA,EAEnC,CAAC,EACE,OAAO,OAAO,EACd,KAAK,IAAI;AAGZ,QAAM,gBAAgB,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAC/D,MAAI,kBAAkB;AACtB,MAAI,cAAc,SAAS,GAAG;AAC5B,UAAM,aAAa,oBAAI,IAAiE;AACxF,eAAW,KAAK,eAAe;AAC7B,iBAAW,KAAK,EAAE,iBAAiB;AACjC,cAAM,MAAM,EAAE,iBAAiB,CAAC,KAAK;AACrC,cAAM,WAAW,WAAW,IAAI,GAAG;AACnC,YAAI,UAAU;AACZ,mBAAS;AACT,cAAID,gBAAe,QAAQ,EAAE,QAAQ,IAAIA,gBAAe,QAAQ,SAAS,QAAQ,GAAG;AAClF,qBAAS,WAAW,EAAE;AAAA,UACxB;AAAA,QACF,OAAO;AACL,qBAAW,IAAI,KAAK,EAAE,MAAM,KAAK,UAAU,EAAE,UAAU,OAAO,EAAE,CAAC;AAAA,QACnE;AAAA,MACF;AAAA,IACF;AACA,UAAM,iBAAiB,CAAC,GAAG,WAAW,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AAC7D,YAAM,UAAUA,gBAAe,QAAQ,EAAE,QAAQ,IAAIA,gBAAe,QAAQ,EAAE,QAAQ;AACtF,UAAI,YAAY,EAAG,QAAO;AAC1B,aAAO,EAAE,QAAQ,EAAE;AAAA,IACrB,CAAC;AAED,UAAM,gBAAgB,CAAC,MAAmE;AACxF,YAAM,MAAM,EAAE,SAAS,YAAY;AACnC,YAAM,aAAa,EAAE,QAAQ,IAAI,aAAa,EAAE,KAAK,MAAM;AAC3D,aAAO,gCAAgC,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE,QAAQ,CAAC,WAAW,IAAI,EAAE,IAAI,CAAC,GAAG,UAAU;AAAA,IACxG;AAEA,UAAM,aAAa;AACnB,UAAM,eAAe,eAAe,MAAM,GAAG,UAAU,EAAE,IAAI,aAAa,EAAE,KAAK,IAAI;AACrF,UAAM,gBAAgB,eAAe,MAAM,UAAU;AACrD,UAAM,eAAe,cAAc,SAAS,IACxC;AAAA,6CAA4B,cAAc,MAAM;AAAA,EAAyB,cAAc,IAAI,aAAa,EAAE,KAAK,IAAI,CAAC;AAAA,cACpH;AAEJ,sBAAkB;AAAA;AAAA,oGAEgD,eAAe,MAAM;AAAA;AAAA,gBAE3E,YAAY,GAAG,YAAY;AAAA;AAAA;AAAA,EAGzC;AAEA,QAAM,gBACJ,WAAW,KAAK,YAAY,WAAW,KAAK,YAAY;AAC1D,QAAM,cACJ,eAAe,IACX,4IACA;AAEN,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,kEAKiB,IAAI,IAAI,CAAC;AAAA,SAC1B,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAQM,IAAI,SAAS,CAAC,oBAAU,IAAI,MAAM,CAAC,gCAAY,IAAI,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,4CAK1C,aAAa,KAAK,OAAO;AAAA;AAAA;AAAA;AAAA,0GAIqC,SAAS;AAAA,0GACT,SAAS;AAAA,MAC7G,eAAe,IAAI,uGAAuG,YAAY,iEAAkD,EAAE;AAAA;AAAA;AAAA,EAG9L,WAAW;AAAA;AAAA,EAEX,SAAS;AAAA;AAAA,EAET,gBAAgB;AAAA;AAAA,EAEhB,eAAe;AAAA;AAAA;AAAA,uCAGiB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOzC;;;ACl7BA,SAAS,eAAe,cAAc,WAAW,kBAAkB;AACnE,SAAS,YAAY;AACrB,SAAS,eAAe;AAQjB,SAAS,eAAe,SAA4C;AACzE,QAAM,MACJ,MACA,QAAQ,WAAW,KACnB,QAAQ,OAAO,IACf,QAAQ,SAAS,IACjB,QAAQ,MAAM;AAChB,SAAO,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC;AACvC;AAEO,SAAS,YACd,aACA,WACQ;AACR,QAAM,UAAU,aAAa,KAAK,QAAQ,GAAG,eAAe;AAC5D,QAAM,QAAQ,YAAY,UAAU,MAAM,GAAG,EAAE;AAG/C,QAAM,UAAU,KAAK,SAAS,SAAS,KAAK;AAC5C,QAAM,eAAe,KAAK,SAAS,WAAW;AAC9C,YAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AACtC,YAAU,cAAc,EAAE,WAAW,KAAK,CAAC;AAG3C,gBAAc,KAAK,SAAS,WAAW,GAAG,KAAK,UAAU,aAAa,MAAM,CAAC,CAAC;AAG9E,QAAM,WAAW,KAAK,cAAc,WAAW;AAC/C,MAAI,WAAiC;AACrC,MAAI,WAAW,QAAQ,GAAG;AACxB,QAAI;AACF,iBAAW,KAAK,MAAM,aAAa,UAAU,OAAO,CAAC;AAAA,IACvD,QAAQ;AAEN,iBAAW;AAAA,IACb;AAAA,EACF;AAGA,QAAM,eAAsC;AAAA,IAC1C,MAAM;AAAA,IACN,OAAO,eAAe,YAAY,OAAO;AAAA,IACzC,UAAU,YAAY,QAAQ;AAAA,IAC9B,MAAM,YAAY,QAAQ;AAAA,IAC1B,QAAQ,YAAY,QAAQ;AAAA,IAC5B,KAAK,YAAY,QAAQ;AAAA,IACzB,eAAe,YAAY,QAAQ;AAAA,EACrC;AAGA,MAAI,UAAU,UAAU,WAAW,CAAC;AACpC,QAAM,MAAM,QAAQ,UAAU,CAAC,MAAM,EAAE,SAAS,KAAK;AACrD,MAAI,OAAO,GAAG;AACZ,YAAQ,GAAG,IAAI;AAAA,EACjB,OAAO;AACL,YAAQ,KAAK,YAAY;AAAA,EAC3B;AAEA,YAAU,QAAQ,MAAM,GAAG;AAG3B,QAAM,gBAA+B;AAAA,IACnC,UAAU;AAAA,MACR,WAAW,YAAY;AAAA,MACvB,SAAS,YAAY;AAAA,MACrB,QAAQ,YAAY;AAAA,MACpB,WAAW,YAAY;AAAA,MACvB,SAAS,YAAY;AAAA,MACrB,SAAS,YAAY,QAAQ,IAAI,CAAC,OAAO;AAAA,QACvC,QAAQ,EAAE;AAAA,QACV,eAAe,EAAE;AAAA,QACjB,QAAQ,EAAE;AAAA,MACZ,EAAE;AAAA,MACF,UAAU,YAAY,QAAQ;AAAA,QAAQ,CAAC,MACrC,EAAE,SAAS,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,EAAE,OAAO,EAAE;AAAA,MACpD;AAAA,IACF;AAAA,IACA;AAAA,IACA,MAAM;AAAA,MACJ,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC,SAAS;AAAA,MACT,mBAAmB;AAAA,IACrB;AAAA,EACF;AAEA,gBAAc,UAAU,KAAK,UAAU,eAAe,MAAM,CAAC,CAAC;AAC9D,SAAO;AACT;;;ACtFA,IAAME,kBAAyC;AAAA,EAC7C,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,UAAU;AACZ;AAEO,SAAS,oBACd,YACA,UACA,QACiC;AACjC,MAAI,SAAS;AAGb,MAAI,OAAO,aAAa;AACtB,UAAM,WAAWA,gBAAe,OAAO,YAAY,YAAY,CAAC,KAAK;AACrE,aAAS,OAAO,OAAO,CAAC,OAAOA,gBAAe,EAAE,QAAQ,KAAK,MAAM,QAAQ;AAAA,EAC7E;AAGA,MAAI,eAAe,2BAA2B,OAAO,uBAAuB,QAAQ;AAClF,UAAM,WAAW,OAAO;AACxB,aAAS,OAAO;AAAA,MAAO,CAAC,MACtB,SAAS,KAAK,CAAC,OAAO;AACpB,cAAM,QAAQ,GAAG,YAAY;AAC7B,eACE,EAAE,MAAM,YAAY,EAAE,SAAS,KAAK,KACpC,EAAE,YAAY,YAAY,EAAE,SAAS,KAAK,KAC1C,EAAE,OAAO,YAAY,EAAE,SAAS,KAAK;AAAA,MAEzC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,eAAe,wBAAwB,OAAO,gBAAgB,QAAQ;AACxE,UAAM,WAAW,OAAO;AACxB,aAAS,OAAO;AAAA,MAAO,CAAC,MACtB,SAAS,KAAK,CAAC,WAAW,EAAE,OAAO,SAAS,MAAM,CAAC;AAAA,IACrD;AAAA,EACF;AAEA,MAAI,eAAe,wBAAwB,OAAO,gBAAgB,QAAQ;AACxE,UAAM,QAAQ,OAAO;AACrB,aAAS,OAAO;AAAA,MAAO,CAAC,MACtB,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS,CAAC,CAAC;AAAA,IACxC;AAAA,EACF;AAEA,SAAO;AACT;AAEO,IAAM,cAMR;AAAA,EACH,gBAAgB;AAAA,IACd,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,qBAAqB,mBAAmB,mBAAmB,gBAAgB,wBAAwB,4BAA4B,kBAAkB,qBAAqB,yBAAyB,sBAAsB,sBAAsB,4BAA4B,yBAAyB,4BAA4B,2BAA2B;AAAA,IACjW,YAAY;AAAA,EACd;AAAA,EACA,YAAY;AAAA,IACV,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,qBAAqB,mBAAmB,wBAAwB,gBAAgB,mBAAmB,4BAA4B,yBAAyB,sBAAsB,sBAAsB,yBAAyB,4BAA4B,2BAA2B;AAAA,IAC9R,gBAAgB;AAAA,MACd,gBAAgB,CAAC,YAAY,UAAU,WAAW,gBAAgB;AAAA,MAClE,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,wBAAwB,gBAAgB,wBAAwB,mBAAmB,yBAAyB,0BAA0B;AAAA,IAChJ,gBAAgB;AAAA,MACd,uBAAuB,CAAC,WAAW,UAAU,YAAY,MAAM;AAAA,IACjE;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,mBAAmB,uBAAuB;AAAA,IACpD,gBAAgB;AAAA,MACd,uBAAuB,CAAC,cAAc,YAAY;AAAA,IACpD;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,4BAA4B,yBAAyB,0BAA0B;AAAA,IACzF,gBAAgB;AAAA,MACd,uBAAuB,CAAC,OAAO,OAAO,UAAU,WAAW;AAAA,IAC7D;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,qBAAqB,uBAAuB;AAAA,IACtD,gBAAgB;AAAA,MACd,uBAAuB,CAAC,WAAW,cAAc,OAAO;AAAA,IAC1D;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,qBAAqB,uBAAuB;AAAA,EACxD;AAAA,EACA,gBAAgB;AAAA,IACd,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,kBAAkB,0BAA0B;AAAA,EACxD;AAAA,EACA,gBAAgB;AAAA,IACd,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,gBAAgB;AAAA,EAC5B;AAAA,EACA,sBAAsB;AAAA,IACpB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,qBAAqB,mBAAmB,4BAA4B,yBAAyB,sBAAsB,0BAA0B;AAAA,EACzJ;AAAA,EACA,aAAa;AAAA,IACX,MAAM;AAAA,IACN,aAAa;AAAA,IACb,SAAS,CAAC,yBAAyB,sBAAsB,sBAAsB,4BAA4B,yBAAyB,4BAA4B,2BAA2B;AAAA,EAC7L;AACF;;;AC9IO,IAAM,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgG/B,IAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;A7B3DpC,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,QAAAC,OAAM,eAAe;AAC9B,SAAS,qBAAqB;AAoB9B,IAAM,sBAA8C;AAAA,EAClD,mBACE;AAAA,EACF,iBACE;AAAA,EACF,iBACE;AAAA,EACF,cACE;AAAA,EACF,sBACE;AAAA,EACF,0BACE;AAAA,EACF,sBACE;AAAA,EACF,gBACE;AAAA,EACF,gBACE;AAAA,EACF,mBACE;AAAA,EACF,uBACE;AAAA,EACF,oBACE;AAAA,EACF,oBACE;AAAA,EACF,0BACE;AAAA,EACF,uBACE;AAAA,EACF,0BACE;AAAA,EACF,2BACE;AACJ;AAEA,SAAS,gBAAgB,QAAgC;AACvD,QAAM,EAAE,QAAQ,IAAI;AACpB,QAAM,QAAQ;AAAA,IACZ,6BAA6B,OAAO,SAAS,OAAO,OAAO,MAAM;AAAA,IACjE,mBAAmB,QAAQ,aAAa,KAAK,QAAQ,QAAQ,cAAc,QAAQ,IAAI,UAAU,QAAQ,MAAM,YAAY,QAAQ,GAAG;AAAA,IACtI,YAAY,QAAQ,cAAc,eAAe,QAAQ,YAAY;AAAA,EACvE;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,oBAAoB,QAA4B;AACvD,QAAM,QAAQ;AAAA,IACZ,WAAW,OAAO,MAAM,WAAM,OAAO,MAAM;AAAA,IAC3C,sBAAsB,OAAO,gBAAgB,eAAe,OAAO,aAAa;AAAA,EAClF;AACA,MAAI,OAAO,UAAU,QAAQ;AAC3B,UAAM,KAAK,aAAa,OAAO,SAAS,MAAM,EAAE;AAAA,EAClD;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,eAAe,iBAAiB,QAAsC;AACpE,MAAI;AACJ,MAAI;AACF,gBAAY,MAAM,aAAa,MAAM;AAAA,EACvC,QAAQ;AACN,gBAAY;AAAA,EACd;AACA,SAAO,EAAE,QAAQ,WAAW,aAAa,MAAM,GAAG,UAAU;AAC9D;AAEO,SAAS,aAAa,eAAkC;AAC7D,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,oBAAoB,SAAS,QAAQ;AAAA,IAC7C,EAAE,cAAc,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE,EAAE;AAAA,EAC5D;AAEA,QAAM,cAAyB;AAAA,IAC7B,IAAI,wBAAwB;AAAA,IAC5B,IAAI,sBAAsB;AAAA,IAC1B,IAAI,sBAAsB;AAAA,IAC1B,IAAI,mBAAmB;AAAA,IACvB,IAAI,2BAA2B;AAAA,IAC/B,IAAI,8BAA8B;AAAA,IAClC,IAAI,0BAA0B;AAAA,IAC9B,IAAI,qBAAqB;AAAA,IACzB,IAAI,qBAAqB;AAAA,IACzB,IAAI,wBAAwB;AAAA,IAC5B,IAAI,2BAA2B;AAAA,IAC/B,IAAI,yBAAyB;AAAA,IAC7B,IAAI,yBAAyB;AAAA,IAC7B,IAAI,8BAA8B;AAAA,IAClC,IAAI,2BAA2B;AAAA,IAC/B,IAAI,8BAA8B;AAAA,IAClC,IAAI,+BAA+B;AAAA,EACrC;AAEA,QAAM,aAAa,oBAAI,IAAqB;AAC5C,aAAW,KAAK,aAAa;AAC3B,eAAW,IAAI,EAAE,YAAY,CAAC;AAAA,EAChC;AAKA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,6CAA6C;AAAA,MACpF,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,qDAAqD;AAAA,MAC/F,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,0EAA0E;AAAA,MACpH,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,0DAA0D;AAAA,IACjH;AAAA,IACA,OAAO,EAAE,QAAQ,UAAU,WAAW,YAAY,MAAM;AACtD,UAAI;AACF,cAAM,IAAI,UAAU;AACpB,YAAI;AAEJ,YAAI,UAAU;AACZ,mBAAS,MAAM,wBAAwB,aAAa,GAAG;AAAA,YACrD,SAAS;AAAA,YACT,UAAU,aAAa;AAAA,YACvB,YAAY;AAAA,UACd,CAAC;AAAA,QACH,OAAO;AACL,mBAAS,MAAM,eAAe,aAAa,CAAC;AAAA,QAC9C;AAEA,eAAO;AAAA,UACL,SAAS;AAAA,YACP,EAAE,MAAM,QAAQ,MAAM,gBAAgB,MAAM,EAAE;AAAA,YAC9C,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE;AAAA,UACxD;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAGA,QAAM,qBAAqF;AAAA,IACzF,EAAE,UAAU,mBAAmB,YAAY,qBAAqB,OAAO,6BAA6B;AAAA,IACpG,EAAE,UAAU,wBAAwB,YAAY,mBAAmB,OAAO,kBAAkB;AAAA,IAC5F,EAAE,UAAU,wBAAwB,YAAY,mBAAmB,OAAO,kBAAkB;AAAA,IAC5F,EAAE,UAAU,qBAAqB,YAAY,gBAAgB,OAAO,eAAe;AAAA,IACnF,EAAE,UAAU,6BAA6B,YAAY,wBAAwB,OAAO,uBAAuB;AAAA,IAC3G,EAAE,UAAU,iCAAiC,YAAY,4BAA4B,OAAO,2BAA2B;AAAA,IACvH,EAAE,UAAU,6BAA6B,YAAY,wBAAwB,OAAO,uBAAuB;AAAA,IAC3G,EAAE,UAAU,uBAAuB,YAAY,kBAAkB,OAAO,iBAAiB;AAAA,IACzF,EAAE,UAAU,uBAAuB,YAAY,kBAAkB,OAAO,iBAAiB;AAAA,IACzF,EAAE,UAAU,0BAA0B,YAAY,qBAAqB,OAAO,oBAAoB;AAAA,IAClG,EAAE,UAAU,8BAA8B,YAAY,yBAAyB,OAAO,wBAAwB;AAAA,IAC9G,EAAE,UAAU,2BAA2B,YAAY,sBAAsB,OAAO,qBAAqB;AAAA,IACrG,EAAE,UAAU,2BAA2B,YAAY,sBAAsB,OAAO,qBAAqB;AAAA,IACrG,EAAE,UAAU,iCAAiC,YAAY,4BAA4B,OAAO,2BAA2B;AAAA,IACvH,EAAE,UAAU,8BAA8B,YAAY,yBAAyB,OAAO,wBAAwB;AAAA,IAC9G,EAAE,UAAU,iCAAiC,YAAY,4BAA4B,OAAO,2BAA2B;AAAA,IACvH,EAAE,UAAU,kCAAkC,YAAY,6BAA6B,OAAO,4BAA4B;AAAA,EAC5H;AAEA,aAAW,EAAE,UAAU,YAAY,MAAM,KAAK,oBAAoB;AAChE,WAAO;AAAA,MACL;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,6CAA6C,EAAE;AAAA,MACxF,OAAO,EAAE,OAAO,MAAM;AACpB,YAAI;AACF,gBAAM,IAAI,UAAU;AACpB,gBAAM,MAAM,MAAM,iBAAiB,CAAC;AACpC,gBAAM,UAAU,WAAW,IAAI,UAAU;AACzC,gBAAM,SAAqB,MAAM,QAAQ,KAAK,GAAG;AACjD,iBAAO;AAAA,YACL,SAAS;AAAA,cACP,EAAE,MAAM,QAAQ,MAAM,oBAAoB,MAAM,EAAE;AAAA,cAClD,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE;AAAA,YACxD;AAAA,UACF;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,QAC1H;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,OAAO,EAAE,OAAO,EAAE,SAAS,4LAA4L;AAAA,MACvN,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,6CAA6C;AAAA,MACpF,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,qDAAqD;AAAA,MAC/F,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,0EAA0E;AAAA,MACpH,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS,0DAA0D;AAAA,IACjH;AAAA,IACA,OAAO,EAAE,OAAO,QAAQ,UAAU,WAAW,YAAY,MAAM;AAC7D,UAAI;AACF,cAAM,WAAW,YAAY,KAAK;AAClC,YAAI,CAAC,UAAU;AACb,gBAAM,YAAY,OAAO,KAAK,WAAW,EAAE,KAAK,IAAI;AACpD,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,8BAA8B,KAAK,wBAAwB,SAAS,GAAG,CAAC;AAAA,YACxG,SAAS;AAAA,UACX;AAAA,QACF;AAEA,cAAM,IAAI,UAAU;AAGpB,YAAI;AACJ,cAAM,iBAA2B,CAAC;AAElC,YAAI,SAAS,QAAQ,SAAS,KAAK,GAAG;AACpC,6BAAmB;AAAA,QACrB,OAAO;AACL,6BAAmB,CAAC;AACpB,qBAAW,OAAO,SAAS,SAAS;AAClC,kBAAM,UAAU,WAAW,IAAI,GAAG;AAClC,gBAAI,SAAS;AACX,+BAAiB,KAAK,OAAO;AAAA,YAC/B,OAAO;AACL,6BAAe,KAAK,GAAG;AAAA,YACzB;AAAA,UACF;AAAA,QACF;AAEA,YAAI,iBAAiB,WAAW,GAAG;AACjC,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,2CAA2C,KAAK,yBAAyB,SAAS,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC;AAAA,YACxI,SAAS;AAAA,UACX;AAAA,QACF;AAEA,YAAI;AAEJ,YAAI,UAAU;AACZ,mBAAS,MAAM,wBAAwB,kBAAkB,GAAG;AAAA,YAC1D,SAAS;AAAA,YACT,UAAU,aAAa;AAAA,YACvB,YAAY;AAAA,UACd,CAAC;AAAA,QACH,OAAO;AACL,mBAAS,MAAM,eAAe,kBAAkB,CAAC;AAAA,QACnD;AAGA,YAAI,SAAS,gBAAgB;AAC3B,qBAAW,OAAO,OAAO,SAAS;AAChC,kBAAM,gBAAgB,IAAI,SAAS;AACnC,gBAAI,WAAW,oBAAoB,IAAI,QAAQ,IAAI,UAAU,SAAS,cAAc;AACpF,gBAAI,gBAAgB,IAAI,SAAS;AACjC,gBAAI,IAAI,SAAS,SAAS,eAAe;AACvC,oBAAM,WAAW,gBAAgB,IAAI,SAAS;AAC9C,kBAAI,CAAC,IAAI,SAAU,KAAI,WAAW,CAAC;AACnC,kBAAI,SAAS,KAAK,uBAAuB,QAAQ,0CAA0C;AAAA,YAC7F;AAAA,UACF;AAEA,cAAI,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM;AAC9C,qBAAW,KAAK,OAAO,SAAS;AAC9B,uBAAW,KAAK,EAAE,UAAU;AAC1B,sBAAQ,EAAE,UAAU;AAAA,gBAClB,KAAK;AAAY;AAAY;AAAA,gBAC7B,KAAK;AAAQ;AAAQ;AAAA,gBACrB,KAAK;AAAU;AAAU;AAAA,gBACzB,KAAK;AAAO;AAAO;AAAA,cACrB;AAAA,YACF;AAAA,UACF;AACA,iBAAO,QAAQ,gBAAgB,WAAW,OAAO,SAAS;AAC1D,iBAAO,QAAQ,WAAW;AAC1B,iBAAO,QAAQ,OAAO;AACtB,iBAAO,QAAQ,SAAS;AACxB,iBAAO,QAAQ,MAAM;AAAA,QACvB;AAEA,cAAM,QAAkB;AAAA,UACtB,eAAe,SAAS,IAAI,KAAK,KAAK;AAAA,UACtC,SAAS;AAAA,UACT;AAAA,UACA,gBAAgB,MAAM;AAAA,QACxB;AAEA,YAAI,eAAe,SAAS,GAAG;AAC7B,gBAAM,KAAK,EAAE;AACb,gBAAM,KAAK,YAAY,eAAe,MAAM,uCAAuC,eAAe,KAAK,IAAI,CAAC,EAAE;AAAA,QAChH;AAEA,eAAO;AAAA,UACL,SAAS;AAAA,YACP,EAAE,MAAM,QAAQ,MAAM,MAAM,KAAK,IAAI,EAAE;AAAA,YACvC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE;AAAA,UACxD;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY;AACV,UAAI;AACF,cAAM,SAAS,OAAO,QAAQ,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,GAAG,OAAO;AAAA,UAC7D;AAAA,UACA,MAAM,IAAI;AAAA,UACV,aAAa,IAAI;AAAA,UACjB,SAAS,IAAI;AAAA,UACb,YAAY,IAAI;AAAA,QAClB,EAAE;AACF,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,CAAC,EAAE;AAAA,MAC9E,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,6CAA6C,EAAE;AAAA,IACnF,OAAO,EAAE,aAAa,MAAM;AAC1B,UAAI;AACF,cAAM,SAAyB,KAAK,MAAM,YAAY;AACtD,cAAM,SAAS,uBAAuB,MAAM;AAC5C,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,CAAC,EAAE;AAAA,MACrD,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,0EAA0E,EAAE;AAAA,IAChH,OAAO,EAAE,aAAa,MAAM;AAC1B,UAAI;AACF,cAAM,SAAyB,KAAK,MAAM,YAAY;AACtD,cAAM,SAAS,oBAAoB,MAAM;AACzC,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,CAAC,EAAE;AAAA,MACrD,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,cAAc,EAAE,OAAO,EAAE,SAAS,6CAA6C;AAAA,MAC/E,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,IACnI;AAAA,IACA,OAAO,EAAE,cAAc,QAAQ,MAAM;AACnC,UAAI;AACF,cAAM,SAAyB,KAAK,MAAM,YAAY;AACtD,cAAM,cAAc,UAAU,KAAK,MAAM,OAAO,IAAI;AACpD,cAAM,SAAS,mBAAmB,QAAQ,WAAW;AACrD,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,CAAC,EAAE;AAAA,MACrD,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,cAAc,EAAE,OAAO,EAAE,SAAS,0EAA0E;AAAA,MAC5G,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yFAAyF;AAAA,IACnI;AAAA,IACA,OAAO,EAAE,cAAc,QAAQ,MAAM;AACnC,UAAI;AACF,cAAM,SAAyB,KAAK,MAAM,YAAY;AACtD,cAAM,cAAc,UAAU,KAAK,MAAM,OAAO,IAAI;AACpD,cAAM,SAAS,wBAAwB,QAAQ,WAAW;AAC1D,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,CAAC,EAAE;AAAA,MACrD,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,6CAA6C,EAAE;AAAA,IACnF,OAAO,EAAE,aAAa,MAAM;AAC1B,UAAI;AACF,cAAM,SAAyB,KAAK,MAAM,YAAY;AACtD,cAAM,WAAW,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,WAAW,mBAAmB;AAC5E,YAAI,CAAC,UAAU;AACb,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,mFAAmF,CAAC;AAAA,YACpH,SAAS;AAAA,UACX;AAAA,QACF;AAGA,cAAM,YAAa,SAAwE;AAE3F,YAAI,CAAC,WAAW;AACd,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,oJAAoJ,CAAC;AAAA,YACrL,SAAS;AAAA,UACX;AAAA,QACF;AAEA,cAAM,iBAAyC;AAAA,UAC7C,cAAc;AAAA,UACd,gBAAgB;AAAA,UAChB,aAAa;AAAA,UACb,aAAa;AAAA,UACb,cAAc;AAAA,UACd,SAAS;AAAA,QACX;AACA,cAAM,oBAA6C;AAAA,UACjD,gBAAgB;AAAA,UAChB,aAAa;AAAA,UACb,aAAa;AAAA,UACb,SAAS;AAAA,QACX;AAEA,cAAM,WAAW,UAAU;AAC3B,cAAM,kBAAkB,UAAU;AAClC,cAAM,gBAAgB,UAAU;AAEhC,cAAM,eAAe,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE;AAChE,cAAM,aAAa,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI,EAAE;AAC9D,cAAM,gBAAgB,SAAS;AAG/B,cAAM,QAAkB,CAAC;AACzB,cAAM,KAAK,oCAAoC;AAC/C,cAAM,KAAK,EAAE;AACb,cAAM,KAAK,eAAe,OAAO,SAAS,cAAc,OAAO,MAAM,EAAE;AACvE,cAAM,KAAK,EAAE;AACb,cAAM,KAAK,iCAAiC,eAAe,GAAG;AAC9D,cAAM,KAAK,sBAAsB,cAAc,OAAO,CAAC,EAAE,YAAY,IAAI,cAAc,MAAM,CAAC,CAAC,EAAE;AACjG,cAAM,KAAK,EAAE;AACb,cAAM,KAAK,oBAAoB;AAC/B,cAAM,KAAK,EAAE;AACb,cAAM,KAAK,+BAA+B;AAC1C,cAAM,KAAK,+BAA+B;AAC1C,mBAAW,OAAO,UAAU;AAC1B,gBAAM,SAAS,IAAI,YAAY,OAAO,mBAAmB,IAAI,YAAY,QAAQ,uBAAuB;AACxG,gBAAM,SAAS,eAAe,IAAI,IAAI,KAAK;AAC3C,gBAAM,KAAK,KAAK,IAAI,IAAI,MAAM,MAAM,MAAM,MAAM,IAAI;AAAA,QACtD;AAEA,cAAM,WAAW,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,IAAI;AAC1D,YAAI,SAAS,SAAS,GAAG;AACvB,gBAAM,KAAK,EAAE;AACb,gBAAM,KAAK,kBAAkB,SAAS,MAAM,iIAAiI;AAAA,QAC/K;AAGA,cAAM,WAAW,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,KAAK;AAC3D,YAAI,SAAS,SAAS,GAAG;AACvB,gBAAM,KAAK,EAAE;AACb,gBAAM,KAAK,sCAAsC;AACjD,gBAAM,KAAK,EAAE;AAEb,gBAAM,gBAAgB,CAAC,gBAAgB,aAAa,aAAa,cAAc,SAAS,YAAY;AACpG,gBAAM,SAAS,SAAS;AAAA,YACtB,CAAC,GAAG,MAAM,cAAc,QAAQ,EAAE,IAAI,IAAI,cAAc,QAAQ,EAAE,IAAI;AAAA,UACxE;AACA,cAAI,MAAM;AACV,qBAAW,OAAO,QAAQ;AACxB,kBAAM,QAAQ,kBAAkB,IAAI,IAAI,IAAI,iCAAiC;AAC7E,kBAAM,KAAK,GAAG,GAAG,YAAY,IAAI,IAAI,GAAG,KAAK,EAAE;AAC/C;AAAA,UACF;AAAA,QACF;AAGA,cAAM,KAAK,EAAE;AACb,cAAM,KAAK,sBAAsB;AACjC,cAAM,KAAK,EAAE;AACb,YAAI,SAAS,SAAS,GAAG;AACvB,gBAAM,KAAK,kBAAkB,cAAc,OAAO,CAAC,EAAE,YAAY,IAAI,cAAc,MAAM,CAAC,CAAC,KAAK,YAAY,IAAI,UAAU,oBAAoB,SAAS,MAAM,WAAW;AAAA,QAC1K,OAAO;AACL,gBAAM,KAAK,kBAAkB,cAAc,OAAO,CAAC,EAAE,YAAY,IAAI,cAAc,MAAM,CAAC,CAAC,KAAK,YAAY,IAAI,aAAa,YAAY;AAAA,QAC3I;AAEA,YAAI,kBAAkB,iBAAiB;AACrC,gBAAM,iBAA2F;AAAA,YAC/F,OAAO,EAAE,OAAO,gBAAgB,QAAQ,GAAG,aAAa,CAAC,gBAAgB,WAAW,EAAE;AAAA,YACtF,cAAc,EAAE,OAAO,YAAY,QAAQ,GAAG,aAAa,CAAC,aAAa,YAAY,EAAE;AAAA,YACvF,UAAU,EAAE,OAAO,iBAAiB,QAAQ,GAAG,aAAa,CAAC,OAAO,EAAE;AAAA,UACxE;AACA,gBAAM,OAAO,eAAe,aAAa;AACzC,cAAI,MAAM;AACR,kBAAM,YAAY,KAAK,YAAY;AAAA,cAAO,CAAC,MACzC,SAAS,KAAK,CAAC,QAAQ,IAAI,SAAS,KAAK,CAAC,IAAI,OAAO;AAAA,YACvD;AACA,gBAAI,UAAU,SAAS,GAAG;AACxB,oBAAM,KAAK,yBAAyB,KAAK,KAAK,KAAK,KAAK,MAAM,IAAI,UAAU,mBAAmB,UAAU,KAAK,KAAK,CAAC,EAAE;AAAA,YACxH;AAAA,UACF;AACA,gBAAM,KAAK,gCAAgC,UAAU,IAAI,UAAU,GAAG;AAAA,QACxE;AAEA,cAAM,KAAK,EAAE;AAEb,cAAM,SAAS,MAAM,KAAK,IAAI;AAE9B,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,CAAC,EAAE;AAAA,MACrD,SAAS,KAAK;AACZ,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC;AAAA,UAC9F,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,cAAc,EAAE,OAAO,EAAE,SAAS,6CAA6C;AAAA,MAC/E,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,6CAA6C;AAAA,IAC1F;AAAA,IACA,OAAO,EAAE,cAAc,WAAW,MAAM;AACtC,UAAI;AACF,cAAM,SAAyB,KAAK,MAAM,YAAY;AACtD,cAAM,WAAW,YAAY,QAAQ,UAAU;AAC/C,eAAO;AAAA,UACL,SAAS;AAAA,YACP,EAAE,MAAM,QAAQ,MAAM,2BAA2B,QAAQ,GAAG;AAAA,UAC9D;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC;AAAA,UAC9F,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY;AACV,UAAI;AACF,cAAM,UAAU,YAAY,IAAI,CAAC,OAAO;AAAA,UACtC,MAAM,EAAE;AAAA,UACR,aAAa,oBAAoB,EAAE,UAAU,KAAK,EAAE;AAAA,QACtD,EAAE;AACF,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE,CAAC,EAAE;AAAA,MAC/E,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,qCAAqC,EAAE;AAAA,IAChF,OAAO,EAAE,OAAO,MAAM;AACpB,UAAI;AACF,cAAM,IAAI,UAAU;AACpB,cAAM,WAAW,MAAM,gBAAgB,CAAC;AACxC,eAAO;AAAA,UACL,SAAS;AAAA,YACP,EAAE,MAAM,QAAQ,MAAM,SAAS,SAAS,MAAM,0CAA0C;AAAA,YACxF,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC,EAAE;AAAA,UAC1D;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,QAAQ,EAAE,KAAK,CAAC,QAAQ,MAAM,CAAC,EAAE,SAAS,EAAE,SAAS,+CAA+C;AAAA,IACtG;AAAA,IACA,OAAO,EAAE,OAAO,MAAM;AACpB,UAAI;AACF,cAAM,MAAM,WAAW,SAAS,SAAS;AACzC,cAAM,mBAAmB,uBAAuB,GAAG;AAEnD,YAAI;AACJ,YAAI;AAEF,gBAAM,aAAa,QAAQ,cAAc,YAAY,GAAG,CAAC;AACzD,gBAAM,eAAeA,MAAK,YAAY,MAAM,aAAa,gBAAgB;AACzE,4BAAkBD,cAAa,cAAc,OAAO;AAAA,QACtD,QAAQ;AACN,cAAI;AAEF,kBAAM,aAAa,QAAQ,cAAc,YAAY,GAAG,CAAC;AACzD,kBAAM,eAAeC,MAAK,YAAY,MAAM,MAAM,aAAa,gBAAgB;AAC/E,8BAAkBD,cAAa,cAAc,OAAO;AAAA,UACtD,QAAQ;AACN,mBAAO;AAAA,cACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,wBAAwB,gBAAgB,0EAA0E,CAAC;AAAA,cACnJ,SAAS;AAAA,YACX;AAAA,UACF;AAAA,QACF;AACA,eAAO;AAAA,UACL,SAAS;AAAA,YACP,EAAE,MAAM,QAAQ,MAAM,qCAAqC,IAAI,YAAY,CAAC;AAAA;AAAA,gFAAoH;AAAA,YAChM,EAAE,MAAM,QAAQ,MAAM,gBAAgB;AAAA,UACxC;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,SAAS,KAAK;AAAA,MAC1H;AAAA,IACF;AAAA,EACF;AAIA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,aAAa,uDAAuD,UAAU,gBAAgB;AAAA,IAChG,aAAa;AAAA,MACX,UAAU,CAAC,EAAE,KAAK,oBAAoB,MAAM,wBAAwB,UAAU,gBAAgB,CAAC;AAAA,IACjG;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,aAAa,kEAAkE,UAAU,gBAAgB;AAAA,IAC3G,aAAa;AAAA,MACX,UAAU,CAAC,EAAE,KAAK,2BAA2B,MAAM,sBAAsB,UAAU,gBAAgB,CAAC;AAAA,IACtG;AAAA,EACF;AAIA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa;AAAA,MACX,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,YACP,MAAM;AAAA,YACN,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,mDAAmD,EAAE;AAAA,IACpF,OAAO,EAAE,QAAQ,OAAO;AAAA,MACtB,UAAU;AAAA,QACR;AAAA,UACE,MAAM;AAAA,UACN,SAAS;AAAA,YACP,MAAM;AAAA,YACN,MAAM;AAAA;AAAA;AAAA,EAA8K,OAAO;AAAA,UAC7L;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,YAAY,eAAsC;AACtE,QAAM,SAAS,aAAa,aAAa;AACzC,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAChC;;;A8B7uBA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,aAAa,KAAK,CAAC;AAEzB,IAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBb,IAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,GAAG;AAClD,UAAQ,IAAI,IAAI;AAChB,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAI,KAAK,SAAS,WAAW,GAAG;AAC9B,UAAQ,IAAI,oBAAoB,OAAO,EAAE;AACzC,UAAQ,KAAK,CAAC;AAChB;AAEA,SAAS,OAAO,MAAkC;AAChD,QAAM,MAAM,KAAK,QAAQ,IAAI;AAC7B,MAAI,QAAQ,MAAM,KAAK,MAAM,CAAC,EAAG,QAAO,KAAK,MAAM,CAAC;AACpD,SAAO;AACT;AAEA,SAAS,YAAoB;AAC3B,SACE,OAAO,UAAU,KACjB,QAAQ,IAAI,cACZ,QAAQ,IAAI,sBACZ;AAEJ;AAEA,IAAI,eAAe,aAAa;AAC9B,QAAM,OAAO,OAAO,OAAO,QAAQ,CAAC,KAAK;AACzC,sEAAuC,KAAK,CAAC,EAAE,gBAAAE,gBAAe,MAAM;AAClE,IAAAA,gBAAe,IAAI;AAAA,EACrB,CAAC;AACH,WAAW,eAAe,oBAAoB;AAC5C,QAAM,SAAS,OAAO,UAAU;AAChC,MAAI,CAAC,QAAQ;AACX,YAAQ,MAAM,yDAAyD;AACvE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,SAAS,UAAU;AACzB,oFAA8C,KAAK,CAAC,EAAE,iBAAAC,iBAAgB,MAAM;AAC1E,IAAAA,iBAAgB,QAAQ,MAAM,EAAE,MAAM,CAAC,QAAQ;AAC7C,cAAQ,MAAM,kBAAkB,IAAI,WAAW,GAAG;AAClD,cAAQ,KAAK,CAAC;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AACH,WAAW,cAAc,CAAC,WAAW,WAAW,IAAI,GAAG;AACrD,UAAQ,MAAM,oBAAoB,UAAU,EAAE;AAC9C,UAAQ,MAAM,0CAA0C;AACxD,UAAQ,KAAK,CAAC;AAChB,OAAO;AAEL,QAAM,SAAS,UAAU;AACzB,cAAY,MAAM,EAAE,MAAM,CAAC,QAAQ;AACjC,YAAQ,MAAM,UAAU,GAAG;AAC3B,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;","names":["createServer","join","existsSync","fileURLToPath","readFileSync","existsSync","copyFileSync","join","extname","fileURLToPath","S3Client","__dirname","__filename","STSClient","GetCallerIdentityCommand","STSClient","makeFinding","makeFinding","makeFinding","EC2Client","DescribeInstancesCommand","makeFinding","EC2Client","DescribeInstancesCommand","makeFinding","S3Client","dns","makeFinding","S3Client","dns","EC2Client","DescribeInstancesCommand","RDSClient","DescribeDBInstancesCommand","S3Client","ListBucketsCommand","makeFinding","EC2Client","DescribeInstancesCommand","RDSClient","DescribeDBInstancesCommand","S3Client","ListBucketsCommand","EC2Client","DescribeAddressesCommand","DescribeInstancesCommand","DescribeSecurityGroupsCommand","makeFinding","EC2Client","DescribeAddressesCommand","DescribeInstancesCommand","DescribeSecurityGroupsCommand","RDSClient","DescribeDBInstancesCommand","EC2Client","DescribeVolumesCommand","S3Client","ListBucketsCommand","makeFinding","RDSClient","DescribeDBInstancesCommand","EC2Client","DescribeVolumesCommand","S3Client","ListBucketsCommand","SecurityHubClient","SecurityHubClient","isNotEnabled","GuardDutyClient","ListDetectorsCommand","GetFindingsCommand","GuardDutyClient","ListDetectorsCommand","GetFindingsCommand","Inspector2Client","ListFindingsCommand","Inspector2Client","ListFindingsCommand","isAccessDenied","isNotEnabled","ConfigServiceClient","ConfigServiceClient","riskScore","severity","formatDuration","SEVERITY_ORDER","items","SEVERITY_ORDER","readFileSync","join","startDashboard","deployDashboard"]}
1
+ {"version":3,"sources":["../../src/commands/dashboard.ts","../../src/commands/deploy-dashboard.ts","../../src/index.ts","../../src/version.ts","../../src/utils/aws-client.ts","../../src/utils/assume-role.ts","../../src/utils/org-accounts.ts","../../src/scanners/runner.ts","../../src/scanners/service-detection.ts","../../src/utils/risk-scoring.ts","../../src/scanners/secret-exposure.ts","../../src/scanners/ssl-certificate.ts","../../src/scanners/dns-dangling.ts","../../src/scanners/network-reachability.ts","../../src/scanners/iam-privilege-escalation.ts","../../src/scanners/public-access-verify.ts","../../src/scanners/tag-compliance.ts","../../src/scanners/idle-resources.ts","../../src/scanners/disaster-recovery.ts","../../src/scanners/security-hub-findings.ts","../../src/scanners/guardduty-findings.ts","../../src/scanners/inspector-findings.ts","../../src/scanners/trusted-advisor-findings.ts","../../src/scanners/config-rules-findings.ts","../../src/scanners/access-analyzer-findings.ts","../../src/scanners/patch-compliance-findings.ts","../../src/scanners/imdsv2-enforcement.ts","../../src/scanners/waf-coverage.ts","../../src/tools/report-tool.ts","../../src/tools/mlps-report.ts","../../src/tools/html-report.ts","../../src/tools/save-results.ts","../../src/tools/scan-groups.ts","../../src/resources/index.ts","../../bin/aws-security-mcp.ts"],"sourcesContent":["import { createServer } from \"node:http\";\nimport { readFile } from \"node:fs/promises\";\nimport { join, extname, resolve } from \"node:path\";\nimport { existsSync, copyFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { exec } from \"node:child_process\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = join(__filename, \"..\");\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html\",\n \".js\": \"text/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nexport function startDashboard(port = 3000): void {\n // dashboard/dist is two levels up from dist/src/commands/\n const dashboardDir = join(__dirname, \"../../dashboard/dist\");\n\n if (!existsSync(dashboardDir)) {\n console.error(\n `Dashboard not built. Run \"npm run build:dashboard\" first.\\n` +\n `Expected: ${dashboardDir}`,\n );\n process.exit(1);\n }\n\n // Copy real data.json if available\n const dataSource = join(\n process.env.HOME || process.env.USERPROFILE || \"~\",\n \".aws-security/dashboard/data.json\",\n );\n const dataDest = join(dashboardDir, \"data.json\");\n if (existsSync(dataSource)) {\n copyFileSync(dataSource, dataDest);\n console.log(`Loaded scan data from ${dataSource}`);\n } else {\n console.log(\n \"No scan data found at ~/.aws-security/dashboard/data.json — using bundled sample data\",\n );\n }\n\n const resolvedBase = resolve(dashboardDir);\n\n const server = createServer(async (req, res) => {\n const url = req.url?.split(\"?\")[0] ?? \"/\";\n let filePath = resolve(\n join(dashboardDir, url === \"/\" ? \"index.html\" : url),\n );\n\n // Ensure the resolved path is within dashboardDir\n if (!filePath.startsWith(resolvedBase + \"/\") && filePath !== resolvedBase) {\n res.writeHead(403);\n res.end(\"Forbidden\");\n return;\n }\n\n // SPA fallback: if file doesn't exist and isn't a static asset, serve index.html\n if (!existsSync(filePath)) {\n filePath = join(dashboardDir, \"index.html\");\n }\n\n try {\n const content = await readFile(filePath);\n const ext = extname(filePath);\n res.writeHead(200, {\n \"Content-Type\": MIME_TYPES[ext] || \"application/octet-stream\",\n });\n res.end(content);\n } catch {\n res.writeHead(404);\n res.end(\"Not found\");\n }\n });\n\n server.listen(port, () => {\n const url = `http://localhost:${port}`;\n console.log(`\\nAWS Security Dashboard: ${url}\\n`);\n console.log(\"Press Ctrl+C to stop.\\n\");\n\n // Try to open browser\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"start\"\n : \"xdg-open\";\n exec(`${cmd} ${url}`, () => {\n // ignore errors — browser open is best-effort\n });\n });\n\n server.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n console.error(`Port ${port} is already in use. Try --port <other>`);\n process.exit(1);\n }\n throw err;\n });\n}\n","import { readdirSync, readFileSync, existsSync, copyFileSync } from \"node:fs\";\nimport { join, extname, relative } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n S3Client,\n PutObjectCommand,\n PutBucketWebsiteCommand,\n PutBucketPolicyCommand,\n} from \"@aws-sdk/client-s3\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = join(__filename, \"..\");\n\nconst CONTENT_TYPES: Record<string, string> = {\n \".html\": \"text/html\",\n \".js\": \"text/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nfunction collectFiles(dir: string): string[] {\n const files: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...collectFiles(full));\n } else {\n files.push(full);\n }\n }\n return files;\n}\n\nexport async function deployDashboard(\n bucket: string,\n region: string,\n): Promise<void> {\n const dashboardDir = join(__dirname, \"../../dashboard/dist\");\n\n if (!existsSync(dashboardDir)) {\n console.error(\n `Dashboard not built. Run \"npm run build:dashboard\" first.\\n` +\n `Expected: ${dashboardDir}`,\n );\n process.exit(1);\n }\n\n // Copy real data.json if available\n const dataSource = join(\n process.env.HOME || process.env.USERPROFILE || \"~\",\n \".aws-security/dashboard/data.json\",\n );\n const dataDest = join(dashboardDir, \"data.json\");\n if (existsSync(dataSource)) {\n copyFileSync(dataSource, dataDest);\n console.log(`Loaded scan data from ${dataSource}`);\n } else {\n console.log(\n \"No scan data at ~/.aws-security/dashboard/data.json — deploying with bundled sample data\",\n );\n }\n\n const s3 = new S3Client({ region });\n\n // Configure static website hosting\n console.log(`Configuring s3://${bucket} for static website hosting...`);\n await s3.send(\n new PutBucketWebsiteCommand({\n Bucket: bucket,\n WebsiteConfiguration: {\n IndexDocument: { Suffix: \"index.html\" },\n ErrorDocument: { Key: \"index.html\" }, // SPA fallback\n },\n }),\n );\n\n // Set bucket policy for public read access\n const partition = region.startsWith(\"cn-\") ? \"aws-cn\" : \"aws\";\n console.log(`Setting public read bucket policy on s3://${bucket}...`);\n await s3.send(\n new PutBucketPolicyCommand({\n Bucket: bucket,\n Policy: JSON.stringify({\n Version: \"2012-10-17\",\n Statement: [\n {\n Sid: \"PublicReadGetObject\",\n Effect: \"Allow\",\n Principal: \"*\",\n Action: \"s3:GetObject\",\n Resource: `arn:${partition}:s3:::${bucket}/*`,\n },\n ],\n }),\n }),\n );\n\n // Upload all files\n const files = collectFiles(dashboardDir);\n console.log(`Uploading ${files.length} files to s3://${bucket}...`);\n\n for (const filePath of files) {\n const key = relative(dashboardDir, filePath);\n const ext = extname(filePath);\n const contentType = CONTENT_TYPES[ext] || \"application/octet-stream\";\n const body = readFileSync(filePath);\n\n await s3.send(\n new PutObjectCommand({\n Bucket: bucket,\n Key: key,\n Body: body,\n ContentType: contentType,\n }),\n );\n console.log(` ${key}`);\n }\n\n const domain = region.startsWith(\"cn-\") ? \"amazonaws.com.cn\" : \"amazonaws.com\";\n const websiteUrl = `http://${bucket}.s3-website.${region}.${domain}`;\n console.log(`\\nDashboard deployed successfully!`);\n console.log(`Website URL: ${websiteUrl}`);\n console.log(\n \"\\nNote: Ensure S3 Block Public Access is disabled on this bucket for the website to be accessible.\\n\",\n );\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\n\nimport { VERSION } from \"./version.js\";\nimport type { Scanner } from \"./scanners/base.js\";\nimport { runAllScanners, runMultiAccountScanners } from \"./scanners/runner.js\";\nimport { ServiceDetectionScanner } from \"./scanners/service-detection.js\";\nimport type { ServiceDetectionResult } from \"./scanners/service-detection.js\";\nimport { SecretExposureScanner } from \"./scanners/secret-exposure.js\";\nimport { SslCertificateScanner } from \"./scanners/ssl-certificate.js\";\nimport { DnsDanglingScanner } from \"./scanners/dns-dangling.js\";\nimport { NetworkReachabilityScanner } from \"./scanners/network-reachability.js\";\nimport { IamPrivilegeEscalationScanner } from \"./scanners/iam-privilege-escalation.js\";\nimport { PublicAccessVerifyScanner } from \"./scanners/public-access-verify.js\";\nimport { TagComplianceScanner } from \"./scanners/tag-compliance.js\";\nimport { IdleResourcesScanner } from \"./scanners/idle-resources.js\";\nimport { DisasterRecoveryScanner } from \"./scanners/disaster-recovery.js\";\nimport { SecurityHubFindingsScanner } from \"./scanners/security-hub-findings.js\";\nimport { GuardDutyFindingsScanner } from \"./scanners/guardduty-findings.js\";\nimport { InspectorFindingsScanner } from \"./scanners/inspector-findings.js\";\nimport { TrustedAdvisorFindingsScanner } from \"./scanners/trusted-advisor-findings.js\";\nimport { ConfigRulesFindingsScanner } from \"./scanners/config-rules-findings.js\";\nimport { AccessAnalyzerFindingsScanner } from \"./scanners/access-analyzer-findings.js\";\nimport { PatchComplianceFindingsScanner } from \"./scanners/patch-compliance-findings.js\";\nimport { Imdsv2EnforcementScanner } from \"./scanners/imdsv2-enforcement.js\";\nimport { WafCoverageScanner } from \"./scanners/waf-coverage.js\";\nimport { generateMarkdownReport } from \"./tools/report-tool.js\";\nimport { generateMlps3Report } from \"./tools/mlps-report.js\";\nimport { generateHtmlReport, generateMlps3HtmlReport } from \"./tools/html-report.js\";\nimport { saveResults } from \"./tools/save-results.js\";\nimport { SCAN_GROUPS, applyFindingsFilter } from \"./tools/scan-groups.js\";\nimport {\n SECURITY_RULES_CONTENT,\n RISK_SCORING_CONTENT,\n} from \"./resources/index.js\";\nimport { getPartition, getAccountId } from \"./utils/aws-client.js\";\nimport { listOrgAccounts } from \"./utils/org-accounts.js\";\nimport type { FullScanResult, ScanResult, ScanContext } from \"./types.js\";\nimport { readFileSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\n\nexport { type Scanner } from \"./scanners/base.js\";\nexport { runAllScanners, runMultiAccountScanners } from \"./scanners/runner.js\";\nexport { assumeRole, buildRoleArn, getCurrentAccountId } from \"./utils/assume-role.js\";\nexport { listOrgAccounts, type OrgAccount } from \"./utils/org-accounts.js\";\nexport { generateMarkdownReport } from \"./tools/report-tool.js\";\nexport { generateHtmlReport, generateMlps3HtmlReport } from \"./tools/html-report.js\";\nexport { saveResults, calculateScore } from \"./tools/save-results.js\";\nexport type {\n Finding,\n ScanResult,\n ScanContext,\n FullScanResult,\n DashboardData,\n DashboardHistoryEntry,\n Severity,\n Priority,\n} from \"./types.js\";\n\nconst MODULE_DESCRIPTIONS: Record<string, string> = {\n service_detection:\n \"Detects which AWS security services (Security Hub, GuardDuty, Inspector, Config, Macie) are enabled and assesses security maturity.\",\n secret_exposure:\n \"Checks Lambda env vars and EC2 userData for exposed secrets (AWS keys, private keys, passwords).\",\n ssl_certificate:\n \"Checks ACM certificates for expiry, failed status, and upcoming renewals.\",\n dns_dangling:\n \"Checks Route53 CNAME records for dangling DNS (subdomain takeover risk).\",\n network_reachability:\n \"Analyzes true network reachability by combining Security Group + NACL rules for public EC2 instances.\",\n iam_privilege_escalation:\n \"Detects IAM privilege escalation paths — users/roles that can escalate to admin via policy manipulation, role creation, or service abuse.\",\n public_access_verify:\n \"Verifies actual public accessibility of resources marked as public (S3 HTTP check, RDS DNS resolution).\",\n tag_compliance:\n \"Checks EC2, RDS, and S3 resources for required tags (Environment, Project, Owner).\",\n idle_resources:\n \"Finds unused/idle AWS resources (unattached EBS volumes, unused EIPs, stopped instances, unused security groups) that waste money and increase attack surface.\",\n disaster_recovery:\n \"Assesses disaster recovery readiness — RDS Multi-AZ & backups, EBS snapshot coverage, S3 versioning & cross-region replication.\",\n security_hub_findings:\n \"Aggregates active findings from AWS Security Hub — replaces individual config scanners with centralized compliance checks.\",\n guardduty_findings:\n \"Aggregates threat detection findings from Amazon GuardDuty — account compromise, instance compromise, and reconnaissance.\",\n inspector_findings:\n \"Aggregates vulnerability findings from Amazon Inspector — CVEs in EC2, Lambda, and container images.\",\n trusted_advisor_findings:\n \"Aggregates security checks from AWS Trusted Advisor — requires Business or Enterprise Support plan.\",\n config_rules_findings:\n \"Pulls non-compliant AWS Config Rule evaluation results — configuration compliance violations across all resource types.\",\n access_analyzer_findings:\n \"Pulls active IAM Access Analyzer findings — resources accessible from outside the account (external principals, public access).\",\n patch_compliance_findings:\n \"Checks SSM Patch Manager compliance — managed instances with missing or failed security and system patches.\",\n imdsv2_enforcement:\n \"Checks if EC2 instances enforce IMDSv2 (HttpTokens: required) — IMDSv1 allows credential theft via SSRF.\",\n waf_coverage:\n \"Checks if internet-facing ALBs have WAF Web ACL associated for protection against common web exploits.\",\n};\n\nconst HW_DEFENSE_CHECKLIST = `\n═══════════════════════════════════════════════════\n📋 护网行动补充提醒(超出自动化扫描范围)\n═══════════════════════════════════════════════════\n\n以下事项需要人工确认和执行:\n\n⚠️ 应急隔离/止血方案\n □ 准备专用隔离安全组(无 Inbound/Outbound 规则)\n □ 制定实例隔离 SOP:告警 → 排查 → 封锁攻击IP → 网络隔离 → 安全处置 → 记录攻击项\n □ 明确各系统(生产核心/生产非核心/测试/开发)的应急处置方式\n □ 明确各项目账户及资源的负责人与联系方式\n\n⚠️ 测试/开发环境处置\n □ 非核心系统在护网期间关闭\n □ 测试/开发环境关闭或与生产保持同等安全基线\n □ 确认哪些环境可以紧急关停,避免攻击扩散\n\n⚠️ 值守团队组建\n □ 7×24 监控快速响应团队\n □ 技术与风险分析组\n □ 安全策略下发组\n □ 业务响应组\n □ 明确 AWS TAM/Support 联系方式(ES/EOP 客户)\n\n⚠️ 出入站路径架构图\n □ 确保所有互联网/DX 专线出入站路径在架构图中清晰标注\n □ 明确各 ELB/Public EC2/S3/DX 的数据流向\n □ 识别所有面向互联网的数据交互接口\n\n⚠️ 主动式渗透测试\n □ 护网前联系安全厂商(青藤/长亭/微步等)进行模拟攻击演练\n □ 基于渗透测试报告进行正式护网前的安全加固\n □ 关注 AWS 安全公告(已知漏洞与补丁)\n\n⚠️ WAR-ROOM 实时沟通\n □ 创建护网期间专用沟通渠道(企微/钉钉/飞书/Chime)\n □ 与 AWS TAM 建立 WAR-ROOM 联系(企业级支持客户)\n □ 统一案例标题格式:\"【护网】+ 问题描述\"\n\n⚠️ 密码与凭证管理\n □ 所有 IAM 用户绑定 MFA\n □ AKSK 轮转周期 ≤ 90 天\n □ 避免共享账户使用\n □ S3/Lambda/应用代码中无明文密码\n\n⚠️ 护网后优化\n □ 针对攻击报告逐项应答与修复\n □ 与安全团队建立周期性安全维护流程\n □ 持续补全安全风险\n\n参考:AWS 护网行动 Standard Operation Procedure (Compliance IEM)\n`;\n\nconst SERVICE_RECOMMENDATIONS: Record<string, { icon: string; service: string; impact: string; action: string }> = {\n security_hub_findings: {\n icon: \"🔴\",\n service: \"Security Hub\",\n impact: \"无法获取 300+ 项自动化安全检查(FSBP/CIS/PCI DSS 标准)\",\n action: \"启用 Security Hub 获得最全面的安全态势评估\",\n },\n guardduty_findings: {\n icon: \"🔴\",\n service: \"GuardDuty\",\n impact: \"无法检测威胁活动(恶意 IP、异常 API 调用、加密货币挖矿等)\",\n action: \"启用 GuardDuty 获得持续威胁检测能力\",\n },\n inspector_findings: {\n icon: \"🟡\",\n service: \"Inspector\",\n impact: \"无法扫描 EC2/Lambda/容器的软件漏洞(CVE)\",\n action: \"启用 Inspector 发现已知安全漏洞\",\n },\n trusted_advisor_findings: {\n icon: \"🟡\",\n service: \"Trusted Advisor\",\n impact: \"无法获取 AWS 最佳实践安全检查\",\n action: \"升级至 Business/Enterprise Support 计划以使用 Trusted Advisor 安全检查\",\n },\n config_rules_findings: {\n icon: \"🟡\",\n service: \"AWS Config\",\n impact: \"无法检查资源配置合规状态\",\n action: \"启用 AWS Config 并配置 Config Rules\",\n },\n access_analyzer_findings: {\n icon: \"🟡\",\n service: \"IAM Access Analyzer\",\n impact: \"无法检测资源是否被外部账号或公网访问\",\n action: \"创建 IAM Access Analyzer(账户级或组织级)\",\n },\n patch_compliance_findings: {\n icon: \"🟡\",\n service: \"SSM Patch Manager\",\n impact: \"无法检查实例补丁合规状态\",\n action: \"安装 SSM Agent 并配置 Patch Manager\",\n },\n};\n\nconst SERVICE_NOT_ENABLED_PATTERNS = [\n \"not enabled\",\n \"not found\",\n \"No IAM Access Analyzer\",\n \"No SSM-managed instances\",\n \"requires AWS Business or Enterprise Support\",\n \"not available\",\n \"is not enabled\",\n];\n\nfunction buildServiceReminder(modules: ScanResult[]): string {\n const disabledServices: Array<{ icon: string; service: string; impact: string; action: string }> = [];\n\n for (const mod of modules) {\n const rec = SERVICE_RECOMMENDATIONS[mod.module];\n if (!rec) continue;\n if (!mod.warnings?.length) continue;\n\n const hasNotEnabled = mod.warnings.some((w) =>\n SERVICE_NOT_ENABLED_PATTERNS.some((p) => w.includes(p)),\n );\n if (hasNotEnabled) {\n disabledServices.push(rec);\n }\n }\n\n if (disabledServices.length === 0) return \"\";\n\n const lines = [\n \"\",\n \"⚡ 以下安全服务未启用,部分检查无法执行:\",\n \"\",\n ];\n\n for (const svc of disabledServices) {\n lines.push(`${svc.icon} ${svc.service} 未启用`);\n lines.push(` 影响:${svc.impact}`);\n lines.push(` 建议:${svc.action}`);\n lines.push(\"\");\n }\n\n lines.push(\"启用以上服务后重新扫描可获得更完整的安全评估。\");\n\n return lines.join(\"\\n\");\n}\n\nfunction summarizeResult(result: FullScanResult): string {\n const { summary } = result;\n const lines = [\n `Scan complete for account ${result.accountId} in ${result.region}.`,\n `Total findings: ${summary.totalFindings} (${summary.critical} Critical, ${summary.high} High, ${summary.medium} Medium, ${summary.low} Low)`,\n `Modules: ${summary.modulesSuccess} succeeded, ${summary.modulesError} errored`,\n ];\n\n const reminder = buildServiceReminder(result.modules);\n if (reminder) {\n lines.push(reminder);\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction summarizeScanResult(result: ScanResult): string {\n const lines = [\n `Module: ${result.module} — ${result.status}`,\n `Resources scanned: ${result.resourcesScanned}, Findings: ${result.findingsCount}`,\n ];\n if (result.warnings?.length) {\n lines.push(`Warnings: ${result.warnings.length}`);\n }\n return lines.join(\"\\n\");\n}\n\nasync function buildScanContext(region: string): Promise<ScanContext> {\n let accountId: string;\n try {\n accountId = await getAccountId(region);\n } catch {\n accountId = \"unknown\";\n }\n return { region, partition: getPartition(region), accountId };\n}\n\nexport function createServer(defaultRegion: string): McpServer {\n const server = new McpServer(\n { name: \"aws-security-mcp\", version: VERSION },\n { capabilities: { resources: {}, tools: {}, prompts: {} } },\n );\n\n const allScanners: Scanner[] = [\n new ServiceDetectionScanner(),\n new SecretExposureScanner(),\n new SslCertificateScanner(),\n new DnsDanglingScanner(),\n new NetworkReachabilityScanner(),\n new IamPrivilegeEscalationScanner(),\n new PublicAccessVerifyScanner(),\n new TagComplianceScanner(),\n new IdleResourcesScanner(),\n new DisasterRecoveryScanner(),\n new SecurityHubFindingsScanner(),\n new GuardDutyFindingsScanner(),\n new InspectorFindingsScanner(),\n new TrustedAdvisorFindingsScanner(),\n new ConfigRulesFindingsScanner(),\n new AccessAnalyzerFindingsScanner(),\n new PatchComplianceFindingsScanner(),\n new Imdsv2EnforcementScanner(),\n new WafCoverageScanner(),\n ];\n\n const scannerMap = new Map<string, Scanner>();\n for (const s of allScanners) {\n scannerMap.set(s.moduleName, s);\n }\n\n // --- Tools ---\n\n // 1. scan_all\n server.tool(\n \"scan_all\",\n \"Run all security scanners in parallel (including service detection). Read-only. Does not modify any AWS resources. Supports multi-account org scanning.\",\n {\n region: z.string().optional().describe(\"AWS region to scan (default: server region)\"),\n org_mode: z.boolean().optional().describe(\"Enable multi-account scanning via AWS Organizations\"),\n role_name: z.string().optional().describe(\"IAM role name to assume in child accounts (default: AWSSecurityMCPAudit)\"),\n account_ids: z.array(z.string()).optional().describe(\"Specific account IDs to scan (default: all org accounts)\"),\n },\n async ({ region, org_mode, role_name, account_ids }) => {\n try {\n const r = region ?? defaultRegion;\n let result: FullScanResult;\n\n if (org_mode) {\n result = await runMultiAccountScanners(allScanners, r, {\n orgMode: true,\n roleName: role_name ?? \"AWSSecurityMCPAudit\",\n accountIds: account_ids,\n });\n } else {\n result = await runAllScanners(allScanners, r);\n }\n\n return {\n content: [\n { type: \"text\", text: summarizeResult(result) },\n { type: \"text\", text: JSON.stringify(result, null, 2) },\n ],\n };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // Individual scanner tools\n const individualScanners: Array<{ toolName: string; moduleName: string; label: string }> = [\n { toolName: \"detect_services\", moduleName: \"service_detection\", label: \"Security Service Detection\" },\n { toolName: \"scan_secret_exposure\", moduleName: \"secret_exposure\", label: \"Secret Exposure\" },\n { toolName: \"scan_ssl_certificate\", moduleName: \"ssl_certificate\", label: \"SSL Certificate\" },\n { toolName: \"scan_dns_dangling\", moduleName: \"dns_dangling\", label: \"Dangling DNS\" },\n { toolName: \"scan_network_reachability\", moduleName: \"network_reachability\", label: \"Network Reachability\" },\n { toolName: \"scan_iam_privilege_escalation\", moduleName: \"iam_privilege_escalation\", label: \"IAM Privilege Escalation\" },\n { toolName: \"scan_public_access_verify\", moduleName: \"public_access_verify\", label: \"Public Access Verify\" },\n { toolName: \"scan_tag_compliance\", moduleName: \"tag_compliance\", label: \"Tag Compliance\" },\n { toolName: \"scan_idle_resources\", moduleName: \"idle_resources\", label: \"Idle Resources\" },\n { toolName: \"scan_disaster_recovery\", moduleName: \"disaster_recovery\", label: \"Disaster Recovery\" },\n { toolName: \"scan_security_hub_findings\", moduleName: \"security_hub_findings\", label: \"Security Hub Findings\" },\n { toolName: \"scan_guardduty_findings\", moduleName: \"guardduty_findings\", label: \"GuardDuty Findings\" },\n { toolName: \"scan_inspector_findings\", moduleName: \"inspector_findings\", label: \"Inspector Findings\" },\n { toolName: \"scan_trusted_advisor_findings\", moduleName: \"trusted_advisor_findings\", label: \"Trusted Advisor Findings\" },\n { toolName: \"scan_config_rules_findings\", moduleName: \"config_rules_findings\", label: \"Config Rules Findings\" },\n { toolName: \"scan_access_analyzer_findings\", moduleName: \"access_analyzer_findings\", label: \"Access Analyzer Findings\" },\n { toolName: \"scan_patch_compliance_findings\", moduleName: \"patch_compliance_findings\", label: \"Patch Compliance Findings\" },\n { toolName: \"scan_imdsv2_enforcement\", moduleName: \"imdsv2_enforcement\", label: \"IMDSv2 Enforcement\" },\n { toolName: \"scan_waf_coverage\", moduleName: \"waf_coverage\", label: \"WAF Coverage\" },\n ];\n\n for (const { toolName, moduleName, label } of individualScanners) {\n server.tool(\n toolName,\n `Run ${label} security scanner only. Read-only. Does not modify any AWS resources.`,\n { region: z.string().optional().describe(\"AWS region to scan (default: server region)\") },\n async ({ region }) => {\n try {\n const r = region ?? defaultRegion;\n const ctx = await buildScanContext(r);\n const scanner = scannerMap.get(moduleName)!;\n const result: ScanResult = await scanner.scan(ctx);\n return {\n content: [\n { type: \"text\", text: summarizeScanResult(result) },\n { type: \"text\", text: JSON.stringify(result, null, 2) },\n ],\n };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n }\n\n // scan_group\n server.tool(\n \"scan_group\",\n \"Run a predefined group of security scanners for a specific scenario (e.g., MLPS compliance, network defense). Read-only. Supports multi-account org scanning.\",\n {\n group: z.string().describe(\"Scan group ID: mlps3_precheck, hw_defense, exposure, data_encryption, least_privilege, log_integrity, disaster_recovery, idle_resources, tag_compliance, new_account_baseline, aggregation\"),\n region: z.string().optional().describe(\"AWS region to scan (default: server region)\"),\n org_mode: z.boolean().optional().describe(\"Enable multi-account scanning via AWS Organizations\"),\n role_name: z.string().optional().describe(\"IAM role name to assume in child accounts (default: AWSSecurityMCPAudit)\"),\n account_ids: z.array(z.string()).optional().describe(\"Specific account IDs to scan (default: all org accounts)\"),\n },\n async ({ group, region, org_mode, role_name, account_ids }) => {\n try {\n const groupDef = SCAN_GROUPS[group];\n if (!groupDef) {\n const available = Object.keys(SCAN_GROUPS).join(\", \");\n return {\n content: [{ type: \"text\", text: `Error: Unknown scan group \"${group}\". Available groups: ${available}` }],\n isError: true,\n };\n }\n\n const r = region ?? defaultRegion;\n\n // Resolve scanners: \"ALL\" means all registered scanners\n let selectedScanners: Scanner[];\n const missingModules: string[] = [];\n\n if (groupDef.modules.includes(\"ALL\")) {\n selectedScanners = allScanners;\n } else {\n selectedScanners = [];\n for (const mod of groupDef.modules) {\n const scanner = scannerMap.get(mod);\n if (scanner) {\n selectedScanners.push(scanner);\n } else {\n missingModules.push(mod);\n }\n }\n }\n\n if (selectedScanners.length === 0) {\n return {\n content: [{ type: \"text\", text: `Error: No available scanners for group \"${group}\". Requested modules: ${groupDef.modules.join(\", \")}` }],\n isError: true,\n };\n }\n\n let result: FullScanResult;\n\n if (org_mode) {\n result = await runMultiAccountScanners(selectedScanners, r, {\n orgMode: true,\n roleName: role_name ?? \"AWSSecurityMCPAudit\",\n accountIds: account_ids,\n });\n } else {\n result = await runAllScanners(selectedScanners, r);\n }\n\n // Apply post-filter if the group defines one\n if (groupDef.findingsFilter) {\n for (const mod of result.modules) {\n const originalCount = mod.findings.length;\n mod.findings = applyFindingsFilter(mod.module, mod.findings, groupDef.findingsFilter);\n mod.findingsCount = mod.findings.length;\n if (mod.findings.length < originalCount) {\n const filtered = originalCount - mod.findings.length;\n if (!mod.warnings) mod.warnings = [];\n mod.warnings.push(`Post-filter removed ${filtered} finding(s) not matching group criteria.`);\n }\n }\n // Recalculate summary after filtering\n let critical = 0, high = 0, medium = 0, low = 0;\n for (const m of result.modules) {\n for (const f of m.findings) {\n switch (f.severity) {\n case \"CRITICAL\": critical++; break;\n case \"HIGH\": high++; break;\n case \"MEDIUM\": medium++; break;\n case \"LOW\": low++; break;\n }\n }\n }\n result.summary.totalFindings = critical + high + medium + low;\n result.summary.critical = critical;\n result.summary.high = high;\n result.summary.medium = medium;\n result.summary.low = low;\n }\n\n const lines: string[] = [\n `Scan group: ${groupDef.name} (${group})`,\n groupDef.description,\n \"\",\n summarizeResult(result),\n ];\n\n if (missingModules.length > 0) {\n lines.push(\"\");\n lines.push(`Warning: ${missingModules.length} requested module(s) not available: ${missingModules.join(\", \")}`);\n }\n\n const content: Array<{ type: \"text\"; text: string }> = [\n { type: \"text\", text: lines.join(\"\\n\") },\n { type: \"text\", text: JSON.stringify(result, null, 2) },\n ];\n\n if (group === \"hw_defense\") {\n // Append checklist to summary\n const summaryContent = content[0];\n if (summaryContent && summaryContent.type === \"text\") {\n summaryContent.text += \"\\n\\n\" + HW_DEFENSE_CHECKLIST;\n }\n }\n\n return { content };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // list_groups\n server.tool(\n \"list_groups\",\n \"List available scan groups with descriptions. Read-only.\",\n async () => {\n try {\n const groups = Object.entries(SCAN_GROUPS).map(([id, def]) => ({\n id,\n name: def.name,\n description: def.description,\n modules: def.modules,\n reportType: def.reportType,\n }));\n return { content: [{ type: \"text\", text: JSON.stringify(groups, null, 2) }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // 9. generate_report\n server.tool(\n \"generate_report\",\n \"Generate a Markdown security report from scan results. Read-only. Does not modify any AWS resources.\",\n { scan_results: z.string().describe(\"JSON string of FullScanResult from scan_all\") },\n async ({ scan_results }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const report = generateMarkdownReport(parsed);\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // generate_mlps3_report\n server.tool(\n \"generate_mlps3_report\",\n \"Generate a GB/T 22239-2019 等保三级 compliance pre-check report from scan results. Best used with scan_group mlps3_precheck results. Read-only.\",\n { scan_results: z.string().describe(\"JSON string of FullScanResult from scan_group mlps3_precheck or scan_all\") },\n async ({ scan_results }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const report = generateMlps3Report(parsed);\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // generate_html_report\n server.tool(\n \"generate_html_report\",\n \"Generate a professional HTML security report. Save the output as an .html file.\",\n {\n scan_results: z.string().describe(\"JSON string of FullScanResult from scan_all\"),\n history: z.string().optional().describe(\"JSON string of DashboardHistoryEntry[] from dashboard data.json for 30-day trend charts\"),\n },\n async ({ scan_results, history }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const historyData = history ? JSON.parse(history) : undefined;\n const report = generateHtmlReport(parsed, historyData);\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // generate_mlps3_html_report\n server.tool(\n \"generate_mlps3_html_report\",\n \"Generate a professional HTML MLPS Level 3 compliance report (等保三级). Save as .html file.\",\n {\n scan_results: z.string().describe(\"JSON string of FullScanResult from scan_group mlps3_precheck or scan_all\"),\n history: z.string().optional().describe(\"JSON string of DashboardHistoryEntry[] from dashboard data.json for 30-day trend charts\"),\n },\n async ({ scan_results, history }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const historyData = history ? JSON.parse(history) : undefined;\n const report = generateMlps3HtmlReport(parsed, historyData);\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // 10. generate_maturity_report\n server.tool(\n \"generate_maturity_report\",\n \"Generate a security maturity assessment report from scan_all results. Requires service_detection module output. Read-only.\",\n { scan_results: z.string().describe(\"JSON string of FullScanResult from scan_all\") },\n async ({ scan_results }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const sdModule = parsed.modules.find((m) => m.module === \"service_detection\");\n if (!sdModule) {\n return {\n content: [{ type: \"text\", text: \"Error: scan results do not include service_detection module. Run scan_all first.\" }],\n isError: true,\n };\n }\n\n // Extract the serviceDetection data attached by the scanner\n const detection = (sdModule as ScanResult & { serviceDetection?: ServiceDetectionResult }).serviceDetection;\n\n if (!detection) {\n return {\n content: [{ type: \"text\", text: \"Error: service detection data is missing (possible JSON round-trip loss). Run scan_all to get fresh results with complete service detection data.\" }],\n isError: true,\n };\n }\n\n const serviceImpacts: Record<string, string> = {\n \"CloudTrail\": \"API activity logging\",\n \"Security Hub\": \"+300 security checks\",\n \"GuardDuty\": \"Threat detection\",\n \"Inspector\": \"Vulnerability scanning\",\n \"AWS Config\": \"Configuration tracking\",\n \"Macie\": \"Sensitive data detection\",\n };\n const serviceFreeTrials: Record<string, boolean> = {\n \"Security Hub\": true,\n \"GuardDuty\": true,\n \"Inspector\": true,\n \"Macie\": true,\n };\n\n const services = detection.services;\n const coveragePercent = detection.coveragePercent;\n const maturityLevel = detection.maturityLevel;\n\n const enabledCount = services.filter((s) => s.enabled === true).length;\n const knownCount = services.filter((s) => s.enabled !== null).length;\n const totalServices = services.length;\n\n // Build the report\n const lines: string[] = [];\n lines.push(\"# AWS Security Maturity Assessment\");\n lines.push(\"\");\n lines.push(`## Account: ${parsed.accountId} | Region: ${parsed.region}`);\n lines.push(\"\");\n lines.push(`## Security Service Coverage: ${coveragePercent}%`);\n lines.push(`## Maturity Level: ${maturityLevel.charAt(0).toUpperCase() + maturityLevel.slice(1)}`);\n lines.push(\"\");\n lines.push(\"### Service Status\");\n lines.push(\"\");\n lines.push(\"| Service | Status | Impact |\");\n lines.push(\"|---------|--------|--------|\");\n for (const svc of services) {\n const status = svc.enabled === true ? \"\\u2705 Enabled\" : svc.enabled === false ? \"\\u274c Not Enabled\" : \"\\u26a0\\ufe0f Unknown\";\n const impact = serviceImpacts[svc.name] ?? \"\";\n lines.push(`| ${svc.name} | ${status} | ${impact} |`);\n }\n\n const unknowns = services.filter((s) => s.enabled === null);\n if (unknowns.length > 0) {\n lines.push(\"\");\n lines.push(`> \\u26a0\\ufe0f ${unknowns.length} service(s) could not be checked (access denied or detection error). Re-run with appropriate permissions for accurate coverage.`);\n }\n\n // Recommendations\n const disabled = services.filter((s) => s.enabled === false);\n if (disabled.length > 0) {\n lines.push(\"\");\n lines.push(\"### Recommendations (Priority Order)\");\n lines.push(\"\");\n // Priority order: Security Hub, GuardDuty, Inspector, Config, Macie, CloudTrail\n const priorityOrder = [\"Security Hub\", \"GuardDuty\", \"Inspector\", \"AWS Config\", \"Macie\", \"CloudTrail\"];\n const sorted = disabled.sort(\n (a, b) => priorityOrder.indexOf(a.name) - priorityOrder.indexOf(b.name),\n );\n let idx = 1;\n for (const svc of sorted) {\n const trial = serviceFreeTrials[svc.name] ? \" \\u2014 free trial available\" : \"\";\n lines.push(`${idx}. Enable ${svc.name}${trial}`);\n idx++;\n }\n }\n\n // Maturity roadmap\n lines.push(\"\");\n lines.push(\"### Maturity Roadmap\");\n lines.push(\"\");\n if (unknowns.length > 0) {\n lines.push(`- **Current**: ${maturityLevel.charAt(0).toUpperCase() + maturityLevel.slice(1)} (${enabledCount}/${knownCount} known services, ${unknowns.length} unknown)`);\n } else {\n lines.push(`- **Current**: ${maturityLevel.charAt(0).toUpperCase() + maturityLevel.slice(1)} (${enabledCount}/${totalServices} services)`);\n }\n\n if (maturityLevel !== \"comprehensive\") {\n const nextMilestones: Record<string, { level: string; target: number; suggestions: string[] }> = {\n basic: { level: \"Intermediate\", target: 2, suggestions: [\"Security Hub\", \"GuardDuty\"] },\n intermediate: { level: \"Advanced\", target: 4, suggestions: [\"Inspector\", \"AWS Config\"] },\n advanced: { level: \"Comprehensive\", target: 6, suggestions: [\"Macie\"] },\n };\n const next = nextMilestones[maturityLevel];\n if (next) {\n const remaining = next.suggestions.filter((s) =>\n services.some((svc) => svc.name === s && !svc.enabled),\n );\n if (remaining.length > 0) {\n lines.push(`- **Next milestone**: ${next.level} (${next.target}/${knownCount}) \\u2014 enable ${remaining.join(\" + \")}`);\n }\n }\n lines.push(`- **Target**: Comprehensive (${knownCount}/${knownCount})`);\n }\n\n lines.push(\"\");\n\n const report = lines.join(\"\\n\");\n\n return { content: [{ type: \"text\", text: report }] };\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],\n isError: true,\n };\n }\n },\n );\n\n // 11. save_results\n server.tool(\n \"save_results\",\n \"Saves scan results to local disk or S3 for dashboard display. Does not modify any AWS resources.\",\n {\n scan_results: z.string().describe(\"JSON string of FullScanResult from scan_all\"),\n output_dir: z.string().optional().describe(\"Output directory (default: ~/.aws-security)\"),\n },\n async ({ scan_results, output_dir }) => {\n try {\n const parsed: FullScanResult = JSON.parse(scan_results);\n const dataPath = saveResults(parsed, output_dir);\n return {\n content: [\n { type: \"text\", text: `Dashboard data saved to ${dataPath}` },\n ],\n };\n } catch (err) {\n return {\n content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],\n isError: true,\n };\n }\n },\n );\n\n // 11. list_modules\n server.tool(\n \"list_modules\",\n \"List available security scan modules with descriptions. Read-only. Does not modify any AWS resources.\",\n async () => {\n try {\n const modules = allScanners.map((s) => ({\n name: s.moduleName,\n description: MODULE_DESCRIPTIONS[s.moduleName] ?? s.moduleName,\n }));\n return { content: [{ type: \"text\", text: JSON.stringify(modules, null, 2) }] };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // list_org_accounts\n server.tool(\n \"list_org_accounts\",\n \"List all accounts in the AWS Organization. Useful for discovering accounts before multi-account scanning. Read-only.\",\n { region: z.string().optional().describe(\"AWS region (default: server region)\") },\n async ({ region }) => {\n try {\n const r = region ?? defaultRegion;\n const accounts = await listOrgAccounts(r);\n return {\n content: [\n { type: \"text\", text: `Found ${accounts.length} active account(s) in the organization.` },\n { type: \"text\", text: JSON.stringify(accounts, null, 2) },\n ],\n };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // get_setup_template\n server.tool(\n \"get_setup_template\",\n \"Returns the CloudFormation StackSet template for deploying the cross-account security audit IAM role. Read-only.\",\n {\n format: z.enum([\"yaml\", \"json\"]).optional().describe(\"Template format: yaml or json (default: yaml)\"),\n },\n async ({ format }) => {\n try {\n const ext = format === \"json\" ? \"json\" : \"yaml\";\n const templateFileName = `stackset-audit-role.${ext}`;\n // Try multiple locations for the template\n let templateContent: string;\n try {\n // When running from source\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const templatePath = join(currentDir, \"..\", \"templates\", templateFileName);\n templateContent = readFileSync(templatePath, \"utf-8\");\n } catch {\n try {\n // When running from dist\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const templatePath = join(currentDir, \"..\", \"..\", \"templates\", templateFileName);\n templateContent = readFileSync(templatePath, \"utf-8\");\n } catch {\n return {\n content: [{ type: \"text\", text: `Error: Template file ${templateFileName} not found. Ensure the templates/ directory is included in the package.` }],\n isError: true,\n };\n }\n }\n return {\n content: [\n { type: \"text\", text: `CloudFormation StackSet template (${ext.toUpperCase()}) for cross-account audit role:\\n\\nDeploy this as a StackSet from your Management Account to all member accounts.` },\n { type: \"text\", text: templateContent },\n ],\n };\n } catch (err) {\n return { content: [{ type: \"text\", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };\n }\n },\n );\n\n // --- Resources ---\n\n server.resource(\n \"security-rules\",\n \"security://rules\",\n { description: \"Describes all 19 scan modules and their check rules\", mimeType: \"text/markdown\" },\n async () => ({\n contents: [{ uri: \"security://rules\", text: SECURITY_RULES_CONTENT, mimeType: \"text/markdown\" }],\n }),\n );\n\n server.resource(\n \"risk-scoring\",\n \"security://risk-scoring\",\n { description: \"Describes the risk scoring model and severity/priority mapping\", mimeType: \"text/markdown\" },\n async () => ({\n contents: [{ uri: \"security://risk-scoring\", text: RISK_SCORING_CONTENT, mimeType: \"text/markdown\" }],\n }),\n );\n\n // --- Prompts ---\n\n server.prompt(\n \"security-scan\",\n \"Run a full AWS security scan workflow: scan all modules, generate a report, and summarize findings.\",\n async () => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: \"Run scan_all to perform a full AWS security scan. Then take the JSON result and pass it to generate_report to create a Markdown report. Finally, summarize the top findings and recommend immediate actions based on priority.\",\n },\n },\n ],\n }),\n );\n\n server.prompt(\n \"analyze-finding\",\n \"Deep analysis of a specific security finding.\",\n { finding: z.string().describe(\"JSON string of a single Finding object to analyze\") },\n async ({ finding }) => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `Analyze this AWS security finding in depth. Explain the risk, potential attack vectors, blast radius, and provide detailed step-by-step remediation guidance.\\n\\nFinding:\\n${finding}`,\n },\n },\n ],\n }),\n );\n\n server.prompt(\n \"hw_defense_checklist\",\n \"护网行动完整检查清单 — 包含自动化扫描项和人工检查项\",\n async () => ({\n messages: [\n {\n role: \"user\",\n content: {\n type: \"text\",\n text: `请基于以下护网行动检查清单,帮助我制定护网准备计划:\\n\\n${HW_DEFENSE_CHECKLIST}\\n\\n自动化扫描部分请使用 scan_group hw_defense 执行。以上人工检查项请逐项确认并提供具体建议。`,\n },\n },\n ],\n }),\n );\n\n return server;\n}\n\nexport async function startServer(defaultRegion: string): Promise<void> {\n const server = createServer(defaultRegion);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","export const VERSION = \"0.5.1\";\n","import { STSClient, GetCallerIdentityCommand } from \"@aws-sdk/client-sts\";\n\nlet cachedAccountId: string | undefined;\n\nexport function getPartition(region: string): string {\n if (region.startsWith(\"cn-\")) return \"aws-cn\";\n if (region.startsWith(\"us-gov-\")) return \"aws-us-gov\";\n return \"aws\";\n}\n\nexport function getIamRegion(region: string): string {\n // IAM is global in standard AWS (us-east-1) but regional in China\n if (region.startsWith(\"cn-\")) return region;\n return \"us-east-1\";\n}\n\nexport async function getAccountId(region?: string): Promise<string> {\n if (cachedAccountId) return cachedAccountId;\n\n const stsRegion = region ?? \"us-east-1\";\n const sts = new STSClient({ region: stsRegion });\n const response = await sts.send(new GetCallerIdentityCommand({}));\n cachedAccountId = response.Account ?? \"unknown\";\n return cachedAccountId;\n}\n\nexport function createClient<T>(\n ClientClass: new (config: any) => T,\n region?: string,\n credentials?: { accessKeyId: string; secretAccessKey: string; sessionToken: string },\n): T {\n const config: any = { region: region ?? \"us-east-1\" };\n if (credentials) config.credentials = credentials;\n return new ClientClass(config);\n}\n","import { STSClient, AssumeRoleCommand, GetCallerIdentityCommand } from \"@aws-sdk/client-sts\";\n\nexport async function getCurrentAccountId(region: string): Promise<string> {\n const sts = new STSClient({ region });\n const result = await sts.send(new GetCallerIdentityCommand({}));\n return result.Account!;\n}\n\nexport const DEFAULT_EXTERNAL_ID = \"aws-security-mcp-audit\";\n\nexport async function assumeRole(roleArn: string, region: string, options?: {\n sessionName?: string;\n externalId?: string;\n}): Promise<{\n accessKeyId: string;\n secretAccessKey: string;\n sessionToken: string;\n}> {\n const sessionName = options?.sessionName ?? \"aws-security-mcp\";\n const externalId = options?.externalId ?? DEFAULT_EXTERNAL_ID;\n const sts = new STSClient({ region });\n const result = await sts.send(new AssumeRoleCommand({\n RoleArn: roleArn,\n RoleSessionName: sessionName,\n ExternalId: externalId,\n DurationSeconds: 3600,\n }));\n return {\n accessKeyId: result.Credentials!.AccessKeyId!,\n secretAccessKey: result.Credentials!.SecretAccessKey!,\n sessionToken: result.Credentials!.SessionToken!,\n };\n}\n\nexport function buildRoleArn(accountId: string, roleName: string, partition = \"aws\"): string {\n return `arn:${partition}:iam::${accountId}:role/${roleName}`;\n}\n","import { OrganizationsClient, ListAccountsCommand } from \"@aws-sdk/client-organizations\";\n\nexport interface OrgAccount {\n id: string;\n name: string;\n email: string;\n status: string;\n}\n\nexport async function listOrgAccounts(region: string): Promise<OrgAccount[]> {\n // Organizations API must use specific endpoints\n // Global: us-east-1, China: cn-northwest-1\n const orgRegion = region.startsWith(\"cn-\") ? \"cn-northwest-1\" : \"us-east-1\";\n const client = new OrganizationsClient({ region: orgRegion });\n const accounts: OrgAccount[] = [];\n let nextToken: string | undefined;\n\n do {\n const result = await client.send(new ListAccountsCommand({ NextToken: nextToken }));\n for (const acct of result.Accounts || []) {\n if (acct.Status === \"ACTIVE\") {\n accounts.push({\n id: acct.Id!,\n name: acct.Name || \"\",\n email: acct.Email || \"\",\n status: acct.Status!,\n });\n }\n }\n nextToken = result.NextToken;\n } while (nextToken);\n\n return accounts;\n}\n","import { FullScanResult, ScanResult, ScanContext, AwsCredentials } from \"../types.js\";\nimport { Scanner } from \"./base.js\";\nimport { getAccountId, getPartition } from \"../utils/aws-client.js\";\nimport { assumeRole, buildRoleArn } from \"../utils/assume-role.js\";\nimport { listOrgAccounts, type OrgAccount } from \"../utils/org-accounts.js\";\n\n/** Aggregation scanners that already pull cross-account data — run once from admin account */\nconst AGGREGATION_MODULES = new Set([\n \"security_hub_findings\",\n \"guardduty_findings\",\n \"inspector_findings\",\n]);\n\nfunction buildSummary(modules: ScanResult[]) {\n let critical = 0;\n let high = 0;\n let medium = 0;\n let low = 0;\n let modulesSuccess = 0;\n let modulesError = 0;\n\n for (const m of modules) {\n if (m.status === \"success\") {\n modulesSuccess++;\n } else {\n modulesError++;\n }\n for (const f of m.findings) {\n switch (f.severity) {\n case \"CRITICAL\": critical++; break;\n case \"HIGH\": high++; break;\n case \"MEDIUM\": medium++; break;\n case \"LOW\": low++; break;\n }\n }\n }\n\n return {\n totalFindings: critical + high + medium + low,\n critical,\n high,\n medium,\n low,\n modulesSuccess,\n modulesError,\n };\n}\n\nasync function runScannersWithContext(\n scanners: Scanner[],\n ctx: ScanContext,\n): Promise<ScanResult[]> {\n const settled = await Promise.allSettled(scanners.map((s) => s.scan(ctx)));\n\n return settled.map((result, i) => {\n if (result.status === \"fulfilled\") {\n // Stamp accountId on all findings\n for (const f of result.value.findings) {\n if (!f.accountId) f.accountId = ctx.accountId;\n if (!f.accountAlias && ctx.accountAlias) f.accountAlias = ctx.accountAlias;\n }\n return result.value;\n }\n return {\n module: scanners[i].moduleName,\n status: \"error\" as const,\n error: result.reason instanceof Error ? result.reason.message : String(result.reason),\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: 0,\n findings: [],\n };\n });\n}\n\nexport async function runAllScanners(\n scanners: Scanner[],\n region: string,\n): Promise<FullScanResult> {\n const scanStart = new Date().toISOString();\n\n // Best-effort accountId retrieval — don't let STS failure break the whole scan\n let accountId: string;\n try {\n accountId = await getAccountId(region);\n } catch {\n accountId = \"unknown\";\n }\n\n const partition = getPartition(region);\n const ctx: ScanContext = { region, partition, accountId };\n\n const modules = await runScannersWithContext(scanners, ctx);\n\n const scanEnd = new Date().toISOString();\n\n return {\n scanStart,\n scanEnd,\n region,\n accountId,\n modules,\n summary: buildSummary(modules),\n };\n}\n\nexport interface MultiAccountOptions {\n orgMode: boolean;\n roleName: string;\n accountIds?: string[];\n}\n\nexport async function runMultiAccountScanners(\n scanners: Scanner[],\n region: string,\n opts: MultiAccountOptions,\n): Promise<FullScanResult> {\n const scanStart = new Date().toISOString();\n const partition = getPartition(region);\n\n // Get current (admin) account ID\n let adminAccountId: string;\n try {\n adminAccountId = await getAccountId(region);\n } catch {\n adminAccountId = \"unknown\";\n }\n\n // Discover org accounts\n let accounts: OrgAccount[];\n try {\n accounts = await listOrgAccounts(region);\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n // Graceful fallback: scan current account only, with clear warning\n const result = await runAllScanners(scanners, region);\n if (result.modules.length > 0) {\n if (!result.modules[0].warnings) result.modules[0].warnings = [];\n result.modules[0].warnings.unshift(`org_mode enabled but Organizations listing failed: ${errMsg}. Scanning current account only.`);\n }\n return result;\n }\n\n // Filter to specific accounts if requested\n if (opts.accountIds?.length) {\n const idSet = new Set(opts.accountIds);\n accounts = accounts.filter((a) => idSet.has(a.id));\n }\n\n // Separate aggregation vs per-account scanners\n const aggregationScanners = scanners.filter((s) => AGGREGATION_MODULES.has(s.moduleName));\n const perAccountScanners = scanners.filter((s) => !AGGREGATION_MODULES.has(s.moduleName));\n\n const allModules: ScanResult[] = [];\n\n // 1. Run aggregation scanners ONCE from admin account (they already aggregate cross-account)\n if (aggregationScanners.length > 0) {\n const adminCtx: ScanContext = { region, partition, accountId: adminAccountId };\n const aggResults = await runScannersWithContext(aggregationScanners, adminCtx);\n allModules.push(...aggResults);\n }\n\n // 2. Run per-account scanners for each account\n for (const account of accounts) {\n let credentials: AwsCredentials | undefined;\n let accountAlias = account.name;\n\n // Skip assume-role for the admin account itself\n if (account.id !== adminAccountId) {\n try {\n const roleArn = buildRoleArn(account.id, opts.roleName, partition);\n credentials = await assumeRole(roleArn, region);\n } catch (err) {\n // Record a failed module for this account\n allModules.push({\n module: `assume_role_${account.id}`,\n status: \"error\",\n error: `Failed to assume role in account ${account.id} (${account.name}): ${err instanceof Error ? err.message : String(err)}`,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: 0,\n findings: [],\n });\n continue;\n }\n }\n\n const ctx: ScanContext = {\n region,\n partition,\n accountId: account.id,\n accountAlias,\n credentials,\n };\n\n const accountResults = await runScannersWithContext(perAccountScanners, ctx);\n allModules.push(...accountResults);\n }\n\n const scanEnd = new Date().toISOString();\n\n // Post-filter: if account_ids was specified, filter aggregation findings too\n if (opts.accountIds?.length) {\n const idSet = new Set(opts.accountIds);\n for (const mod of allModules) {\n if (AGGREGATION_MODULES.has(mod.module)) {\n mod.findings = mod.findings.filter((f) => !f.accountId || idSet.has(f.accountId));\n mod.findingsCount = mod.findings.length;\n }\n }\n }\n\n return {\n scanStart,\n scanEnd,\n region,\n accountId: adminAccountId,\n modules: allModules,\n summary: buildSummary(allModules),\n };\n}\n","import {\n SecurityHubClient,\n DescribeHubCommand,\n} from \"@aws-sdk/client-securityhub\";\nimport {\n GuardDutyClient,\n ListDetectorsCommand,\n} from \"@aws-sdk/client-guardduty\";\nimport {\n Inspector2Client,\n BatchGetAccountStatusCommand,\n} from \"@aws-sdk/client-inspector2\";\nimport {\n ConfigServiceClient,\n DescribeConfigurationRecordersCommand,\n} from \"@aws-sdk/client-config-service\";\nimport {\n Macie2Client,\n GetMacieSessionCommand,\n} from \"@aws-sdk/client-macie2\";\nimport {\n CloudTrailClient,\n DescribeTrailsCommand,\n} from \"@aws-sdk/client-cloudtrail\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nexport interface ServiceStatus {\n name: string;\n enabled: boolean | null; // null = unknown (access denied or detection error)\n details?: string;\n recommendation?: string;\n freeTrialAvailable?: boolean;\n}\n\nexport interface ServiceDetectionResult {\n services: ServiceStatus[];\n coveragePercent: number;\n maturityLevel: \"basic\" | \"intermediate\" | \"advanced\" | \"comprehensive\";\n}\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction isAccessDenied(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const name = (err as Error & { name?: string }).name ?? \"\";\n const code = (err as Error & { Code?: string }).Code ?? \"\";\n return (\n name === \"AccessDeniedException\" ||\n name === \"UnauthorizedAccess\" ||\n name === \"AccessDenied\" ||\n code === \"AccessDeniedException\" ||\n code === \"AccessDenied\" ||\n name === \"ForbiddenException\" ||\n // AWS SDK v3 uses __type or $metadata for some errors\n (err.message?.includes(\"is not authorized to perform\") ?? false) ||\n (err.message?.includes(\"Access Denied\") ?? false)\n );\n}\n\nfunction isNotEnabled(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n return (\n err.name === \"InvalidAccessException\" || // Security Hub specific\n err.name === \"DisabledException\" ||\n err.message.includes(\"not enabled\") ||\n err.message.includes(\"not subscribed\")\n );\n}\n\nfunction computeMaturityLevel(\n enabledCount: number,\n): \"basic\" | \"intermediate\" | \"advanced\" | \"comprehensive\" {\n if (enabledCount >= 6) return \"comprehensive\";\n if (enabledCount >= 4) return \"advanced\";\n if (enabledCount >= 2) return \"intermediate\";\n return \"basic\";\n}\n\nexport class ServiceDetectionScanner implements Scanner {\n readonly moduleName = \"service_detection\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n const services: ServiceStatus[] = [];\n\n // --- CloudTrail ---\n try {\n const ct = createClient(CloudTrailClient, region, ctx.credentials);\n const resp = await ct.send(new DescribeTrailsCommand({}));\n const trails = resp.trailList ?? [];\n if (trails.length > 0) {\n services.push({\n name: \"CloudTrail\",\n enabled: true,\n details: `${trails.length} trail(s) configured`,\n });\n } else {\n services.push({\n name: \"CloudTrail\",\n enabled: false,\n recommendation: \"Create a multi-region trail for API logging\",\n });\n // CloudTrail is checked by service detection only for coverage assessment.\n }\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"CloudTrail: insufficient permissions to check status\");\n services.push({ name: \"CloudTrail\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"CloudTrail\",\n enabled: false,\n recommendation: \"Create a multi-region trail for API logging\",\n });\n // CloudTrail is checked by service detection only for coverage assessment\n } else {\n warnings.push(`CloudTrail detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"CloudTrail\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- Security Hub ---\n try {\n const sh = createClient(SecurityHubClient, region, ctx.credentials);\n await sh.send(new DescribeHubCommand({}));\n services.push({\n name: \"Security Hub\",\n enabled: true,\n details: \"Enabled with automated security checks\",\n });\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"Security Hub: insufficient permissions to check status\");\n services.push({ name: \"Security Hub\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"Security Hub\",\n enabled: false,\n recommendation: \"Enable Security Hub for 300+ automated security checks\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: \"AWS Security Hub is not enabled\",\n resourceType: \"AWS::SecurityHub::Hub\",\n resourceId: \"securityhub\",\n resourceArn: `arn:${partition}:securityhub:${region}:${accountId}:hub/default`,\n region,\n description:\n \"AWS Security Hub is not enabled in this region. Security Hub provides a comprehensive view of security alerts and compliance status.\",\n impact:\n \"Enables 300+ automated security checks across AWS services. Without it, security findings are fragmented across individual services.\",\n remediationSteps: [\n \"Open the AWS Security Hub console.\",\n \"Click 'Go to Security Hub' and enable it.\",\n \"Enable the AWS Foundational Security Best Practices standard.\",\n \"Security Hub offers a 30-day free trial.\",\n ],\n }),\n );\n } else {\n warnings.push(`Security Hub detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"Security Hub\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- GuardDuty ---\n try {\n const gd = createClient(GuardDutyClient, region, ctx.credentials);\n const resp = await gd.send(new ListDetectorsCommand({}));\n const detectors = resp.DetectorIds ?? [];\n if (detectors.length > 0) {\n services.push({\n name: \"GuardDuty\",\n enabled: true,\n details: `${detectors.length} detector(s) active`,\n });\n } else {\n services.push({\n name: \"GuardDuty\",\n enabled: false,\n recommendation: \"Enable GuardDuty for continuous threat detection\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: \"Amazon GuardDuty is not enabled\",\n resourceType: \"AWS::GuardDuty::Detector\",\n resourceId: \"guardduty\",\n resourceArn: `arn:${partition}:guardduty:${region}:${accountId}:detector/none`,\n region,\n description:\n \"Amazon GuardDuty is not enabled in this region. GuardDuty provides intelligent threat detection by analyzing CloudTrail, VPC Flow Logs, and DNS logs.\",\n impact:\n \"Provides continuous threat detection for account compromise, instance compromise, and malicious reconnaissance. Without it, many attack patterns go undetected.\",\n remediationSteps: [\n \"Open the Amazon GuardDuty console.\",\n \"Click 'Get Started' and enable GuardDuty.\",\n \"GuardDuty offers a 30-day free trial.\",\n \"Consider enabling S3 protection and EKS protection add-ons.\",\n ],\n }),\n );\n }\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"GuardDuty: insufficient permissions to check status\");\n services.push({ name: \"GuardDuty\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"GuardDuty\",\n enabled: false,\n recommendation: \"Enable GuardDuty for continuous threat detection\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: \"Amazon GuardDuty is not enabled\",\n resourceType: \"AWS::GuardDuty::Detector\",\n resourceId: \"guardduty\",\n resourceArn: `arn:${partition}:guardduty:${region}:${accountId}:detector/none`,\n region,\n description:\n \"Amazon GuardDuty is not enabled in this region. GuardDuty provides intelligent threat detection by analyzing CloudTrail, VPC Flow Logs, and DNS logs.\",\n impact:\n \"Provides continuous threat detection for account compromise, instance compromise, and malicious reconnaissance. Without it, many attack patterns go undetected.\",\n remediationSteps: [\n \"Open the Amazon GuardDuty console.\",\n \"Click 'Get Started' and enable GuardDuty.\",\n \"GuardDuty offers a 30-day free trial.\",\n \"Consider enabling S3 protection and EKS protection add-ons.\",\n ],\n }),\n );\n } else {\n warnings.push(`GuardDuty detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"GuardDuty\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- Inspector ---\n try {\n const insp = createClient(Inspector2Client, region, ctx.credentials);\n const resp = await insp.send(new BatchGetAccountStatusCommand({ accountIds: [accountId] }));\n const accounts = resp.accounts ?? [];\n const active = accounts.some(\n (a) =>\n a.state?.status === \"ENABLED\" ||\n a.state?.status === \"ENABLING\",\n );\n if (active) {\n services.push({\n name: \"Inspector\",\n enabled: true,\n details: \"Vulnerability scanning active\",\n });\n } else {\n services.push({\n name: \"Inspector\",\n enabled: false,\n recommendation: \"Enable Inspector to scan for software vulnerabilities\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: \"Amazon Inspector is not enabled\",\n resourceType: \"AWS::Inspector2::AccountStatus\",\n resourceId: \"inspector\",\n resourceArn: `arn:${partition}:inspector2:${region}:${accountId}:account`,\n region,\n description:\n \"Amazon Inspector is not enabled in this region. Inspector automatically discovers and scans EC2 instances, containers, and Lambda functions for software vulnerabilities.\",\n impact:\n \"Scans for software vulnerabilities in EC2 instances, container images, and Lambda functions. Without it, known CVEs may go undetected.\",\n remediationSteps: [\n \"Open the Amazon Inspector console.\",\n \"Click 'Get Started' and enable Inspector.\",\n \"Inspector offers a 15-day free trial.\",\n \"Enable scanning for EC2, ECR, and Lambda as appropriate.\",\n ],\n }),\n );\n }\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"Inspector: insufficient permissions to check status\");\n services.push({ name: \"Inspector\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"Inspector\",\n enabled: false,\n recommendation: \"Enable Inspector to scan for software vulnerabilities\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: \"Amazon Inspector is not enabled\",\n resourceType: \"AWS::Inspector2::AccountStatus\",\n resourceId: \"inspector\",\n resourceArn: `arn:${partition}:inspector2:${region}:${accountId}:account`,\n region,\n description:\n \"Amazon Inspector is not enabled in this region. Inspector automatically discovers and scans EC2 instances, containers, and Lambda functions for software vulnerabilities.\",\n impact:\n \"Scans for software vulnerabilities in EC2 instances, container images, and Lambda functions. Without it, known CVEs may go undetected.\",\n remediationSteps: [\n \"Open the Amazon Inspector console.\",\n \"Click 'Get Started' and enable Inspector.\",\n \"Inspector offers a 15-day free trial.\",\n \"Enable scanning for EC2, ECR, and Lambda as appropriate.\",\n ],\n }),\n );\n } else {\n warnings.push(`Inspector detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"Inspector\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- AWS Config ---\n try {\n const cfg = createClient(ConfigServiceClient, region, ctx.credentials);\n const resp = await cfg.send(new DescribeConfigurationRecordersCommand({}));\n const recorders = resp.ConfigurationRecorders ?? [];\n if (recorders.length > 0) {\n services.push({\n name: \"AWS Config\",\n enabled: true,\n details: `${recorders.length} recorder(s) configured`,\n });\n } else {\n services.push({\n name: \"AWS Config\",\n enabled: false,\n recommendation: \"Enable AWS Config to track configuration changes\",\n });\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: \"AWS Config is not enabled\",\n resourceType: \"AWS::Config::ConfigurationRecorder\",\n resourceId: \"config\",\n resourceArn: `arn:${partition}:config:${region}:${accountId}:configuration-recorder/none`,\n region,\n description:\n \"AWS Config is not enabled in this region. Config continuously records resource configurations and enables compliance auditing.\",\n impact:\n \"Tracks configuration changes and enables compliance rules. Without it, configuration drift and non-compliant resources go undetected.\",\n remediationSteps: [\n \"Open the AWS Config console.\",\n \"Click 'Get Started' and configure a recorder.\",\n \"Select the resource types to record.\",\n \"Configure an S3 bucket for configuration snapshots.\",\n ],\n }),\n );\n }\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"AWS Config: insufficient permissions to check status\");\n services.push({ name: \"AWS Config\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"AWS Config\",\n enabled: false,\n recommendation: \"Enable AWS Config to track configuration changes\",\n });\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: \"AWS Config is not enabled\",\n resourceType: \"AWS::Config::ConfigurationRecorder\",\n resourceId: \"config\",\n resourceArn: `arn:${partition}:config:${region}:${accountId}:configuration-recorder/none`,\n region,\n description:\n \"AWS Config is not enabled in this region. Config continuously records resource configurations and enables compliance auditing.\",\n impact:\n \"Tracks configuration changes and enables compliance rules. Without it, configuration drift and non-compliant resources go undetected.\",\n remediationSteps: [\n \"Open the AWS Config console.\",\n \"Click 'Get Started' and configure a recorder.\",\n \"Select the resource types to record.\",\n \"Configure an S3 bucket for configuration snapshots.\",\n ],\n }),\n );\n } else {\n warnings.push(`AWS Config detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"AWS Config\", enabled: null, details: \"Detection error\" });\n }\n }\n\n // --- Macie (not available in AWS China regions) ---\n if (region.startsWith(\"cn-\")) {\n services.push({ name: \"Macie\", enabled: null, details: \"Not available in China regions\" });\n warnings.push(\"Macie is not available in AWS China regions.\");\n } else {\n try {\n const mc = createClient(Macie2Client, region, ctx.credentials);\n await mc.send(new GetMacieSessionCommand({}));\n services.push({\n name: \"Macie\",\n enabled: true,\n details: \"Sensitive data detection active\",\n });\n } catch (err) {\n if (isAccessDenied(err)) {\n warnings.push(\"Macie: insufficient permissions to check status\");\n services.push({ name: \"Macie\", enabled: null, details: \"Access denied\" });\n } else if (isNotEnabled(err)) {\n services.push({\n name: \"Macie\",\n enabled: false,\n recommendation: \"Enable Macie to detect sensitive data in S3\",\n freeTrialAvailable: true,\n });\n findings.push(\n makeFinding({\n riskScore: 5.0,\n title: \"Amazon Macie is not enabled\",\n resourceType: \"AWS::Macie::Session\",\n resourceId: \"macie\",\n resourceArn: `arn:${partition}:macie2:${region}:${accountId}:session`,\n region,\n description:\n \"Amazon Macie is not enabled in this region. Macie uses machine learning to discover and protect sensitive data stored in S3.\",\n impact:\n \"Detects sensitive data (PII, credentials, financial data) in S3 buckets. Without it, sensitive data exposure may go unnoticed.\",\n remediationSteps: [\n \"Open the Amazon Macie console.\",\n \"Click 'Get Started' and enable Macie.\",\n \"Macie offers a 30-day free trial for sensitive data discovery.\",\n \"Configure automated sensitive data discovery jobs.\",\n ],\n }),\n );\n } else {\n warnings.push(`Macie detection failed: ${err instanceof Error ? err.message : String(err)}`);\n services.push({ name: \"Macie\", enabled: null, details: \"Detection error\" });\n }\n }\n }\n\n // Compute coverage and maturity (exclude unknown services from coverage denominator)\n const knownServices = services.filter((s) => s.enabled !== null);\n const enabledCount = services.filter((s) => s.enabled === true).length;\n const coveragePercent = knownServices.length > 0 ? Math.round((enabledCount / knownServices.length) * 100) : 0;\n const maturityLevel = computeMaturityLevel(enabledCount);\n\n const detectionResult: ServiceDetectionResult = {\n services,\n coveragePercent,\n maturityLevel,\n };\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: services.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n // Attach the structured detection result as a custom property via the findings metadata\n ...({ serviceDetection: detectionResult } as Record<string, unknown>),\n } as ScanResult & { serviceDetection: ServiceDetectionResult };\n }\n}\n","import { Severity, Priority } from \"../types.js\";\n\nexport function severityFromScore(score: number): Severity {\n if (score >= 9.0) return \"CRITICAL\";\n if (score >= 7.0) return \"HIGH\";\n if (score >= 4.0) return \"MEDIUM\";\n return \"LOW\";\n}\n\nexport function priorityFromSeverity(severity: Severity): Priority {\n switch (severity) {\n case \"CRITICAL\": return \"P0\";\n case \"HIGH\": return \"P1\";\n case \"MEDIUM\": return \"P2\";\n case \"LOW\": return \"P3\";\n }\n}\n","import {\n LambdaClient,\n ListFunctionsCommand,\n type FunctionConfiguration,\n} from \"@aws-sdk/client-lambda\";\nimport {\n EC2Client,\n DescribeInstancesCommand,\n DescribeInstanceAttributeCommand,\n type Instance,\n} from \"@aws-sdk/client-ec2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst SECRET_PATTERNS: Array<{ name: string; pattern: RegExp; matchType: \"value\" | \"name\" }> = [\n { name: \"AWS Access Key\", pattern: /AKIA[0-9A-Z]{16}/, matchType: \"value\" },\n { name: \"Private Key\", pattern: /-----BEGIN.*PRIVATE KEY-----/, matchType: \"value\" },\n { name: \"Password in env var\", pattern: /^(PASSWORD|PASSWD|DB_PASSWORD|SECRET|API_KEY|APIKEY|TOKEN|AUTH_TOKEN)$/i, matchType: \"name\" },\n];\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class SecretExposureScanner implements Scanner {\n readonly moduleName = \"secret_exposure\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n // --- Lambda functions ---\n try {\n const lambda = createClient(LambdaClient, region, ctx.credentials);\n const functions: FunctionConfiguration[] = [];\n let marker: string | undefined;\n do {\n const resp = await lambda.send(\n new ListFunctionsCommand({ Marker: marker }),\n );\n if (resp.Functions) functions.push(...resp.Functions);\n marker = resp.NextMarker;\n } while (marker);\n\n resourcesScanned += functions.length;\n\n for (const fn of functions) {\n const fnName = fn.FunctionName ?? \"unknown\";\n const fnArn =\n fn.FunctionArn ??\n `arn:${partition}:lambda:${region}:${accountId}:function:${fnName}`;\n const envVars = fn.Environment?.Variables ?? {};\n\n for (const [varName, varValue] of Object.entries(envVars)) {\n for (const sp of SECRET_PATTERNS) {\n if (sp.matchType === \"name\") {\n if (sp.pattern.test(varName)) {\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `Lambda ${fnName} has suspicious env var \"${varName}\"`,\n resourceType: \"AWS::Lambda::Function\",\n resourceId: fnName,\n resourceArn: fnArn,\n region,\n description: `Lambda function \"${fnName}\" has an environment variable named \"${varName}\" which may contain a secret.`,\n impact:\n \"Secrets in Lambda environment variables are visible to anyone with lambda:GetFunctionConfiguration permission and may leak through logs.\",\n remediationSteps: [\n \"Move the secret to AWS Secrets Manager or SSM Parameter Store (SecureString).\",\n \"Update the Lambda function to fetch the secret at runtime.\",\n \"Rotate the exposed credential immediately.\",\n ],\n }),\n );\n }\n } else {\n // match value\n if (sp.pattern.test(varValue)) {\n const riskScore = sp.name === \"AWS Access Key\" ? 9.5 : 9.0;\n findings.push(\n makeFinding({\n riskScore,\n title: `Lambda ${fnName} env var contains ${sp.name}`,\n resourceType: \"AWS::Lambda::Function\",\n resourceId: fnName,\n resourceArn: fnArn,\n region,\n description: `Lambda function \"${fnName}\" has an environment variable containing a ${sp.name} pattern.`,\n impact:\n \"Hard-coded credentials in Lambda environment variables can be extracted by any principal with read access to the function configuration.\",\n remediationSteps: [\n \"Remove the hard-coded credential from environment variables.\",\n \"Use AWS Secrets Manager or SSM Parameter Store (SecureString) instead.\",\n \"Rotate the exposed credential immediately.\",\n \"Review CloudTrail logs for unauthorized use of the credential.\",\n ],\n }),\n );\n }\n }\n }\n }\n }\n } catch (e: unknown) {\n warnings.push(`Lambda scan error: ${e instanceof Error ? e.message : String(e)}`);\n }\n\n // --- EC2 userData ---\n try {\n const ec2 = createClient(EC2Client, region, ctx.credentials);\n const instances: Instance[] = [];\n let nextToken: string | undefined;\n do {\n const resp = await ec2.send(\n new DescribeInstancesCommand({ NextToken: nextToken }),\n );\n for (const res of resp.Reservations ?? []) {\n if (res.Instances) instances.push(...res.Instances);\n }\n nextToken = resp.NextToken;\n } while (nextToken);\n\n resourcesScanned += instances.length;\n\n for (const inst of instances) {\n const instId = inst.InstanceId ?? \"unknown\";\n const instArn = `arn:${partition}:ec2:${region}:${accountId}:instance/${instId}`;\n\n let userData: string | undefined;\n try {\n const attrResp = await ec2.send(\n new DescribeInstanceAttributeCommand({\n InstanceId: instId,\n Attribute: \"userData\",\n }),\n );\n const raw = attrResp.UserData?.Value;\n if (raw) {\n userData = Buffer.from(raw, \"base64\").toString(\"utf-8\");\n }\n } catch (e: unknown) {\n warnings.push(`Could not read userData for ${instId}: ${e instanceof Error ? e.message : String(e)}`);\n continue;\n }\n\n if (!userData) continue;\n\n for (const sp of SECRET_PATTERNS) {\n if (sp.matchType === \"name\") continue; // name-matching doesn't apply to userData\n if (sp.pattern.test(userData)) {\n const riskScore = sp.name === \"AWS Access Key\" ? 9.5 : 8.0;\n findings.push(\n makeFinding({\n riskScore,\n title: `EC2 ${instId} userData contains ${sp.name}`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: instArn,\n region,\n description: `EC2 instance \"${instId}\" has user data containing a ${sp.name} pattern.`,\n impact:\n \"Instance user data is accessible to anyone with ec2:DescribeInstanceAttribute permission and from the instance metadata service.\",\n remediationSteps: [\n \"Remove the secret from instance user data.\",\n \"Use IAM instance profiles for AWS API access instead of embedding keys.\",\n \"Use Secrets Manager or SSM Parameter Store for other secrets.\",\n \"Rotate the exposed credential immediately.\",\n ],\n }),\n );\n }\n }\n }\n } catch (e: unknown) {\n warnings.push(`EC2 userData scan error: ${e instanceof Error ? e.message : String(e)}`);\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n ACMClient,\n ListCertificatesCommand,\n DescribeCertificateCommand,\n type CertificateSummary,\n} from \"@aws-sdk/client-acm\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class SslCertificateScanner implements Scanner {\n readonly moduleName = \"ssl_certificate\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n const client = createClient(ACMClient, region, ctx.credentials);\n\n // List all certificates\n const certs: CertificateSummary[] = [];\n let nextToken: string | undefined;\n do {\n const resp = await client.send(\n new ListCertificatesCommand({ NextToken: nextToken }),\n );\n if (resp.CertificateSummaryList) {\n certs.push(...resp.CertificateSummaryList);\n }\n nextToken = resp.NextToken;\n } while (nextToken);\n\n for (const cert of certs) {\n const certArn = cert.CertificateArn ?? \"unknown\";\n const domainName = cert.DomainName ?? \"unknown\";\n\n let detail;\n try {\n const descResp = await client.send(\n new DescribeCertificateCommand({ CertificateArn: certArn }),\n );\n detail = descResp.Certificate;\n } catch (e: unknown) {\n warnings.push(`Could not describe certificate ${certArn}: ${e instanceof Error ? e.message : String(e)}`);\n continue;\n }\n\n if (!detail) continue;\n\n const status = detail.Status ?? \"UNKNOWN\";\n const inUseBy = detail.InUseBy ?? [];\n const inUseStr = inUseBy.length > 0 ? ` In use by ${inUseBy.length} resource(s).` : \" Not currently in use.\";\n\n // Check for FAILED status\n if (status === \"FAILED\") {\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `Certificate for ${domainName} is in FAILED status`,\n resourceType: \"AWS::ACM::Certificate\",\n resourceId: domainName,\n resourceArn: certArn,\n region,\n description: `ACM certificate for \"${domainName}\" has status FAILED.${inUseStr}`,\n impact:\n \"The certificate failed validation and cannot be used for TLS termination. Services relying on it may lose HTTPS protection.\",\n remediationSteps: [\n \"Check the failure reason in the ACM console.\",\n \"Request a new certificate with correct domain validation.\",\n \"If using DNS validation, ensure the CNAME records are correctly configured.\",\n ],\n }),\n );\n continue;\n }\n\n // Check expiry (only for ISSUED certificates)\n if (status === \"ISSUED\" && detail.NotAfter) {\n const now = new Date();\n const expiryDate = new Date(detail.NotAfter);\n const daysUntilExpiry = Math.floor(\n (expiryDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24),\n );\n\n if (daysUntilExpiry < 0) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `Certificate for ${domainName} has expired`,\n resourceType: \"AWS::ACM::Certificate\",\n resourceId: domainName,\n resourceArn: certArn,\n region,\n description: `ACM certificate for \"${domainName}\" expired ${Math.abs(daysUntilExpiry)} days ago.${inUseStr}`,\n impact:\n \"Expired certificates cause TLS errors for end users. Browsers will display security warnings and block access.\",\n remediationSteps: [\n \"Renew or replace the certificate immediately.\",\n \"If using ACM-managed renewal, check why automatic renewal failed.\",\n \"Verify domain validation records are still in place.\",\n ],\n }),\n );\n } else if (daysUntilExpiry < 30) {\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: `Certificate for ${domainName} expires in ${daysUntilExpiry} days`,\n resourceType: \"AWS::ACM::Certificate\",\n resourceId: domainName,\n resourceArn: certArn,\n region,\n description: `ACM certificate for \"${domainName}\" expires in ${daysUntilExpiry} days (${expiryDate.toISOString().split(\"T\")[0]}).${inUseStr}`,\n impact:\n \"Certificate will expire soon. If not renewed, services will experience TLS errors.\",\n remediationSteps: [\n \"Verify ACM automatic renewal is working (check renewal status).\",\n \"If imported certificate, prepare and import the renewed certificate.\",\n \"Set up CloudWatch alarms for certificate expiry.\",\n ],\n }),\n );\n } else if (daysUntilExpiry < 90) {\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `Certificate for ${domainName} expires in ${daysUntilExpiry} days`,\n resourceType: \"AWS::ACM::Certificate\",\n resourceId: domainName,\n resourceArn: certArn,\n region,\n description: `ACM certificate for \"${domainName}\" expires in ${daysUntilExpiry} days (${expiryDate.toISOString().split(\"T\")[0]}).${inUseStr}`,\n impact:\n \"Certificate is approaching expiry. Plan renewal to avoid service disruption.\",\n remediationSteps: [\n \"Verify ACM automatic renewal is configured and working.\",\n \"If imported certificate, begin the renewal process.\",\n \"Consider setting up monitoring for certificate expiry dates.\",\n ],\n }),\n );\n }\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: certs.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n Route53Client,\n ListHostedZonesCommand,\n ListResourceRecordSetsCommand,\n type HostedZone,\n type ResourceRecordSet,\n} from \"@aws-sdk/client-route-53\";\nimport {\n S3Client,\n HeadBucketCommand,\n} from \"@aws-sdk/client-s3\";\nimport { promises as dns } from \"dns\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction extractS3BucketName(target: string): string | null {\n // Matches: bucket.s3.amazonaws.com, bucket.s3-website-us-east-1.amazonaws.com,\n // bucket.s3.cn-north-1.amazonaws.com.cn, etc.\n const s3Pattern = /^([^.]+)\\.s3[.-]/;\n const m = target.match(s3Pattern);\n return m ? m[1] : null;\n}\n\nfunction classifyTarget(target: string): \"s3\" | \"elb\" | \"cloudfront\" | null {\n if (/\\.s3[.-](.*\\.)?amazonaws\\.com(\\.cn)?\\.?$/.test(target)) return \"s3\";\n if (/\\.elb\\.amazonaws\\.com(\\.cn)?\\.?$/.test(target)) return \"elb\";\n if (/\\.cloudfront\\.net\\.?$/.test(target)) return \"cloudfront\";\n return null;\n}\n\nasync function dnsResolves(hostname: string): Promise<boolean> {\n try {\n // Remove trailing dot for DNS lookup\n const h = hostname.endsWith(\".\") ? hostname.slice(0, -1) : hostname;\n await dns.resolve(h);\n return true;\n } catch {\n return false;\n }\n}\n\nexport class DnsDanglingScanner implements Scanner {\n readonly moduleName = \"dns_dangling\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const route53 = createClient(Route53Client, region, ctx.credentials);\n\n // List hosted zones\n const zones: HostedZone[] = [];\n let marker: string | undefined;\n do {\n const resp = await route53.send(\n new ListHostedZonesCommand({ Marker: marker }),\n );\n if (resp.HostedZones) zones.push(...resp.HostedZones);\n marker = resp.IsTruncated ? resp.NextMarker : undefined;\n } while (marker);\n\n for (const zone of zones) {\n const zoneId = zone.Id ?? \"unknown\";\n const zoneName = zone.Name ?? \"unknown\";\n const shortZoneId = zoneId.replace(\"/hostedzone/\", \"\");\n\n // List record sets\n const records: ResourceRecordSet[] = [];\n let nextName: string | undefined;\n let nextType: string | undefined;\n do {\n const resp = await route53.send(\n new ListResourceRecordSetsCommand({\n HostedZoneId: shortZoneId,\n StartRecordName: nextName,\n StartRecordType: nextType as ResourceRecordSet[\"Type\"],\n }),\n );\n if (resp.ResourceRecordSets) records.push(...resp.ResourceRecordSets);\n if (resp.IsTruncated) {\n nextName = resp.NextRecordName;\n nextType = resp.NextRecordType;\n } else {\n nextName = undefined;\n nextType = undefined;\n }\n } while (nextName);\n\n // Filter CNAME records\n const cnameRecords = records.filter(\n (r) => r.Type === \"CNAME\" && r.ResourceRecords && r.ResourceRecords.length > 0,\n );\n\n resourcesScanned += cnameRecords.length;\n\n for (const record of cnameRecords) {\n const recordName = record.Name ?? \"unknown\";\n const target = record.ResourceRecords![0].Value ?? \"\";\n const recordArn = `arn:${partition}:route53:::hostedzone/${shortZoneId}`;\n const targetType = classifyTarget(target);\n\n if (targetType === \"s3\") {\n // Check if S3 bucket exists\n const bucketName = extractS3BucketName(target);\n if (bucketName) {\n let bucketExists = false;\n try {\n const s3 = createClient(S3Client, region, ctx.credentials);\n await s3.send(new HeadBucketCommand({ Bucket: bucketName }));\n bucketExists = true;\n } catch (e: unknown) {\n const errName = (e as { name?: string }).name ?? \"\";\n // 404 / NoSuchBucket = doesn't exist; 403 = exists but no access\n if (errName === \"Forbidden\" || errName === \"AccessDenied\" || errName === \"403\") {\n bucketExists = true;\n }\n }\n\n if (!bucketExists) {\n findings.push(\n makeFinding({\n riskScore: 9.5,\n title: `CNAME ${recordName} points to non-existent S3 bucket \"${bucketName}\"`,\n resourceType: \"AWS::Route53::RecordSet\",\n resourceId: recordName,\n resourceArn: recordArn,\n region,\n description: `DNS record \"${recordName}\" in zone \"${zoneName}\" has a CNAME to S3 bucket \"${bucketName}\" which does not exist. An attacker can claim this bucket for subdomain takeover.`,\n impact:\n \"Critical subdomain takeover vulnerability. An attacker can create the S3 bucket and serve arbitrary content on your domain, enabling phishing, cookie theft, and reputation damage.\",\n remediationSteps: [\n \"Immediately create the S3 bucket to prevent takeover.\",\n \"Remove the dangling DNS record if the bucket is no longer needed.\",\n \"Audit all CNAME records pointing to S3 buckets.\",\n ],\n }),\n );\n }\n }\n } else if (targetType === \"elb\") {\n const resolves = await dnsResolves(target);\n if (!resolves) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `CNAME ${recordName} points to non-resolving ELB`,\n resourceType: \"AWS::Route53::RecordSet\",\n resourceId: recordName,\n resourceArn: recordArn,\n region,\n description: `DNS record \"${recordName}\" in zone \"${zoneName}\" has a CNAME to ELB \"${target}\" which does not resolve. The load balancer may have been deleted.`,\n impact:\n \"Potential subdomain takeover if the ELB DNS name can be re-registered. Dangling DNS records indicate resource lifecycle gaps.\",\n remediationSteps: [\n \"Remove the dangling DNS record.\",\n \"If the ELB was deleted, clean up all associated DNS records.\",\n \"Implement automated DNS record cleanup when decommissioning resources.\",\n ],\n }),\n );\n }\n } else if (targetType === \"cloudfront\") {\n const resolves = await dnsResolves(target);\n if (!resolves) {\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `CNAME ${recordName} points to non-resolving CloudFront distribution`,\n resourceType: \"AWS::Route53::RecordSet\",\n resourceId: recordName,\n resourceArn: recordArn,\n region,\n description: `DNS record \"${recordName}\" in zone \"${zoneName}\" has a CNAME to CloudFront \"${target}\" which does not resolve. The distribution may have been deleted.`,\n impact:\n \"Potential subdomain takeover via CloudFront. An attacker may create a distribution with this alternate domain name.\",\n remediationSteps: [\n \"Remove the dangling DNS record.\",\n \"If the CloudFront distribution was deleted, clean up associated DNS records.\",\n \"Use CloudFront Origin Access Identity to limit exposure.\",\n ],\n }),\n );\n }\n } else if (targetType === null) {\n // Generic CNAME — just check if it resolves\n const resolves = await dnsResolves(target);\n if (!resolves) {\n findings.push(\n makeFinding({\n riskScore: 5.0,\n title: `CNAME ${recordName} target does not resolve`,\n resourceType: \"AWS::Route53::RecordSet\",\n resourceId: recordName,\n resourceArn: recordArn,\n region,\n description: `DNS record \"${recordName}\" in zone \"${zoneName}\" has a CNAME to \"${target}\" which does not resolve.`,\n impact:\n \"Orphaned DNS record pointing to a non-existent target. May indicate incomplete resource cleanup.\",\n remediationSteps: [\n \"Verify the target resource still exists.\",\n \"Remove the DNS record if it is no longer needed.\",\n \"Implement DNS record lifecycle management.\",\n ],\n }),\n );\n }\n }\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n EC2Client,\n DescribeInstancesCommand,\n DescribeSecurityGroupsCommand,\n DescribeNetworkAclsCommand,\n DescribeAddressesCommand,\n type Instance,\n type SecurityGroup,\n type NetworkAcl,\n type IpPermission,\n type NetworkAclEntry,\n} from \"@aws-sdk/client-ec2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst HIGH_RISK_PORTS: Record<number, string> = {\n 22: \"SSH\",\n 3389: \"RDP\",\n 3306: \"MySQL\",\n 5432: \"PostgreSQL\",\n 1433: \"MSSQL\",\n 27017: \"MongoDB\",\n 6379: \"Redis\",\n 9200: \"Elasticsearch\",\n 11211: \"Memcached\",\n};\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction sgAllowsPort(sgs: SecurityGroup[], port: number): boolean {\n for (const sg of sgs) {\n for (const perm of sg.IpPermissions ?? []) {\n if (permissionAllowsWorldPort(perm, port)) return true;\n }\n }\n return false;\n}\n\nfunction sgAllowsAllPorts(sgs: SecurityGroup[]): boolean {\n for (const sg of sgs) {\n for (const perm of sg.IpPermissions ?? []) {\n if (isAllPorts(perm) && hasWorldCidr(perm)) return true;\n }\n }\n return false;\n}\n\nfunction permissionAllowsWorldPort(perm: IpPermission, port: number): boolean {\n if (!hasWorldCidr(perm)) return false;\n const from = perm.FromPort ?? -1;\n const to = perm.ToPort ?? -1;\n if (from === -1 && to === -1) return true; // all traffic\n return port >= from && port <= to;\n}\n\nfunction hasWorldCidr(perm: IpPermission): boolean {\n const hasIpv4 = (perm.IpRanges ?? []).some((r) => r.CidrIp === \"0.0.0.0/0\");\n const hasIpv6 = (perm.Ipv6Ranges ?? []).some((r) => r.CidrIpv6 === \"::/0\");\n return hasIpv4 || hasIpv6;\n}\n\nfunction isAllPorts(perm: IpPermission): boolean {\n const from = perm.FromPort ?? -1;\n const to = perm.ToPort ?? -1;\n return (from === -1 && to === -1) || (from === 0 && to === 65535);\n}\n\nfunction naclAllowsPort(nacl: NetworkAcl, port: number): boolean {\n // NACL rules are evaluated in order (lowest rule number first)\n // We check inbound rules only (Egress === false)\n const inboundRules = (nacl.Entries ?? [])\n .filter((e) => e.Egress === false)\n .sort((a, b) => (a.RuleNumber ?? 0) - (b.RuleNumber ?? 0));\n\n for (const rule of inboundRules) {\n if (naclRuleMatchesPort(rule, port) && naclRuleMatchesWorldCidr(rule)) {\n // RuleAction \"allow\" or \"deny\"\n return rule.RuleAction === \"allow\";\n }\n }\n // Default: deny\n return false;\n}\n\nfunction naclRuleMatchesPort(rule: NetworkAclEntry, port: number): boolean {\n // Protocol -1 means all traffic\n if (rule.Protocol === \"-1\") return true;\n // Protocol 6 = TCP, 17 = UDP\n if (rule.Protocol !== \"6\" && rule.Protocol !== \"17\") return false;\n const from = rule.PortRange?.From ?? 0;\n const to = rule.PortRange?.To ?? 65535;\n return port >= from && port <= to;\n}\n\nfunction naclRuleMatchesWorldCidr(rule: NetworkAclEntry): boolean {\n return rule.CidrBlock === \"0.0.0.0/0\" || rule.Ipv6CidrBlock === \"::/0\";\n}\n\nexport class NetworkReachabilityScanner implements Scanner {\n readonly moduleName = \"network_reachability\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n const client = createClient(EC2Client, region, ctx.credentials);\n\n // Get EIPs for lookup\n const eipMap = new Map<string, string>(); // instanceId -> EIP\n try {\n const eipResp = await client.send(new DescribeAddressesCommand({}));\n for (const addr of eipResp.Addresses ?? []) {\n if (addr.InstanceId && addr.PublicIp) {\n eipMap.set(addr.InstanceId, addr.PublicIp);\n }\n }\n } catch (e: unknown) {\n warnings.push(`Could not list Elastic IPs: ${e instanceof Error ? e.message : String(e)}`);\n }\n\n // Get instances\n const instances: Instance[] = [];\n let nextToken: string | undefined;\n do {\n const resp = await client.send(\n new DescribeInstancesCommand({ NextToken: nextToken }),\n );\n for (const res of resp.Reservations ?? []) {\n if (res.Instances) instances.push(...res.Instances);\n }\n nextToken = resp.NextToken;\n } while (nextToken);\n\n // Filter to instances with public IPs or EIPs\n const publicInstances = instances.filter((inst) => {\n const instId = inst.InstanceId ?? \"\";\n return inst.PublicIpAddress || eipMap.has(instId);\n });\n\n // Collect all SG IDs and subnet IDs\n const sgIds = new Set<string>();\n const subnetIds = new Set<string>();\n for (const inst of publicInstances) {\n for (const sg of inst.SecurityGroups ?? []) {\n if (sg.GroupId) sgIds.add(sg.GroupId);\n }\n if (inst.SubnetId) subnetIds.add(inst.SubnetId);\n }\n\n // Fetch all referenced SGs\n const sgMap = new Map<string, SecurityGroup>();\n if (sgIds.size > 0) {\n const sgResp = await client.send(\n new DescribeSecurityGroupsCommand({\n GroupIds: [...sgIds],\n }),\n );\n for (const sg of sgResp.SecurityGroups ?? []) {\n if (sg.GroupId) sgMap.set(sg.GroupId, sg);\n }\n }\n\n // Fetch NACLs for referenced subnets\n const subnetNaclMap = new Map<string, NetworkAcl>(); // subnetId -> NACL\n if (subnetIds.size > 0) {\n let naclToken: string | undefined;\n const allNacls: NetworkAcl[] = [];\n do {\n const naclResp = await client.send(\n new DescribeNetworkAclsCommand({\n Filters: [{ Name: \"association.subnet-id\", Values: [...subnetIds] }],\n NextToken: naclToken,\n }),\n );\n if (naclResp.NetworkAcls) allNacls.push(...naclResp.NetworkAcls);\n naclToken = naclResp.NextToken;\n } while (naclToken);\n\n for (const nacl of allNacls) {\n for (const assoc of nacl.Associations ?? []) {\n if (assoc.SubnetId) {\n subnetNaclMap.set(assoc.SubnetId, nacl);\n }\n }\n }\n }\n\n // Analyze each public instance\n for (const inst of publicInstances) {\n const instId = inst.InstanceId ?? \"unknown\";\n const instArn = `arn:${partition}:ec2:${region}:${accountId}:instance/${instId}`;\n const publicIp = inst.PublicIpAddress ?? eipMap.get(instId) ?? \"unknown\";\n const subnetId = inst.SubnetId ?? \"\";\n\n // Get this instance's SGs\n const instSgs: SecurityGroup[] = [];\n for (const sg of inst.SecurityGroups ?? []) {\n if (sg.GroupId) {\n const fullSg = sgMap.get(sg.GroupId);\n if (fullSg) instSgs.push(fullSg);\n }\n }\n\n const nacl = subnetNaclMap.get(subnetId);\n\n // Check each high-risk port\n for (const [portStr, portName] of Object.entries(HIGH_RISK_PORTS)) {\n const port = Number(portStr);\n const sgAllows = sgAllowsPort(instSgs, port);\n const naclAllows = nacl ? naclAllowsPort(nacl, port) : true; // if no NACL info, assume allow\n\n if (sgAllows && naclAllows) {\n findings.push(\n makeFinding({\n riskScore: 9.5,\n title: `EC2 ${instId} (${publicIp}): ${portName} (${port}) reachable from internet`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: instArn,\n region,\n description: `EC2 instance \"${instId}\" has public IP ${publicIp} and both its security group(s) and subnet NACL allow inbound ${portName} (port ${port}) from the internet.`,\n impact:\n `${portName} is directly reachable from the internet, enabling brute-force, exploitation, or unauthorized access.`,\n remediationSteps: [\n `Restrict security group inbound rules for port ${port} to specific IPs.`,\n \"Use Systems Manager Session Manager or a bastion host instead of direct access.\",\n \"Add NACL deny rules for high-risk ports as an additional layer.\",\n \"Enable VPC Flow Logs to monitor connection attempts.\",\n ],\n }),\n );\n } else if (sgAllows && !naclAllows) {\n findings.push(\n makeFinding({\n riskScore: 2.0,\n title: `EC2 ${instId}: ${portName} (${port}) allowed by SG but blocked by NACL`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: instArn,\n region,\n description: `EC2 instance \"${instId}\" (${publicIp}) has security group rules allowing ${portName} (port ${port}) from the internet, but the subnet NACL blocks it.`,\n impact:\n \"Currently protected by NACL, but the SG is overly permissive. NACL changes could expose the port.\",\n remediationSteps: [\n `Tighten the security group rules for port ${port} to match the intended access.`,\n \"Do not rely solely on NACLs for access control.\",\n ],\n }),\n );\n }\n }\n\n // Check for all-ports open via SG + NACL\n if (sgAllowsAllPorts(instSgs)) {\n // Check if NACL is also wide open (allows common ports)\n const naclOpen = nacl ? naclAllowsPort(nacl, 80) : true; // proxy check with port 80\n if (naclOpen) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `EC2 ${instId} (${publicIp}): all ports reachable from internet`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: instArn,\n region,\n description: `EC2 instance \"${instId}\" has public IP ${publicIp} and its security group allows all ports from the internet with no NACL restriction.`,\n impact:\n \"All services on this instance are exposed to the internet, creating a large attack surface.\",\n remediationSteps: [\n \"Replace the all-ports SG rule with specific port rules.\",\n \"Implement NACL rules to restrict inbound traffic as defense in depth.\",\n \"Audit all services running on the instance.\",\n ],\n }),\n );\n }\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: publicInstances.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n IAMClient,\n ListUsersCommand,\n ListAttachedUserPoliciesCommand,\n GetPolicyCommand,\n GetPolicyVersionCommand,\n ListUserPoliciesCommand,\n GetUserPolicyCommand,\n type User,\n} from \"@aws-sdk/client-iam\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient, getIamRegion } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\ninterface PolicyStatement {\n Effect?: string;\n Action?: string | string[];\n Resource?: string | string[];\n}\n\nfunction extractActions(doc: unknown): string[] {\n const actions: string[] = [];\n if (!doc || typeof doc !== \"object\") return actions;\n const policy = doc as { Statement?: PolicyStatement | PolicyStatement[] };\n const stmts = Array.isArray(policy.Statement)\n ? policy.Statement\n : policy.Statement\n ? [policy.Statement]\n : [];\n\n for (const stmt of stmts) {\n if (stmt.Effect !== \"Allow\") continue;\n const acts = Array.isArray(stmt.Action)\n ? stmt.Action\n : stmt.Action\n ? [stmt.Action]\n : [];\n actions.push(...acts);\n }\n return actions.map((a) => a.toLowerCase());\n}\n\nfunction hasAction(actions: string[], pattern: string): boolean {\n const pat = pattern.toLowerCase();\n return actions.some((a) => {\n if (a === \"*\") return true;\n if (a === pat) return true;\n // Wildcard match: \"iam:*\" matches \"iam:createrole\"\n if (a.endsWith(\"*\")) {\n const prefix = a.slice(0, -1);\n if (pat.startsWith(prefix)) return true;\n }\n return false;\n });\n}\n\nexport class IamPrivilegeEscalationScanner implements Scanner {\n readonly moduleName = \"iam_privilege_escalation\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n const iamRegion = getIamRegion(region);\n\n warnings.push(\n \"Note: This scanner currently checks IAM users only. Role and group policy analysis will be added in a future version.\",\n );\n\n try {\n const client = createClient(IAMClient, iamRegion, ctx.credentials);\n\n // List all IAM users\n const users: User[] = [];\n let marker: string | undefined;\n do {\n const resp = await client.send(\n new ListUsersCommand({ Marker: marker }),\n );\n if (resp.Users) users.push(...resp.Users);\n marker = resp.IsTruncated ? resp.Marker : undefined;\n } while (marker);\n\n for (const user of users) {\n const userName = user.UserName ?? \"unknown\";\n const userArn =\n user.Arn ??\n `arn:${partition}:iam::${accountId}:user/${userName}`;\n\n // Collect all allowed actions from both managed and inline policies\n const allActions: string[] = [];\n\n // 1. Check attached (managed) policies\n try {\n const attachedResp = await client.send(\n new ListAttachedUserPoliciesCommand({ UserName: userName }),\n );\n for (const policy of attachedResp.AttachedPolicies ?? []) {\n const policyArn = policy.PolicyArn;\n if (!policyArn) continue;\n try {\n const policyResp = await client.send(\n new GetPolicyCommand({ PolicyArn: policyArn }),\n );\n const versionId =\n policyResp.Policy?.DefaultVersionId ?? \"v1\";\n const versionResp = await client.send(\n new GetPolicyVersionCommand({\n PolicyArn: policyArn,\n VersionId: versionId,\n }),\n );\n const doc = versionResp.PolicyVersion?.Document;\n if (doc) {\n const parsed = JSON.parse(decodeURIComponent(doc));\n allActions.push(...extractActions(parsed));\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(\n `Could not read policy ${policyArn} for user ${userName}: ${msg}`,\n );\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(\n `Could not list attached policies for user ${userName}: ${msg}`,\n );\n }\n\n // 2. Check inline policies\n try {\n const inlineResp = await client.send(\n new ListUserPoliciesCommand({ UserName: userName }),\n );\n for (const policyName of inlineResp.PolicyNames ?? []) {\n try {\n const inlinePolicyResp = await client.send(\n new GetUserPolicyCommand({\n UserName: userName,\n PolicyName: policyName,\n }),\n );\n const doc = inlinePolicyResp.PolicyDocument;\n if (doc) {\n const parsed = JSON.parse(decodeURIComponent(doc));\n allActions.push(...extractActions(parsed));\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(\n `Could not read inline policy ${policyName} for user ${userName}: ${msg}`,\n );\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(\n `Could not list inline policies for user ${userName}: ${msg}`,\n );\n }\n\n if (allActions.length === 0) continue;\n\n // Check for wildcard iam:* or full wildcard *\n if (\n hasAction(allActions, \"iam:*\") ||\n allActions.includes(\"*\")\n ) {\n findings.push(\n makeFinding({\n riskScore: 9.0,\n title: `IAM user ${userName} has iam:* wildcard permissions`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has wildcard IAM permissions (iam:* or *), granting full control over identity and access management.`,\n impact:\n \"The user can create, modify, or delete any IAM resource including creating admin users, modifying policies, and escalating privileges without restriction.\",\n remediationSteps: [\n `Remove wildcard IAM permissions from user \"${userName}\".`,\n \"Replace with specific, least-privilege IAM permissions.\",\n \"Use IAM Access Analyzer to identify actually used permissions.\",\n ],\n }),\n );\n // Skip further checks — wildcard already covers everything\n continue;\n }\n\n // Self-grant admin: iam:PutUserPolicy or iam:AttachUserPolicy\n if (\n hasAction(allActions, \"iam:putuserpolicy\") ||\n hasAction(allActions, \"iam:attachuserpolicy\")\n ) {\n findings.push(\n makeFinding({\n riskScore: 9.5,\n title: `IAM user ${userName} can self-grant admin via policy attachment`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has iam:PutUserPolicy or iam:AttachUserPolicy, allowing them to attach AdministratorAccess or any policy to themselves.`,\n impact:\n \"The user can escalate to full administrator access by attaching an admin policy to their own account.\",\n remediationSteps: [\n `Remove iam:PutUserPolicy and iam:AttachUserPolicy from user \"${userName}\".`,\n \"Use permission boundaries to restrict policy attachment scope.\",\n \"Require MFA for sensitive IAM operations via condition keys.\",\n ],\n }),\n );\n }\n\n // Create admin roles: iam:CreateRole + iam:AttachRolePolicy\n if (\n hasAction(allActions, \"iam:createrole\") &&\n hasAction(allActions, \"iam:attachrolepolicy\")\n ) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `IAM user ${userName} can create admin roles`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has both iam:CreateRole and iam:AttachRolePolicy, allowing creation of new roles with admin policies.`,\n impact:\n \"The user can create a new IAM role with AdministratorAccess and assume it to gain full account access.\",\n remediationSteps: [\n `Restrict iam:CreateRole and iam:AttachRolePolicy with resource conditions for user \"${userName}\".`,\n \"Use permission boundaries on all created roles.\",\n \"Monitor IAM role creation via CloudTrail alerts.\",\n ],\n }),\n );\n }\n\n // PassRole + Lambda escalation: iam:PassRole + lambda:CreateFunction\n if (\n hasAction(allActions, \"iam:passrole\") &&\n hasAction(allActions, \"lambda:createfunction\")\n ) {\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `IAM user ${userName} can escalate via Lambda role passing`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has iam:PassRole and lambda:CreateFunction, allowing them to create a Lambda function with an admin role.`,\n impact:\n \"The user can pass a high-privilege role to a Lambda function and invoke it to execute actions beyond their own permissions.\",\n remediationSteps: [\n `Restrict iam:PassRole to specific role ARNs for user \"${userName}\".`,\n \"Use condition keys to limit which roles can be passed to Lambda.\",\n \"Implement SCP guardrails for privilege escalation paths.\",\n ],\n }),\n );\n }\n\n // Create access keys for other users: iam:CreateAccessKey\n if (hasAction(allActions, \"iam:createaccesskey\")) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `IAM user ${userName} can create access keys for other users`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has iam:CreateAccessKey, which allows creating access keys for any IAM user unless restricted by resource conditions.`,\n impact:\n \"The user can impersonate other IAM users (including admins) by generating access keys on their behalf.\",\n remediationSteps: [\n `Restrict iam:CreateAccessKey to the user's own ARN using a resource condition.`,\n \"Implement SCP to prevent cross-user key creation.\",\n \"Monitor CreateAccessKey events in CloudTrail.\",\n ],\n }),\n );\n }\n\n // STS AssumeRole on admin roles\n if (hasAction(allActions, \"sts:assumerole\")) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `IAM user ${userName} can assume roles (potential admin escalation)`,\n resourceType: \"AWS::IAM::User\",\n resourceId: userName,\n resourceArn: userArn,\n region: \"global\",\n description: `User \"${userName}\" has sts:AssumeRole, which may allow assuming high-privilege or admin roles if not restricted by resource ARN.`,\n impact:\n \"The user can escalate privileges by assuming roles with higher permissions than their own.\",\n remediationSteps: [\n `Restrict sts:AssumeRole to specific role ARNs for user \"${userName}\".`,\n \"Require MFA for assuming sensitive roles via role trust policy conditions.\",\n \"Audit which roles this user can assume and their permission levels.\",\n ],\n }),\n );\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: users.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n S3Client,\n ListBucketsCommand,\n GetPublicAccessBlockCommand,\n GetBucketAclCommand,\n GetBucketPolicyStatusCommand,\n GetBucketLocationCommand,\n} from \"@aws-sdk/client-s3\";\nimport {\n RDSClient,\n DescribeDBInstancesCommand,\n type DBInstance,\n} from \"@aws-sdk/client-rds\";\nimport dns from \"node:dns\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction s3Endpoint(bucket: string, region: string): string {\n const suffix = region.startsWith(\"cn-\")\n ? \"amazonaws.com.cn\"\n : \"amazonaws.com\";\n return `https://${bucket}.s3.${region}.${suffix}/`;\n}\n\nasync function getBucketRegion(\n client: S3Client,\n bucketName: string,\n defaultRegion: string,\n warnings: string[],\n): Promise<string> {\n try {\n const resp = await client.send(\n new GetBucketLocationCommand({ Bucket: bucketName }),\n );\n const loc = String(resp.LocationConstraint ?? \"\") || \"us-east-1\";\n return loc;\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Failed to detect region for bucket ${bucketName}, using ${defaultRegion}: ${msg}`);\n return defaultRegion;\n }\n}\n\nasync function isBucketMarkedPublic(\n client: S3Client,\n bucketName: string,\n warnings: string[],\n): Promise<boolean | \"skip\"> {\n // Check if Block Public Access is off AND (public ACL or public policy)\n let bpaBlocks = false;\n try {\n const bpa = await client.send(\n new GetPublicAccessBlockCommand({ Bucket: bucketName }),\n );\n const cfg = bpa.PublicAccessBlockConfiguration;\n bpaBlocks = !!(\n cfg?.BlockPublicAcls &&\n cfg?.IgnorePublicAcls &&\n cfg?.BlockPublicPolicy &&\n cfg?.RestrictPublicBuckets\n );\n } catch (e: unknown) {\n if (\n e instanceof Error &&\n e.name === \"NoSuchPublicAccessBlockConfiguration\"\n ) {\n bpaBlocks = false;\n } else {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Could not check public access for bucket ${bucketName}: ${msg}`);\n return \"skip\";\n }\n }\n\n if (bpaBlocks) return false;\n\n // Check ACL for public grants\n try {\n const acl = await client.send(\n new GetBucketAclCommand({ Bucket: bucketName }),\n );\n for (const grant of acl.Grants ?? []) {\n const uri = grant.Grantee?.URI ?? \"\";\n if (uri.includes(\"AllUsers\") || uri.includes(\"AuthenticatedUsers\")) {\n return true;\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Could not check ACL for bucket ${bucketName}: ${msg}`);\n }\n\n // Check bucket policy status\n try {\n const policyStatus = await client.send(\n new GetBucketPolicyStatusCommand({ Bucket: bucketName }),\n );\n if (policyStatus.PolicyStatus?.IsPublic) return true;\n } catch (e: unknown) {\n // NoSuchBucketPolicy is expected for buckets without policies\n if (e instanceof Error && !e.name.includes(\"NoSuchBucketPolicy\")) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Could not check policy status for bucket ${bucketName}: ${msg}`);\n }\n }\n\n return false;\n}\n\nfunction isPrivateIp(ip: string): boolean {\n if (ip.startsWith(\"10.\")) return true;\n if (ip.startsWith(\"192.168.\")) return true;\n if (ip.startsWith(\"172.\")) {\n const second = parseInt(ip.split(\".\")[1], 10);\n return second >= 16 && second <= 31;\n }\n if (ip.startsWith(\"127.\")) return true;\n return false;\n}\n\nexport class PublicAccessVerifyScanner implements Scanner {\n readonly moduleName = \"public_access_verify\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n // --- S3 public access verification ---\n try {\n const s3Client = createClient(S3Client, region, ctx.credentials);\n const listResp = await s3Client.send(new ListBucketsCommand({}));\n const buckets = listResp.Buckets ?? [];\n\n for (const bucket of buckets) {\n const name = bucket.Name ?? \"unknown\";\n const arn = `arn:${partition}:s3:::${name}`;\n\n const bucketRegion = await getBucketRegion(s3Client, name, region, warnings);\n const bucketClient =\n bucketRegion === region\n ? s3Client\n : createClient(S3Client, bucketRegion, ctx.credentials);\n\n const markedPublic = await isBucketMarkedPublic(bucketClient, name, warnings);\n if (markedPublic === \"skip\" || !markedPublic) continue;\n\n resourcesScanned++;\n const url = s3Endpoint(name, bucketRegion);\n\n try {\n const resp = await fetch(url, {\n method: \"HEAD\",\n signal: AbortSignal.timeout(5000),\n });\n\n if (resp.ok || resp.status === 200) {\n findings.push(\n makeFinding({\n riskScore: 9.5,\n title: `S3 bucket ${name} is publicly readable (verified)`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region: bucketRegion,\n description: `HTTP HEAD to ${url} returned status ${resp.status}. The bucket is confirmed publicly accessible from the internet.`,\n impact:\n \"Anyone on the internet can read objects from this bucket, potentially exposing sensitive data.\",\n remediationSteps: [\n \"Enable Block Public Access on the bucket immediately.\",\n \"Review and remove public ACL grants and public bucket policies.\",\n \"Audit bucket contents for sensitive data exposure.\",\n ],\n }),\n );\n } else if (resp.status === 403) {\n findings.push(\n makeFinding({\n riskScore: 2.0,\n title: `S3 bucket ${name} is marked public but returns 403 (blocked)`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region: bucketRegion,\n description: `Bucket \"${name}\" has public ACL/policy configuration but HTTP access returns 403 Forbidden, likely blocked by other controls.`,\n impact:\n \"Currently not accessible, but the public configuration is a risk if blocking controls are removed.\",\n remediationSteps: [\n \"Clean up the public ACL or policy to match the intended access model.\",\n \"Enable Block Public Access to formalize the restriction.\",\n ],\n }),\n );\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`HTTP check for bucket ${name} failed: ${msg}`);\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`S3 public access verification failed: ${msg}`);\n }\n\n // --- RDS public DNS verification ---\n try {\n const rdsClient = createClient(RDSClient, region, ctx.credentials);\n const instances: DBInstance[] = [];\n let marker: string | undefined;\n do {\n const resp = await rdsClient.send(\n new DescribeDBInstancesCommand({ Marker: marker }),\n );\n if (resp.DBInstances) instances.push(...resp.DBInstances);\n marker = resp.Marker;\n } while (marker);\n\n for (const db of instances) {\n if (!db.PubliclyAccessible) continue;\n\n const dbId = db.DBInstanceIdentifier ?? \"unknown\";\n const dbArn =\n db.DBInstanceArn ??\n `arn:${partition}:rds:${region}:${accountId}:db/${dbId}`;\n const endpoint = db.Endpoint?.Address;\n if (!endpoint) continue;\n\n resourcesScanned++;\n\n try {\n const addresses = await dns.promises.resolve4(endpoint);\n const hasPublicIp = addresses.some((ip) => !isPrivateIp(ip));\n\n if (hasPublicIp) {\n findings.push(\n makeFinding({\n riskScore: 8.0,\n title: `RDS instance ${dbId} endpoint resolves to public IP (verified)`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS endpoint ${endpoint} resolves to public IP(s): ${addresses.join(\", \")}. The database is network-reachable from the internet.`,\n impact:\n \"The database can be reached from the public internet, making it vulnerable to brute-force, credential stuffing, and exploitation of database vulnerabilities.\",\n remediationSteps: [\n \"Set PubliclyAccessible to false on the RDS instance.\",\n \"Move the instance to a private subnet.\",\n \"Use VPN or bastion host for database access.\",\n \"Restrict security group inbound rules to known IPs.\",\n ],\n }),\n );\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`DNS resolution for RDS ${dbId} (${endpoint}) failed: ${msg}`);\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`RDS public access verification failed: ${msg}`);\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n EC2Client,\n DescribeInstancesCommand,\n type Instance,\n} from \"@aws-sdk/client-ec2\";\nimport {\n RDSClient,\n DescribeDBInstancesCommand,\n type DBInstance,\n} from \"@aws-sdk/client-rds\";\nimport {\n S3Client,\n ListBucketsCommand,\n GetBucketTaggingCommand,\n} from \"@aws-sdk/client-s3\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst DEFAULT_REQUIRED_TAGS = [\"Environment\", \"Project\", \"Owner\"];\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nfunction getMissingTags(\n tags: Array<{ Key?: string; Value?: string }>,\n requiredTags: string[],\n): string[] {\n const tagKeys = new Set(tags.map((t) => t.Key ?? \"\"));\n return requiredTags.filter((rt) => !tagKeys.has(rt));\n}\n\nexport class TagComplianceScanner implements Scanner {\n readonly moduleName = \"tag_compliance\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n const requiredTags = DEFAULT_REQUIRED_TAGS;\n\n try {\n // --- EC2 instances ---\n try {\n const ec2Client = createClient(EC2Client, region, ctx.credentials);\n const instances: Instance[] = [];\n let nextToken: string | undefined;\n do {\n const resp = await ec2Client.send(\n new DescribeInstancesCommand({ NextToken: nextToken }),\n );\n for (const res of resp.Reservations ?? []) {\n if (res.Instances) instances.push(...res.Instances);\n }\n nextToken = resp.NextToken;\n } while (nextToken);\n\n resourcesScanned += instances.length;\n\n for (const instance of instances) {\n const id = instance.InstanceId ?? \"unknown\";\n const arn = `arn:${partition}:ec2:${region}:${accountId}:instance/${id}`;\n const tags = instance.Tags ?? [];\n const missing = getMissingTags(tags, requiredTags);\n\n if (missing.length > 0) {\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `EC2 instance ${id} missing required tags: ${missing.join(\", \")}`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: id,\n resourceArn: arn,\n region,\n description: `EC2 instance \"${id}\" is missing the following required tags: ${missing.join(\", \")}.`,\n impact:\n \"Resources without proper tags cannot be tracked for cost allocation, ownership, or compliance purposes.\",\n remediationSteps: [\n `Add the missing tags (${missing.join(\", \")}) to instance ${id}.`,\n \"Implement AWS Config rules or Tag Policies to enforce tagging.\",\n \"Use AWS Tag Editor for bulk tagging operations.\",\n ],\n }),\n );\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`EC2 tag compliance check failed: ${msg}`);\n }\n\n // --- RDS instances ---\n try {\n const rdsClient = createClient(RDSClient, region, ctx.credentials);\n const dbInstances: DBInstance[] = [];\n let marker: string | undefined;\n do {\n const resp = await rdsClient.send(\n new DescribeDBInstancesCommand({ Marker: marker }),\n );\n if (resp.DBInstances) dbInstances.push(...resp.DBInstances);\n marker = resp.Marker;\n } while (marker);\n\n resourcesScanned += dbInstances.length;\n\n for (const db of dbInstances) {\n const dbId = db.DBInstanceIdentifier ?? \"unknown\";\n const dbArn =\n db.DBInstanceArn ??\n `arn:${partition}:rds:${region}:${accountId}:db/${dbId}`;\n const tags = (db.TagList ?? []).map((t) => ({\n Key: t.Key,\n Value: t.Value,\n }));\n const missing = getMissingTags(tags, requiredTags);\n\n if (missing.length > 0) {\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `RDS instance ${dbId} missing required tags: ${missing.join(\", \")}`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS instance \"${dbId}\" is missing the following required tags: ${missing.join(\", \")}.`,\n impact:\n \"Resources without proper tags cannot be tracked for cost allocation, ownership, or compliance purposes.\",\n remediationSteps: [\n `Add the missing tags (${missing.join(\", \")}) to RDS instance ${dbId}.`,\n \"Implement AWS Config rules or Tag Policies to enforce tagging.\",\n \"Use AWS Tag Editor for bulk tagging operations.\",\n ],\n }),\n );\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`RDS tag compliance check failed: ${msg}`);\n }\n\n // --- S3 buckets ---\n try {\n const s3Client = createClient(S3Client, region, ctx.credentials);\n const listResp = await s3Client.send(new ListBucketsCommand({}));\n const buckets = listResp.Buckets ?? [];\n resourcesScanned += buckets.length;\n\n for (const bucket of buckets) {\n const name = bucket.Name ?? \"unknown\";\n const arn = `arn:${partition}:s3:::${name}`;\n\n try {\n const taggingResp = await s3Client.send(\n new GetBucketTaggingCommand({ Bucket: name }),\n );\n const tags = (taggingResp.TagSet ?? []).map((t) => ({\n Key: t.Key,\n Value: t.Value,\n }));\n const missing = getMissingTags(tags, requiredTags);\n\n if (missing.length > 0) {\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `S3 bucket ${name} missing required tags: ${missing.join(\", \")}`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region: \"global\",\n description: `S3 bucket \"${name}\" is missing the following required tags: ${missing.join(\", \")}.`,\n impact:\n \"Resources without proper tags cannot be tracked for cost allocation, ownership, or compliance purposes.\",\n remediationSteps: [\n `Add the missing tags (${missing.join(\", \")}) to bucket ${name}.`,\n \"Implement AWS Config rules or Tag Policies to enforce tagging.\",\n \"Use AWS Tag Editor for bulk tagging operations.\",\n ],\n }),\n );\n }\n } catch (e: unknown) {\n if (\n e instanceof Error &&\n e.name === \"NoSuchTagSet\"\n ) {\n // No tags at all — all required tags are missing\n findings.push(\n makeFinding({\n riskScore: 4.0,\n title: `S3 bucket ${name} missing required tags: ${requiredTags.join(\", \")}`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region: \"global\",\n description: `S3 bucket \"${name}\" has no tags configured. Missing all required tags: ${requiredTags.join(\", \")}.`,\n impact:\n \"Resources without proper tags cannot be tracked for cost allocation, ownership, or compliance purposes.\",\n remediationSteps: [\n `Add the required tags (${requiredTags.join(\", \")}) to bucket ${name}.`,\n \"Implement AWS Config rules or Tag Policies to enforce tagging.\",\n \"Use AWS Tag Editor for bulk tagging operations.\",\n ],\n }),\n );\n } else {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`S3 tag check for ${name} failed: ${msg}`);\n }\n }\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`S3 tag compliance check failed: ${msg}`);\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n EC2Client,\n DescribeVolumesCommand,\n DescribeAddressesCommand,\n DescribeInstancesCommand,\n DescribeNetworkInterfacesCommand,\n DescribeSecurityGroupsCommand,\n type Volume,\n type Address,\n type Instance,\n type SecurityGroup,\n} from \"@aws-sdk/client-ec2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class IdleResourcesScanner implements Scanner {\n readonly moduleName = \"idle_resources\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n const client = createClient(EC2Client, region, ctx.credentials);\n let resourcesScanned = 0;\n\n // 1. Unattached EBS volumes (State = \"available\")\n const volumes: Volume[] = [];\n let volToken: string | undefined;\n do {\n const resp = await client.send(\n new DescribeVolumesCommand({ NextToken: volToken }),\n );\n if (resp.Volumes) volumes.push(...resp.Volumes);\n volToken = resp.NextToken;\n } while (volToken);\n\n resourcesScanned += volumes.length;\n\n for (const vol of volumes) {\n if (vol.State === \"available\") {\n const volId = vol.VolumeId ?? \"unknown\";\n findings.push(\n makeFinding({\n riskScore: 3.0,\n title: `EBS volume ${volId} is unattached`,\n resourceType: \"AWS::EC2::Volume\",\n resourceId: volId,\n resourceArn: `arn:${partition}:ec2:${region}:${accountId}:volume/${volId}`,\n region,\n description: `EBS volume \"${volId}\" (${vol.Size ?? \"?\"}GB, ${vol.VolumeType ?? \"unknown\"}) is in \"available\" state with no attachments.`,\n impact:\n \"Unattached volumes incur storage costs and may contain sensitive data that is no longer actively managed.\",\n remediationSteps: [\n \"Determine if the volume is still needed.\",\n \"If not needed, create a snapshot for archival and delete the volume.\",\n \"If needed, attach it to the appropriate instance.\",\n ],\n }),\n );\n }\n }\n\n // 2. Unused Elastic IPs (not associated with any instance)\n let addresses: Address[] = [];\n try {\n const addrResp = await client.send(new DescribeAddressesCommand({}));\n addresses = addrResp.Addresses ?? [];\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Elastic IP check failed: ${msg}`);\n }\n\n resourcesScanned += addresses.length;\n\n for (const addr of addresses) {\n if (!addr.AssociationId) {\n const allocId = addr.AllocationId ?? \"unknown\";\n const publicIp = addr.PublicIp ?? \"unknown\";\n findings.push(\n makeFinding({\n riskScore: 2.0,\n title: `Elastic IP ${publicIp} is not associated`,\n resourceType: \"AWS::EC2::EIP\",\n resourceId: allocId,\n resourceArn: `arn:${partition}:ec2:${region}:${accountId}:elastic-ip/${allocId}`,\n region,\n description: `Elastic IP ${publicIp} (${allocId}) is allocated but not associated with any instance or network interface.`,\n impact:\n \"Unused Elastic IPs cost ~$3.60/month each and represent unnecessary spend.\",\n remediationSteps: [\n \"Associate the EIP with an instance or network interface if needed.\",\n \"Release the EIP if it is no longer required.\",\n ],\n }),\n );\n }\n }\n\n // 3. Stopped EC2 instances (>30 days)\n const instances: Instance[] = [];\n let instToken: string | undefined;\n do {\n const instResp = await client.send(\n new DescribeInstancesCommand({ NextToken: instToken }),\n );\n for (const res of instResp.Reservations ?? []) {\n if (res.Instances) instances.push(...res.Instances);\n }\n instToken = instResp.NextToken;\n } while (instToken);\n\n resourcesScanned += instances.length;\n const now = Date.now();\n\n for (const inst of instances) {\n if (inst.State?.Name === \"stopped\") {\n const instId = inst.InstanceId ?? \"unknown\";\n const reason = inst.StateTransitionReason ?? \"\";\n const stoppedTime = reason ? parseStopTime(reason) : null;\n\n if (!stoppedTime) {\n warnings.push(\n `Could not determine stop date for instance ${instId}. StateTransitionReason: ${reason}`,\n );\n continue;\n }\n\n const stoppedDays = Math.round(\n (now - stoppedTime) / (24 * 60 * 60 * 1000),\n );\n\n if (stoppedDays > 30) {\n findings.push(\n makeFinding({\n riskScore: 3.0,\n title: `EC2 instance ${instId} has been stopped for ${stoppedDays} days`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instId,\n resourceArn: `arn:${partition}:ec2:${region}:${accountId}:instance/${instId}`,\n region,\n description: `EC2 instance \"${instId}\" (${inst.InstanceType ?? \"unknown\"}) is in stopped state for ${stoppedDays} days. Attached EBS volumes continue to incur charges.`,\n impact:\n \"Stopped instances still incur EBS storage costs and may contain stale configurations or unpatched AMIs.\",\n remediationSteps: [\n \"Determine if the instance is still needed.\",\n \"If not needed, create an AMI for archival and terminate the instance.\",\n \"If needed temporarily, consider using a launch template for on-demand recreation.\",\n ],\n }),\n );\n }\n }\n }\n\n // 4. Unused Security Groups (not attached to any ENI)\n const securityGroups: SecurityGroup[] = [];\n let sgToken: string | undefined;\n do {\n const sgResp = await client.send(\n new DescribeSecurityGroupsCommand({ NextToken: sgToken }),\n );\n if (sgResp.SecurityGroups) securityGroups.push(...sgResp.SecurityGroups);\n sgToken = sgResp.NextToken;\n } while (sgToken);\n\n // Find all SGs referenced by ENIs\n const usedSgIds = new Set<string>();\n let eniToken: string | undefined;\n do {\n const eniResp = await client.send(\n new DescribeNetworkInterfacesCommand({ NextToken: eniToken }),\n );\n for (const eni of eniResp.NetworkInterfaces ?? []) {\n for (const group of eni.Groups ?? []) {\n if (group.GroupId) usedSgIds.add(group.GroupId);\n }\n }\n eniToken = eniResp.NextToken;\n } while (eniToken);\n\n resourcesScanned += securityGroups.length;\n\n for (const sg of securityGroups) {\n const sgId = sg.GroupId ?? \"unknown\";\n // Skip default security groups — they cannot be deleted\n if (sg.GroupName === \"default\") continue;\n\n if (!usedSgIds.has(sgId)) {\n findings.push(\n makeFinding({\n riskScore: 2.0,\n title: `Security group ${sgId} is not attached to any resource`,\n resourceType: \"AWS::EC2::SecurityGroup\",\n resourceId: sgId,\n resourceArn: `arn:${partition}:ec2:${region}:${sg.OwnerId ?? accountId}:security-group/${sgId}`,\n region,\n description: `Security group \"${sg.GroupName}\" (${sgId}) is not associated with any network interface.`,\n impact:\n \"Unused security groups add clutter and may cause confusion during security reviews.\",\n remediationSteps: [\n \"Verify the security group is not referenced by other resources (e.g., launch templates).\",\n \"Delete the security group if it is no longer needed.\",\n ],\n }),\n );\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n\n/**\n * Parse the stop time from EC2 StateTransitionReason.\n * Format: \"User initiated (2024-01-15 08:30:00 GMT)\"\n */\nfunction parseStopTime(reason: string): number | null {\n const match = reason.match(/\\((\\d{4}-\\d{2}-\\d{2}\\s\\d{2}:\\d{2}:\\d{2}\\s\\w+)\\)/);\n if (!match) return null;\n const parsed = Date.parse(match[1]);\n return isNaN(parsed) ? null : parsed;\n}\n","import {\n RDSClient,\n DescribeDBInstancesCommand,\n type DBInstance,\n} from \"@aws-sdk/client-rds\";\nimport {\n EC2Client,\n DescribeVolumesCommand,\n DescribeSnapshotsCommand,\n type Volume,\n type Snapshot,\n} from \"@aws-sdk/client-ec2\";\nimport {\n S3Client,\n ListBucketsCommand,\n GetBucketVersioningCommand,\n GetBucketReplicationCommand,\n} from \"@aws-sdk/client-s3\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nconst SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class DisasterRecoveryScanner implements Scanner {\n readonly moduleName = \"disaster_recovery\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n let resourcesScanned = 0;\n\n // --- RDS checks ---\n const rdsClient = createClient(RDSClient, region, ctx.credentials);\n const instances: DBInstance[] = [];\n let marker: string | undefined;\n do {\n const resp = await rdsClient.send(\n new DescribeDBInstancesCommand({ Marker: marker }),\n );\n if (resp.DBInstances) instances.push(...resp.DBInstances);\n marker = resp.Marker;\n } while (marker);\n\n resourcesScanned += instances.length;\n\n for (const db of instances) {\n const dbId = db.DBInstanceIdentifier ?? \"unknown\";\n const dbArn =\n db.DBInstanceArn ??\n `arn:${partition}:rds:${region}:${accountId}:db/${dbId}`;\n const engine = db.Engine ?? \"unknown\";\n\n // MultiAZ check\n if (!db.MultiAZ) {\n findings.push(\n makeFinding({\n riskScore: 6.0,\n title: `RDS instance ${dbId} is not Multi-AZ`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS instance \"${dbId}\" (${engine}) does not have Multi-AZ deployment enabled.`,\n impact:\n \"Single-AZ deployments have no automatic failover. An AZ outage will cause downtime and potential data loss.\",\n remediationSteps: [\n \"Enable Multi-AZ deployment for the RDS instance.\",\n \"This provides automatic failover to a standby in a different AZ.\",\n ],\n }),\n );\n }\n\n // Backup retention check\n const retention = db.BackupRetentionPeriod ?? 0;\n if (retention === 0) {\n findings.push(\n makeFinding({\n riskScore: 5.5,\n title: `RDS instance ${dbId} has automated backups disabled`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS instance \"${dbId}\" (${engine}) has backup retention period set to 0 (disabled).`,\n impact:\n \"No automated backups or point-in-time recovery. Data loss from failures or corruption is unrecoverable.\",\n remediationSteps: [\n \"Set the backup retention period to at least 7 days.\",\n \"Consider cross-region backup replication for critical databases.\",\n ],\n }),\n );\n } else if (retention < 7) {\n findings.push(\n makeFinding({\n riskScore: 5.5,\n title: `RDS instance ${dbId} backup retention is only ${retention} day(s)`,\n resourceType: \"AWS::RDS::DBInstance\",\n resourceId: dbId,\n resourceArn: dbArn,\n region,\n description: `RDS instance \"${dbId}\" (${engine}) has backup retention period of ${retention} day(s), below the recommended 7 days.`,\n impact:\n \"Short retention windows limit point-in-time recovery options and may not meet compliance requirements.\",\n remediationSteps: [\n \"Increase the backup retention period to at least 7 days.\",\n \"For production databases, consider 14-35 days retention.\",\n ],\n }),\n );\n }\n }\n\n // --- EBS snapshot checks ---\n const ec2Client = createClient(EC2Client, region, ctx.credentials);\n\n const volumes: Volume[] = [];\n let volToken: string | undefined;\n do {\n const resp = await ec2Client.send(\n new DescribeVolumesCommand({ NextToken: volToken }),\n );\n if (resp.Volumes) volumes.push(...resp.Volumes);\n volToken = resp.NextToken;\n } while (volToken);\n\n // Get all snapshots owned by this account\n const snapshots: Snapshot[] = [];\n let snapToken: string | undefined;\n do {\n const resp = await ec2Client.send(\n new DescribeSnapshotsCommand({\n OwnerIds: [\"self\"],\n NextToken: snapToken,\n }),\n );\n if (resp.Snapshots) snapshots.push(...resp.Snapshots);\n snapToken = resp.NextToken;\n } while (snapToken);\n\n // Build a map: volumeId -> most recent snapshot time\n const latestSnapshotByVolume = new Map<string, number>();\n for (const snap of snapshots) {\n if (!snap.VolumeId || snap.State !== \"completed\") continue;\n const snapTime = snap.StartTime?.getTime() ?? 0;\n const existing = latestSnapshotByVolume.get(snap.VolumeId) ?? 0;\n if (snapTime > existing) {\n latestSnapshotByVolume.set(snap.VolumeId, snapTime);\n }\n }\n\n // Only check in-use volumes for snapshot coverage\n const inUseVolumes = volumes.filter((v) => v.State === \"in-use\");\n resourcesScanned += inUseVolumes.length;\n const now = Date.now();\n\n for (const vol of inUseVolumes) {\n const volId = vol.VolumeId ?? \"unknown\";\n const volArn = `arn:${partition}:ec2:${region}:${accountId}:volume/${volId}`;\n const latestSnap = latestSnapshotByVolume.get(volId);\n\n if (latestSnap === undefined) {\n // No snapshots at all\n findings.push(\n makeFinding({\n riskScore: 7.0,\n title: `EBS volume ${volId} has no snapshots`,\n resourceType: \"AWS::EC2::Volume\",\n resourceId: volId,\n resourceArn: volArn,\n region,\n description: `EBS volume \"${volId}\" (${vol.Size ?? \"?\"}GB, ${vol.VolumeType ?? \"unknown\"}) has no snapshots. Data cannot be recovered if the volume fails.`,\n impact:\n \"Complete data loss if the volume becomes unavailable. No backup exists for disaster recovery.\",\n remediationSteps: [\n \"Create a snapshot of the volume immediately.\",\n \"Set up automated snapshots using AWS Backup or Amazon Data Lifecycle Manager.\",\n ],\n }),\n );\n } else if (now - latestSnap > SEVEN_DAYS_MS) {\n const daysSince = Math.round((now - latestSnap) / (24 * 60 * 60 * 1000));\n findings.push(\n makeFinding({\n riskScore: 5.0,\n title: `EBS volume ${volId} has no recent snapshot (${daysSince} days old)`,\n resourceType: \"AWS::EC2::Volume\",\n resourceId: volId,\n resourceArn: volArn,\n region,\n description: `EBS volume \"${volId}\" (${vol.Size ?? \"?\"}GB) most recent snapshot is ${daysSince} days old, exceeding the 7-day threshold.`,\n impact:\n \"Recovery from the latest snapshot would lose up to ${daysSince} days of data.\",\n remediationSteps: [\n \"Create a fresh snapshot of the volume.\",\n \"Configure automated snapshot schedules using AWS Backup or Data Lifecycle Manager.\",\n ],\n }),\n );\n }\n }\n\n // --- S3 checks ---\n const s3Client = createClient(S3Client, region, ctx.credentials);\n\n let bucketNames: string[] = [];\n try {\n const listResp = await s3Client.send(new ListBucketsCommand({}));\n bucketNames = (listResp.Buckets ?? []).map((b) => b.Name).filter((n): n is string => !!n);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`S3 bucket list failed: ${msg}`);\n }\n\n resourcesScanned += bucketNames.length;\n\n for (const name of bucketNames) {\n const arn = `arn:${partition}:s3:::${name}`;\n\n // Versioning check\n try {\n const ver = await s3Client.send(\n new GetBucketVersioningCommand({ Bucket: name }),\n );\n if (ver.Status !== \"Enabled\") {\n findings.push(\n makeFinding({\n riskScore: 3.0,\n title: `S3 bucket ${name} does not have versioning enabled`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region,\n description: `Bucket \"${name}\" versioning is ${ver.Status ?? \"not set\"}. Object deletion or overwrite is irreversible.`,\n impact:\n \"Accidental deletion or corruption of objects cannot be recovered without versioning.\",\n remediationSteps: [\n \"Enable versioning on the bucket.\",\n \"Consider adding lifecycle rules to manage version storage costs.\",\n ],\n }),\n );\n }\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Bucket ${name} versioning check failed: ${msg}`);\n }\n\n // Cross-region replication check\n try {\n await s3Client.send(\n new GetBucketReplicationCommand({ Bucket: name }),\n );\n // If the call succeeds, replication is configured — no finding needed\n } catch (e: unknown) {\n if (\n e instanceof Error &&\n e.name === \"ReplicationConfigurationNotFoundError\"\n ) {\n findings.push(\n makeFinding({\n riskScore: 3.5,\n title: `S3 bucket ${name} has no cross-region replication`,\n resourceType: \"AWS::S3::Bucket\",\n resourceId: name,\n resourceArn: arn,\n region,\n description: `Bucket \"${name}\" does not have cross-region replication configured.`,\n impact:\n \"Data is stored in a single region. A regional outage could make the data unavailable.\",\n remediationSteps: [\n \"Enable cross-region replication to a bucket in another region.\",\n \"Ensure versioning is enabled (required for CRR).\",\n \"Consider S3 Replication Time Control for critical data.\",\n ],\n }),\n );\n } else {\n const msg = e instanceof Error ? e.message : String(e);\n warnings.push(`Bucket ${name} replication check failed: ${msg}`);\n }\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n SecurityHubClient,\n GetFindingsCommand,\n} from \"@aws-sdk/client-securityhub\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction shSeverityToScore(label: string): number | null {\n switch (label) {\n case \"CRITICAL\": return 9.5;\n case \"HIGH\": return 8.0;\n case \"MEDIUM\": return 5.5;\n case \"LOW\": return 3.0;\n case \"INFORMATIONAL\": return null; // skip\n default: return null;\n }\n}\n\nexport class SecurityHubFindingsScanner implements Scanner {\n readonly moduleName = \"security_hub_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(SecurityHubClient, region, ctx.credentials);\n let nextToken: string | undefined;\n\n do {\n const resp = await client.send(\n new GetFindingsCommand({\n Filters: {\n WorkflowStatus: [\n { Value: \"NEW\", Comparison: \"EQUALS\" },\n { Value: \"NOTIFIED\", Comparison: \"EQUALS\" },\n ],\n RecordState: [{ Value: \"ACTIVE\", Comparison: \"EQUALS\" }],\n },\n MaxResults: 100,\n NextToken: nextToken,\n }),\n );\n\n const shFindings = resp.Findings ?? [];\n resourcesScanned += shFindings.length;\n\n for (const f of shFindings) {\n const severityLabel = f.Severity?.Label ?? \"INFORMATIONAL\";\n const score = shSeverityToScore(severityLabel);\n if (score === null) continue; // skip INFORMATIONAL\n\n const severity = severityFromScore(score);\n const resourceId = f.Resources?.[0]?.Id ?? \"unknown\";\n const resourceType = f.Resources?.[0]?.Type ?? \"AWS::Unknown\";\n const resourceArn = resourceId.startsWith(\"arn:\")\n ? resourceId\n : `arn:${partition}:securityhub:${region}:${accountId}:finding/${f.Id ?? \"unknown\"}`;\n\n const remediationSteps: string[] = [];\n if (f.Remediation?.Recommendation?.Text) {\n remediationSteps.push(f.Remediation.Recommendation.Text);\n }\n if (f.Remediation?.Recommendation?.Url) {\n remediationSteps.push(`Reference: ${f.Remediation.Recommendation.Url}`);\n }\n if (remediationSteps.length === 0) {\n remediationSteps.push(\"Review the finding in the AWS Security Hub console and follow the recommended remediation.\");\n }\n\n findings.push({\n severity,\n title: f.Title ?? \"Security Hub Finding\",\n resourceType,\n resourceId,\n resourceArn,\n region: f.Region ?? region,\n description: f.Description ?? f.Title ?? \"No description\",\n impact: `Source: ${f.ProductName ?? \"Security Hub\"} (${f.GeneratorId ?? \"unknown\"})`,\n riskScore: score,\n remediationSteps,\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId: f.AwsAccountId ?? accountId,\n });\n }\n\n nextToken = resp.NextToken;\n } while (nextToken);\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isNotEnabled =\n (err instanceof Error && err.name === \"InvalidAccessException\") ||\n msg.includes(\"not subscribed\") ||\n msg.includes(\"not enabled\");\n\n if (isNotEnabled) {\n warnings.push(\"Security Hub is not enabled in this region. Enable it to aggregate security findings.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Security Hub findings scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n GuardDutyClient,\n ListDetectorsCommand,\n ListFindingsCommand,\n GetFindingsCommand,\n} from \"@aws-sdk/client-guardduty\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction gdSeverityToScore(severity: number): number {\n if (severity >= 7.0) return 8.0; // HIGH\n if (severity >= 4.0) return 5.5; // MEDIUM\n return 3.0; // LOW\n}\n\nexport class GuardDutyFindingsScanner implements Scanner {\n readonly moduleName = \"guardduty_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(GuardDutyClient, region, ctx.credentials);\n\n // Step 1: Get detector ID\n const detectorsResp = await client.send(new ListDetectorsCommand({}));\n const detectorIds = detectorsResp.DetectorIds ?? [];\n\n if (detectorIds.length === 0) {\n warnings.push(\"GuardDuty is not enabled in this region (no detectors found).\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n const detectorId = detectorIds[0];\n\n // Step 2: List finding IDs (not archived)\n let nextToken: string | undefined;\n const findingIds: string[] = [];\n\n do {\n const listResp = await client.send(\n new ListFindingsCommand({\n DetectorId: detectorId,\n FindingCriteria: {\n Criterion: {\n \"service.archived\": {\n Eq: [\"false\"],\n },\n },\n },\n MaxResults: 50,\n NextToken: nextToken,\n }),\n );\n findingIds.push(...(listResp.FindingIds ?? []));\n nextToken = listResp.NextToken;\n } while (nextToken);\n\n resourcesScanned = findingIds.length;\n\n if (findingIds.length === 0) {\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n // Step 3: Get finding details (batch of 50)\n for (let i = 0; i < findingIds.length; i += 50) {\n const batch = findingIds.slice(i, i + 50);\n const detailsResp = await client.send(\n new GetFindingsCommand({\n DetectorId: detectorId,\n FindingIds: batch,\n }),\n );\n\n for (const gdf of detailsResp.Findings ?? []) {\n const gdSeverity = gdf.Severity ?? 0;\n const score = gdSeverityToScore(gdSeverity);\n const severity = severityFromScore(score);\n\n const resourceType = gdf.Resource?.ResourceType ?? \"AWS::Unknown\";\n const resourceId = gdf.Resource?.InstanceDetails?.InstanceId\n ?? gdf.Resource?.AccessKeyDetails?.AccessKeyId\n ?? gdf.Arn\n ?? \"unknown\";\n const resourceArn = gdf.Arn\n ?? `arn:${partition}:guardduty:${region}:${accountId}:detector/${detectorId}/finding/${gdf.Id ?? \"unknown\"}`;\n\n findings.push({\n severity,\n title: `[GuardDuty] ${gdf.Title ?? gdf.Type ?? \"Finding\"}`,\n resourceType,\n resourceId,\n resourceArn,\n region: gdf.Region ?? region,\n description: gdf.Description ?? gdf.Title ?? \"No description\",\n impact: `GuardDuty threat type: ${gdf.Type ?? \"unknown\"} (severity ${gdSeverity})`,\n riskScore: score,\n remediationSteps: [\n \"Review the finding in the Amazon GuardDuty console.\",\n `Finding type: ${gdf.Type ?? \"unknown\"}`,\n \"Follow the recommended remediation in the GuardDuty documentation.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId: gdf.AccountId ?? accountId,\n });\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n module: this.moduleName,\n status: \"error\",\n error: `GuardDuty findings scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n Inspector2Client,\n ListFindingsCommand,\n type FilterCriteria,\n} from \"@aws-sdk/client-inspector2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction inspectorSeverityToScore(label: string): number | null {\n switch (label) {\n case \"CRITICAL\": return 9.5;\n case \"HIGH\": return 8.0;\n case \"MEDIUM\": return 5.5;\n case \"LOW\": return 3.0;\n case \"INFORMATIONAL\": return null;\n case \"UNTRIAGED\": return 5.5;\n default: return null;\n }\n}\n\nexport class InspectorFindingsScanner implements Scanner {\n readonly moduleName = \"inspector_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(Inspector2Client, region, ctx.credentials);\n let nextToken: string | undefined;\n\n const filterCriteria: FilterCriteria = {\n findingStatus: [{ comparison: \"EQUALS\", value: \"ACTIVE\" }],\n };\n\n do {\n const resp = await client.send(\n new ListFindingsCommand({\n filterCriteria,\n maxResults: 100,\n nextToken,\n }),\n );\n\n const inspFindings = resp.findings ?? [];\n resourcesScanned += inspFindings.length;\n\n for (const f of inspFindings) {\n const severityLabel = f.severity ?? \"INFORMATIONAL\";\n const score = inspectorSeverityToScore(severityLabel);\n if (score === null) continue;\n\n const severity = severityFromScore(score);\n\n // Build title with CVE if available\n const cveId = f.packageVulnerabilityDetails?.vulnerabilityId;\n const titleBase = f.title ?? \"Inspector Finding\";\n const title = cveId ? `[${cveId}] ${titleBase}` : titleBase;\n\n const resourceId = f.resources?.[0]?.id ?? \"unknown\";\n const resourceType = f.resources?.[0]?.type ?? \"AWS::Unknown\";\n const resourceArn = resourceId.startsWith(\"arn:\")\n ? resourceId\n : `arn:${partition}:inspector2:${region}:${accountId}:finding/${f.findingArn ?? \"unknown\"}`;\n\n const remediationSteps: string[] = [];\n if (f.remediation?.recommendation?.text) {\n remediationSteps.push(f.remediation.recommendation.text);\n }\n if (f.remediation?.recommendation?.Url) {\n remediationSteps.push(`Reference: ${f.remediation.recommendation.Url}`);\n }\n if (f.packageVulnerabilityDetails?.referenceUrls?.length) {\n remediationSteps.push(`CVE references: ${f.packageVulnerabilityDetails.referenceUrls.slice(0, 3).join(\", \")}`);\n }\n if (remediationSteps.length === 0) {\n remediationSteps.push(\"Review the finding in the Amazon Inspector console and apply the recommended patch or update.\");\n }\n\n const description = f.description ?? titleBase;\n const impact = cveId\n ? `Vulnerability ${cveId} — CVSS: ${f.packageVulnerabilityDetails?.cvss?.[0]?.baseScore ?? \"N/A\"}`\n : `Inspector finding type: ${f.type ?? \"unknown\"}`;\n\n findings.push({\n severity,\n title,\n resourceType,\n resourceId,\n resourceArn,\n region,\n description,\n impact,\n riskScore: score,\n remediationSteps,\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId: f.awsAccountId ?? accountId,\n });\n }\n\n nextToken = resp.nextToken;\n } while (nextToken);\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const errName = err instanceof Error ? err.name : \"\";\n\n const isAccessDenied = errName === \"AccessDeniedException\" || msg.includes(\"AccessDeniedException\");\n const isNotEnabled = msg.includes(\"not enabled\") || msg.includes(\"not subscribed\");\n\n if (isAccessDenied) {\n warnings.push(\"Insufficient permissions to access Inspector. Grant inspector2:ListFindings to scan for vulnerabilities.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n if (isNotEnabled) {\n warnings.push(\"Inspector is not enabled in this region. Enable it to scan for software vulnerabilities.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Inspector findings scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n SupportClient,\n DescribeTrustedAdvisorChecksCommand,\n DescribeTrustedAdvisorCheckResultCommand,\n} from \"@aws-sdk/client-support\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction taStatusToScore(status: string): number | null {\n switch (status) {\n case \"error\": return 8.0; // RED = action required\n case \"warning\": return 5.5; // YELLOW = investigation recommended\n case \"ok\": return null; // GREEN = no issue\n case \"not_available\": return null;\n default: return null;\n }\n}\n\nexport class TrustedAdvisorFindingsScanner implements Scanner {\n readonly moduleName = \"trusted_advisor_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n // Trusted Advisor API endpoint: cn-north-1 for China, us-east-1 for standard\n const supportRegion = region.startsWith(\"cn-\") ? \"cn-north-1\" : \"us-east-1\";\n const clientConfig: any = { region: supportRegion };\n if (ctx.credentials) clientConfig.credentials = ctx.credentials;\n const client = new SupportClient(clientConfig);\n\n // Step 1: List security checks\n const checksResp = await client.send(\n new DescribeTrustedAdvisorChecksCommand({ language: \"en\" }),\n );\n const allChecks = checksResp.checks ?? [];\n const securityChecks = allChecks.filter((c) => c.category === \"security\");\n\n if (securityChecks.length === 0) {\n warnings.push(\"No Trusted Advisor security checks found.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n // Step 2: Get results for each security check\n for (const check of securityChecks) {\n if (!check.id) continue;\n\n try {\n const resultResp = await client.send(\n new DescribeTrustedAdvisorCheckResultCommand({\n checkId: check.id,\n }),\n );\n\n const result = resultResp.result;\n if (!result) continue;\n\n const status = result.status ?? \"not_available\";\n const score = taStatusToScore(status);\n\n resourcesScanned++;\n\n if (score === null) continue; // ok or not_available — skip\n\n // Map flagged resources to findings\n const flaggedResources = result.flaggedResources ?? [];\n\n if (flaggedResources.length === 0) {\n // Check-level finding without specific resources\n const severity = severityFromScore(score);\n findings.push({\n severity,\n title: `[Trusted Advisor] ${check.name ?? \"Security Check\"}`,\n resourceType: \"AWS::TrustedAdvisor::Check\",\n resourceId: check.id,\n resourceArn: `arn:${partition}:trustedadvisor:${region}:${accountId}:check/${check.id}`,\n region,\n description: check.description ?? check.name ?? \"Security check flagged\",\n impact: `Trusted Advisor status: ${status}`,\n riskScore: score,\n remediationSteps: [\n \"Review this Trusted Advisor check in the AWS console.\",\n \"Follow the recommended actions to resolve the flagged issue.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n continue;\n }\n\n // Create findings for flagged resources (limit to first 25 per check)\n const metadata = check.metadata ?? [];\n for (const fr of flaggedResources.slice(0, 25)) {\n if (fr.isSuppressed) continue;\n\n const severity = severityFromScore(score);\n const resourceMeta = fr.metadata ?? [];\n\n // Try to extract resource ID from metadata\n const resourceIdIdx = metadata.indexOf(\"Resource ID\");\n const regionIdx = metadata.indexOf(\"Region\");\n const flaggedResourceId = resourceIdIdx >= 0 && resourceMeta[resourceIdIdx]\n ? resourceMeta[resourceIdIdx]\n : fr.resourceId ?? \"unknown\";\n const flaggedRegion = regionIdx >= 0 && resourceMeta[regionIdx]\n ? resourceMeta[regionIdx]\n : region;\n\n findings.push({\n severity,\n title: `[Trusted Advisor] ${check.name ?? \"Security Check\"}: ${flaggedResourceId}`,\n resourceType: \"AWS::TrustedAdvisor::FlaggedResource\",\n resourceId: flaggedResourceId,\n resourceArn: `arn:${partition}:trustedadvisor:${flaggedRegion}:${accountId}:check/${check.id}/${fr.resourceId ?? \"unknown\"}`,\n region: flaggedRegion,\n description: `${check.name}: ${resourceMeta.join(\" | \")}`,\n impact: `Trusted Advisor status: ${status} — ${check.name ?? \"security check\"}`,\n riskScore: score,\n remediationSteps: [\n `Review Trusted Advisor check: ${check.name}`,\n \"Follow the recommended actions in the AWS Trusted Advisor console.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n }\n } catch (checkErr) {\n const checkMsg = checkErr instanceof Error ? checkErr.message : String(checkErr);\n warnings.push(`Trusted Advisor check ${check.name ?? check.id} failed: ${checkMsg}`);\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n const isSubscriptionRequired =\n msg.includes(\"SubscriptionRequiredException\") ||\n msg.includes(\"subscription\") ||\n msg.includes(\"AWS Premium Support\") ||\n (err instanceof Error && err.name === \"SubscriptionRequiredException\");\n\n if (isSubscriptionRequired) {\n warnings.push(\"Trusted Advisor requires AWS Business or Enterprise Support plan. Skipping.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Trusted Advisor scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n ConfigServiceClient,\n DescribeComplianceByConfigRuleCommand,\n GetComplianceDetailsByConfigRuleCommand,\n type ComplianceByConfigRule,\n} from \"@aws-sdk/client-config-service\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\n/** Security-related Config rule name patterns that warrant HIGH severity */\nconst SECURITY_RULE_PATTERNS = [\n \"securitygroup\", \"security-group\",\n \"encryption\", \"encrypted\",\n \"public\", \"unrestricted\",\n \"mfa\", \"password\", \"access-key\",\n \"root\", \"admin\",\n \"logging\", \"cloudtrail\",\n \"iam\", \"kms\", \"ssl\", \"tls\",\n \"vpc-flow\", \"guardduty\", \"securityhub\",\n];\n\nfunction ruleIsSecurityRelated(ruleName: string): boolean {\n const lower = ruleName.toLowerCase();\n return SECURITY_RULE_PATTERNS.some((pat) => lower.includes(pat));\n}\n\nexport class ConfigRulesFindingsScanner implements Scanner {\n readonly moduleName = \"config_rules_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(ConfigServiceClient, region, ctx.credentials);\n\n // Step 1: Get all rules and their compliance status\n let nextToken: string | undefined;\n const nonCompliantRules: ComplianceByConfigRule[] = [];\n\n do {\n const resp = await client.send(\n new DescribeComplianceByConfigRuleCommand({ NextToken: nextToken }),\n );\n\n for (const rule of resp.ComplianceByConfigRules ?? []) {\n resourcesScanned++;\n if (rule.Compliance?.ComplianceType === \"NON_COMPLIANT\") {\n nonCompliantRules.push(rule);\n }\n }\n\n nextToken = resp.NextToken;\n } while (nextToken);\n\n if (resourcesScanned === 0) {\n warnings.push(\"AWS Config is not enabled in this region or no Config Rules are defined.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n // Step 2: For each non-compliant rule, get the non-compliant resources\n for (const rule of nonCompliantRules) {\n const ruleName = rule.ConfigRuleName ?? \"unknown\";\n\n try {\n let detailToken: string | undefined;\n do {\n const detailResp = await client.send(\n new GetComplianceDetailsByConfigRuleCommand({\n ConfigRuleName: ruleName,\n ComplianceTypes: [\"NON_COMPLIANT\"],\n NextToken: detailToken,\n }),\n );\n\n for (const evalResult of detailResp.EvaluationResults ?? []) {\n const qualifier = evalResult.EvaluationResultIdentifier?.EvaluationResultQualifier;\n const resourceType = qualifier?.ResourceType ?? \"AWS::Unknown\";\n const resourceId = qualifier?.ResourceId ?? \"unknown\";\n const annotation = evalResult.Annotation;\n\n const isSecurityRule = ruleIsSecurityRelated(ruleName);\n const riskScore = isSecurityRule ? 7.5 : 5.5;\n const severity = severityFromScore(riskScore);\n\n const descParts = [`Config Rule: ${ruleName}`, `Resource Type: ${resourceType}`];\n if (annotation) descParts.push(`Annotation: ${annotation}`);\n\n findings.push({\n severity,\n title: `Config Rule: ${ruleName} - ${resourceType}/${resourceId} Non-Compliant`,\n resourceType,\n resourceId,\n resourceArn: resourceId,\n region,\n description: descParts.join(\". \"),\n impact: `Resource is non-compliant with Config Rule: ${ruleName}`,\n riskScore,\n remediationSteps: [\n `Review the Config Rule \"${ruleName}\" in the AWS Config console.`,\n `Check resource ${resourceId} for compliance violations.`,\n \"Follow the rule's remediation guidance to bring the resource into compliance.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n }\n\n detailToken = detailResp.NextToken;\n } while (detailToken);\n } catch (detailErr) {\n const msg = detailErr instanceof Error ? detailErr.message : String(detailErr);\n warnings.push(`Failed to get details for rule ${ruleName}: ${msg}`);\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n\n // Config not enabled is a common case — return success with warning\n if (\n msg.includes(\"NoSuchConfigurationRecorder\") ||\n msg.includes(\"InsufficientDeliveryPolicy\") ||\n msg.includes(\"No Configuration Recorder\")\n ) {\n warnings.push(\"AWS Config is not enabled in this region.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Config Rules scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n AccessAnalyzerClient,\n ListAnalyzersCommand,\n ListFindingsV2Command,\n type AnalyzerSummary,\n type FindingSummaryV2,\n} from \"@aws-sdk/client-accessanalyzer\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\n/** Maps Access Analyzer findingType to a risk score. */\nfunction findingTypeToScore(findingType: string | undefined): number {\n const ft = findingType as string | undefined;\n switch (ft) {\n case \"ExternalAccess\": return 8.0;\n case \"UnusedIAMRole\":\n case \"UnusedIAMUserAccessKey\":\n case \"UnusedIAMUserPassword\": return 5.5;\n case \"UnusedPermission\": return 3.0;\n default: return 5.5;\n }\n}\n\nconst UNUSED_FINDING_TYPES = new Set([\n \"UnusedIAMRole\",\n \"UnusedIAMUserAccessKey\",\n \"UnusedIAMUserPassword\",\n \"UnusedPermission\",\n]);\n\nfunction isSecurityRelevant(findingType: string | undefined): boolean {\n const ft = findingType as string | undefined;\n return ft === \"ExternalAccess\" || UNUSED_FINDING_TYPES.has(ft ?? \"\");\n}\n\nfunction isExternalAccess(findingType: string | undefined): boolean {\n return (findingType as string | undefined) === \"ExternalAccess\";\n}\n\nexport class AccessAnalyzerFindingsScanner implements Scanner {\n readonly moduleName = \"access_analyzer_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(AccessAnalyzerClient, region, ctx.credentials);\n\n // Step 1: List active analyzers\n let analyzerToken: string | undefined;\n const analyzers: AnalyzerSummary[] = [];\n\n do {\n const resp = await client.send(\n new ListAnalyzersCommand({ nextToken: analyzerToken }),\n );\n for (const analyzer of resp.analyzers ?? []) {\n if (analyzer.status === \"ACTIVE\") {\n analyzers.push(analyzer);\n }\n }\n analyzerToken = resp.nextToken;\n } while (analyzerToken);\n\n if (analyzers.length === 0) {\n warnings.push(\"No IAM Access Analyzer found. Create an analyzer to detect external access to your resources.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n // Step 2: For each active analyzer, list ACTIVE findings\n for (const analyzer of analyzers) {\n const analyzerArn = analyzer.arn ?? \"unknown\";\n\n let findingToken: string | undefined;\n do {\n const listResp = await client.send(\n new ListFindingsV2Command({\n analyzerArn,\n filter: {\n status: { eq: [\"ACTIVE\"] },\n },\n nextToken: findingToken,\n }),\n );\n\n for (const aaf of listResp.findings ?? []) {\n // Only include security-relevant finding types\n if (!isSecurityRelevant(aaf.findingType)) {\n continue;\n }\n\n resourcesScanned++;\n const score = findingTypeToScore(aaf.findingType);\n const severity = severityFromScore(score);\n\n const resourceArn = aaf.resource ?? \"unknown\";\n const resourceType = aaf.resourceType ?? \"AWS::Unknown\";\n const resourceId = resourceArn.split(\"/\").pop() ?? resourceArn.split(\":\").pop() ?? \"unknown\";\n const external = isExternalAccess(aaf.findingType);\n\n const descParts = [`Resource Type: ${resourceType}`];\n if (aaf.resourceOwnerAccount) descParts.push(`Owner Account: ${aaf.resourceOwnerAccount}`);\n if (aaf.findingType) descParts.push(`Finding Type: ${aaf.findingType}`);\n\n const title = buildFindingTitle(aaf);\n\n const impact = external\n ? `Resource is accessible from outside the account. Type: ${aaf.findingType ?? \"unknown\"}`\n : `Unused access detected — review and remove to follow least-privilege. Type: ${aaf.findingType ?? \"unknown\"}`;\n\n const remediationSteps = external\n ? [\n \"Review the finding in the IAM Access Analyzer console.\",\n `Check resource ${resourceId} for unintended external access.`,\n \"Remove or restrict the resource policy to eliminate external access.\",\n ]\n : [\n \"Review the finding in the IAM Access Analyzer console.\",\n `Check resource ${resourceId} for unused access permissions.`,\n \"Remove unused permissions, roles, or credentials to follow least-privilege.\",\n ];\n\n findings.push({\n severity,\n title,\n resourceType: mapResourceType(resourceType),\n resourceId,\n resourceArn,\n region,\n description: descParts.join(\". \"),\n impact,\n riskScore: score,\n remediationSteps,\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId: aaf.resourceOwnerAccount ?? accountId,\n });\n }\n\n findingToken = listResp.nextToken;\n } while (findingToken);\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Access Analyzer scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n\nfunction buildFindingTitle(finding: FindingSummaryV2): string {\n const resourceType = finding.resourceType ?? \"Resource\";\n const resource = finding.resource\n ? (finding.resource.split(\"/\").pop() ?? finding.resource.split(\":\").pop() ?? finding.resource)\n : \"unknown\";\n const label = isExternalAccess(finding.findingType)\n ? \"external access detected\"\n : \"unused access detected\";\n return `[Access Analyzer] ${resourceType} ${resource} — ${label}`;\n}\n\nfunction mapResourceType(aaType: string): string {\n const mapping: Record<string, string> = {\n \"AWS::S3::Bucket\": \"AWS::S3::Bucket\",\n \"AWS::IAM::Role\": \"AWS::IAM::Role\",\n \"AWS::SQS::Queue\": \"AWS::SQS::Queue\",\n \"AWS::Lambda::Function\": \"AWS::Lambda::Function\",\n \"AWS::Lambda::LayerVersion\": \"AWS::Lambda::LayerVersion\",\n \"AWS::KMS::Key\": \"AWS::KMS::Key\",\n \"AWS::SecretsManager::Secret\": \"AWS::SecretsManager::Secret\",\n \"AWS::SNS::Topic\": \"AWS::SNS::Topic\",\n \"AWS::EFS::FileSystem\": \"AWS::EFS::FileSystem\",\n \"AWS::RDS::DBSnapshot\": \"AWS::RDS::DBSnapshot\",\n \"AWS::RDS::DBClusterSnapshot\": \"AWS::RDS::DBClusterSnapshot\",\n \"AWS::ECR::Repository\": \"AWS::ECR::Repository\",\n };\n return mapping[aaType] ?? aaType;\n}\n","import {\n SSMClient,\n DescribeInstanceInformationCommand,\n DescribeInstancePatchStatesCommand,\n type InstanceInformation,\n type InstancePatchState,\n} from \"@aws-sdk/client-ssm\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nexport class PatchComplianceFindingsScanner implements Scanner {\n readonly moduleName = \"patch_compliance_findings\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n let resourcesScanned = 0;\n\n try {\n const client = createClient(SSMClient, region, ctx.credentials);\n\n // Step 1: Get all managed instances\n let nextToken: string | undefined;\n const instances: InstanceInformation[] = [];\n\n do {\n const resp = await client.send(\n new DescribeInstanceInformationCommand({\n MaxResults: 50,\n NextToken: nextToken,\n }),\n );\n instances.push(...(resp.InstanceInformationList ?? []));\n nextToken = resp.NextToken;\n } while (nextToken);\n\n if (instances.length === 0) {\n warnings.push(\"No SSM-managed instances found in this region.\");\n return {\n module: this.moduleName,\n status: \"success\",\n warnings,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n resourcesScanned = instances.length;\n\n // Step 2: Get patch states in batches\n const instanceIds = instances.map((i) => i.InstanceId).filter(Boolean) as string[];\n const patchStateMap = new Map<string, InstancePatchState>();\n\n // DescribeInstancePatchStates supports up to 50 instances per call\n for (let i = 0; i < instanceIds.length; i += 50) {\n const batch = instanceIds.slice(i, i + 50);\n let patchToken: string | undefined;\n\n do {\n const patchResp = await client.send(\n new DescribeInstancePatchStatesCommand({\n InstanceIds: batch,\n NextToken: patchToken,\n }),\n );\n\n for (const ps of patchResp.InstancePatchStates ?? []) {\n if (ps.InstanceId) {\n patchStateMap.set(ps.InstanceId, ps);\n }\n }\n\n patchToken = patchResp.NextToken;\n } while (patchToken);\n }\n\n // Step 3: Generate findings for instances with missing/failed patches\n for (const instance of instances) {\n const instanceId = instance.InstanceId ?? \"unknown\";\n const platform = instance.PlatformName ?? instance.PlatformType ?? \"unknown\";\n const instanceArn = `arn:${partition}:ec2:${region}:${accountId}:instance/${instanceId}`;\n\n const patchState = patchStateMap.get(instanceId);\n\n if (!patchState) {\n // Instance not managed for patching — INFO-level finding\n const riskScore = 3.0;\n const severity = severityFromScore(riskScore);\n findings.push({\n severity,\n title: `Instance ${instanceId} has no patch compliance data`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instanceId,\n resourceArn: instanceArn,\n region,\n description: `Instance ${instanceId} (${platform}) is managed by SSM but has no patch compliance data. Patch Manager may not be configured for this instance.`,\n impact: \"Patch compliance status is unknown — vulnerabilities may exist.\",\n riskScore,\n remediationSteps: [\n \"Configure AWS Systems Manager Patch Manager for this instance.\",\n \"Create a patch baseline and maintenance window.\",\n \"Run a patch scan to establish compliance status.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n continue;\n }\n\n const missingCount = patchState.MissingCount ?? 0;\n const failedCount = patchState.FailedCount ?? 0;\n const criticalNonCompliantCount = patchState.CriticalNonCompliantCount ?? 0;\n const securityNonCompliantCount = patchState.SecurityNonCompliantCount ?? 0;\n const otherNonCompliantCount = patchState.OtherNonCompliantCount ?? 0;\n const lastScanTime = patchState.OperationEndTime?.toISOString() ?? \"unknown\";\n\n if (\n missingCount === 0 &&\n failedCount === 0 &&\n criticalNonCompliantCount === 0 &&\n securityNonCompliantCount === 0 &&\n otherNonCompliantCount === 0\n ) {\n continue; // Instance is fully patched\n }\n\n // Determine severity based on patch issues\n let riskScore: number;\n if (criticalNonCompliantCount > 0 || securityNonCompliantCount > 0 || failedCount > 0) {\n riskScore = 7.5; // HIGH — critical/security patches missing or failed\n } else if (otherNonCompliantCount > 0) {\n riskScore = 5.5; // MEDIUM — other non-compliant patches\n } else {\n riskScore = 5.5; // MEDIUM — non-security patches missing\n }\n const severity = severityFromScore(riskScore);\n\n const titleParts: string[] = [];\n if (missingCount > 0) titleParts.push(`${missingCount} missing`);\n if (failedCount > 0) titleParts.push(`${failedCount} failed`);\n if (criticalNonCompliantCount > 0) titleParts.push(`${criticalNonCompliantCount} critical non-compliant`);\n if (securityNonCompliantCount > 0) titleParts.push(`${securityNonCompliantCount} security non-compliant`);\n if (otherNonCompliantCount > 0) titleParts.push(`${otherNonCompliantCount} other non-compliant`);\n\n const descParts = [\n `Instance: ${instanceId}`,\n `Platform: ${platform}`,\n `Missing patches: ${missingCount}`,\n `Failed patches: ${failedCount}`,\n `Critical non-compliant: ${criticalNonCompliantCount}`,\n `Security non-compliant: ${securityNonCompliantCount}`,\n `Other non-compliant: ${otherNonCompliantCount}`,\n `Last scan: ${lastScanTime}`,\n ];\n\n findings.push({\n severity,\n title: `Instance ${instanceId} has ${titleParts.join(\", \")} patches`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instanceId,\n resourceArn: instanceArn,\n region,\n description: descParts.join(\". \"),\n impact: `Instance has ${missingCount} missing and ${failedCount} failed patches — potential security vulnerabilities.`,\n riskScore,\n remediationSteps: [\n `Review patch compliance for instance ${instanceId} in the Systems Manager console.`,\n \"Apply missing patches using a maintenance window or manual patching.\",\n \"Investigate and resolve any failed patch installations.\",\n \"Consider enabling automatic patching through Patch Manager.\",\n ],\n priority: priorityFromSeverity(severity),\n module: this.moduleName,\n accountId,\n });\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n module: this.moduleName,\n status: \"error\",\n error: `Patch compliance scan failed: ${msg}`,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n EC2Client,\n DescribeInstancesCommand,\n type Instance,\n} from \"@aws-sdk/client-ec2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class Imdsv2EnforcementScanner implements Scanner {\n readonly moduleName = \"imdsv2_enforcement\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region, partition, accountId } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n const client = createClient(EC2Client, region, ctx.credentials);\n\n // List all running EC2 instances\n const instances: Instance[] = [];\n let nextToken: string | undefined;\n do {\n const resp = await client.send(\n new DescribeInstancesCommand({\n Filters: [{ Name: \"instance-state-name\", Values: [\"running\"] }],\n NextToken: nextToken,\n }),\n );\n if (resp.Reservations) {\n for (const reservation of resp.Reservations) {\n if (reservation.Instances) {\n instances.push(...reservation.Instances);\n }\n }\n }\n nextToken = resp.NextToken;\n } while (nextToken);\n\n for (const instance of instances) {\n const instanceId = instance.InstanceId ?? \"unknown\";\n const instanceType = instance.InstanceType ?? \"unknown\";\n const state = instance.State?.Name ?? \"unknown\";\n const httpTokens = instance.MetadataOptions?.HttpTokens ?? \"unknown\";\n const hopLimit = instance.MetadataOptions?.HttpPutResponseHopLimit ?? 1;\n const instanceArn = `arn:${partition}:ec2:${region}:${accountId}:instance/${instanceId}`;\n\n if (httpTokens !== \"required\") {\n const description = [\n `EC2 instance ${instanceId} (type: ${instanceType}, state: ${state}) has HttpTokens set to \"${httpTokens}\".`,\n `IMDSv1 is accessible, allowing unauthenticated metadata requests.`,\n ];\n if (hopLimit > 1) {\n description.push(`HttpPutResponseHopLimit is ${hopLimit} (>1), which may allow containers to reach IMDS.`);\n }\n\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `EC2 instance ${instanceId} does not enforce IMDSv2`,\n resourceType: \"AWS::EC2::Instance\",\n resourceId: instanceId,\n resourceArn: instanceArn,\n region,\n description: description.join(\" \"),\n impact: \"IMDSv1 allows attackers to steal IAM role credentials via SSRF attacks\",\n remediationSteps: [\n \"Enforce IMDSv2 by setting HttpTokens to 'required'.\",\n \"Run: aws ec2 modify-instance-metadata-options --instance-id \" + instanceId + \" --http-tokens required --http-endpoint enabled\",\n \"Set HttpPutResponseHopLimit to 1 unless running containers that need metadata access.\",\n \"Update launch templates and Auto Scaling groups to enforce IMDSv2 for new instances.\",\n ],\n }),\n );\n } else if (hopLimit > 1) {\n // IMDSv2 enforced but hop limit is elevated — informational warning\n warnings.push(\n `Instance ${instanceId} enforces IMDSv2 but HttpPutResponseHopLimit is ${hopLimit} (>1). Verify this is intentional for containerized workloads.`,\n );\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: instances.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n return {\n module: this.moduleName,\n status: \"error\",\n error: err instanceof Error ? err.message : String(err),\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import {\n ElasticLoadBalancingV2Client,\n DescribeLoadBalancersCommand,\n type LoadBalancer,\n} from \"@aws-sdk/client-elastic-load-balancing-v2\";\nimport {\n WAFV2Client,\n GetWebACLForResourceCommand,\n} from \"@aws-sdk/client-wafv2\";\nimport { Scanner } from \"./base.js\";\nimport { ScanResult, ScanContext, Finding } from \"../types.js\";\nimport { createClient } from \"../utils/aws-client.js\";\nimport { severityFromScore, priorityFromSeverity } from \"../utils/risk-scoring.js\";\n\nfunction makeFinding(opts: {\n riskScore: number;\n title: string;\n resourceType: string;\n resourceId: string;\n resourceArn: string;\n region: string;\n description: string;\n impact: string;\n remediationSteps: string[];\n}): Finding {\n const severity = severityFromScore(opts.riskScore);\n return { ...opts, severity, priority: priorityFromSeverity(severity) };\n}\n\nexport class WafCoverageScanner implements Scanner {\n readonly moduleName = \"waf_coverage\";\n\n async scan(ctx: ScanContext): Promise<ScanResult> {\n const { region } = ctx;\n const startMs = Date.now();\n const findings: Finding[] = [];\n const warnings: string[] = [];\n\n try {\n const elbClient = createClient(ElasticLoadBalancingV2Client, region, ctx.credentials);\n const wafClient = createClient(WAFV2Client, region, ctx.credentials);\n\n // List all ELBv2 load balancers\n const loadBalancers: LoadBalancer[] = [];\n let marker: string | undefined;\n do {\n const resp = await elbClient.send(\n new DescribeLoadBalancersCommand({ Marker: marker }),\n );\n if (resp.LoadBalancers) {\n loadBalancers.push(...resp.LoadBalancers);\n }\n marker = resp.NextMarker;\n } while (marker);\n\n // Filter to internet-facing only\n const internetFacing = loadBalancers.filter((lb) => lb.Scheme === \"internet-facing\");\n\n for (const lb of internetFacing) {\n const lbName = lb.LoadBalancerName ?? \"unknown\";\n const lbArn = lb.LoadBalancerArn ?? \"unknown\";\n const lbType = lb.Type ?? \"unknown\";\n\n // WAF only applies to ALB (application), not NLB (network) or GLB (gateway)\n if (lbType !== \"application\") {\n warnings.push(\n `Skipping ${lbType} load balancer \"${lbName}\" — WAF Web ACL association is only supported for ALBs.`,\n );\n continue;\n }\n\n try {\n const wafResp = await wafClient.send(\n new GetWebACLForResourceCommand({ ResourceArn: lbArn }),\n );\n\n if (!wafResp.WebACL) {\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `Internet-facing ALB ${lbName} has no WAF protection`,\n resourceType: \"AWS::ElasticLoadBalancingV2::LoadBalancer\",\n resourceId: lbName,\n resourceArn: lbArn,\n region,\n description: `Internet-facing Application Load Balancer \"${lbName}\" does not have a WAF Web ACL associated. Traffic is not inspected for common web exploits.`,\n impact: \"Without WAF, the ALB is exposed to SQL injection, XSS, and other OWASP Top 10 attacks\",\n remediationSteps: [\n \"Create a WAFv2 Web ACL with managed rule groups (e.g., AWSManagedRulesCommonRuleSet).\",\n \"Associate the Web ACL with the ALB using the REGIONAL scope.\",\n \"Enable WAF logging for visibility into blocked requests.\",\n \"Consider adding rate-based rules to mitigate DDoS at the application layer.\",\n ],\n }),\n );\n }\n } catch (wafErr: unknown) {\n const errMsg = wafErr instanceof Error ? wafErr.message : String(wafErr);\n const errName = wafErr instanceof Error ? (wafErr as any).name ?? \"\" : \"\";\n\n // Handle WAFv2 not available or access denied gracefully\n if (errName === \"WAFNonexistentItemException\") {\n // No Web ACL associated — same as null response\n findings.push(\n makeFinding({\n riskScore: 7.5,\n title: `Internet-facing ALB ${lbName} has no WAF protection`,\n resourceType: \"AWS::ElasticLoadBalancingV2::LoadBalancer\",\n resourceId: lbName,\n resourceArn: lbArn,\n region,\n description: `Internet-facing Application Load Balancer \"${lbName}\" does not have a WAF Web ACL associated. Traffic is not inspected for common web exploits.`,\n impact: \"Without WAF, the ALB is exposed to SQL injection, XSS, and other OWASP Top 10 attacks\",\n remediationSteps: [\n \"Create a WAFv2 Web ACL with managed rule groups (e.g., AWSManagedRulesCommonRuleSet).\",\n \"Associate the Web ACL with the ALB using the REGIONAL scope.\",\n \"Enable WAF logging for visibility into blocked requests.\",\n \"Consider adding rate-based rules to mitigate DDoS at the application layer.\",\n ],\n }),\n );\n } else if (errName === \"AccessDeniedException\" || errName === \"WAFInvalidParameterException\") {\n warnings.push(\n `Could not check WAF for ALB \"${lbName}\": ${errMsg}. Ensure wafv2:GetWebACLForResource permission is granted.`,\n );\n } else {\n warnings.push(`Error checking WAF for ALB \"${lbName}\": ${errMsg}`);\n }\n }\n }\n\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: internetFacing.length,\n findingsCount: findings.length,\n scanTimeMs: Date.now() - startMs,\n findings,\n };\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n const errName = err instanceof Error ? (err as any).name ?? \"\" : \"\";\n\n // If WAFv2 or ELBv2 is not available or access denied, return success with warning\n if (errName === \"AccessDeniedException\" || errName === \"UnrecognizedClientException\") {\n return {\n module: this.moduleName,\n status: \"success\",\n warnings: [`WAF coverage check skipped: ${errMsg}`],\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n\n return {\n module: this.moduleName,\n status: \"error\",\n error: errMsg,\n warnings: warnings.length > 0 ? warnings : undefined,\n resourcesScanned: 0,\n findingsCount: 0,\n scanTimeMs: Date.now() - startMs,\n findings: [],\n };\n }\n }\n}\n","import type { FullScanResult, Finding, Severity } from \"../types.js\";\n\nconst SEVERITY_ICON: Record<Severity, string> = {\n CRITICAL: \"🔴\",\n HIGH: \"🟠\",\n MEDIUM: \"🟡\",\n LOW: \"🟢\",\n};\n\nconst SEVERITY_ORDER: Severity[] = [\"CRITICAL\", \"HIGH\", \"MEDIUM\", \"LOW\"];\n\nfunction formatDuration(start: string, end: string): string {\n const ms = new Date(end).getTime() - new Date(start).getTime();\n if (ms < 1000) return `${ms}ms`;\n const secs = Math.round(ms / 1000);\n if (secs < 60) return `${secs}s`;\n const mins = Math.floor(secs / 60);\n const remainSecs = secs % 60;\n return `${mins}m ${remainSecs}s`;\n}\n\nfunction renderFinding(f: Finding): string {\n const steps = f.remediationSteps\n .map((s, i) => ` ${i + 1}. ${s}`)\n .join(\"\\n\");\n\n return [\n `#### ${f.title}`,\n `- **Resource:** ${f.resourceId} (\\`${f.resourceArn}\\`)`,\n `- **Description:** ${f.description}`,\n `- **Impact:** ${f.impact}`,\n `- **Risk Score:** ${f.riskScore}/10`,\n `- **Remediation:**`,\n steps,\n `- **Priority:** ${f.priority}`,\n ].join(\"\\n\");\n}\n\nexport function generateMarkdownReport(scanResults: FullScanResult): string {\n const { summary, modules, accountId, region, scanStart, scanEnd } =\n scanResults;\n const date = scanStart.split(\"T\")[0];\n const duration = formatDuration(scanStart, scanEnd);\n\n const lines: string[] = [];\n\n lines.push(`# AWS Security Scan Report — ${date}`);\n lines.push(\"\");\n\n // Executive Summary\n lines.push(\"## Executive Summary\");\n lines.push(`- **Account:** ${accountId}`);\n lines.push(`- **Region:** ${region}`);\n lines.push(`- **Scan Duration:** ${duration}`);\n lines.push(\n `- **Total Findings:** ${summary.totalFindings} (🔴 ${summary.critical} Critical | 🟠 ${summary.high} High | 🟡 ${summary.medium} Medium | 🟢 ${summary.low} Low)`,\n );\n lines.push(\"\");\n\n // Edge case: no findings\n if (summary.totalFindings === 0) {\n lines.push(\"## Findings by Severity\");\n lines.push(\"\");\n lines.push(\"✅ No security issues found.\");\n lines.push(\"\");\n } else {\n // Collect all findings\n const allFindings: Finding[] = modules.flatMap((m) => m.findings);\n\n // Group by severity\n const grouped = new Map<Severity, Finding[]>();\n for (const sev of SEVERITY_ORDER) {\n grouped.set(sev, []);\n }\n for (const f of allFindings) {\n grouped.get(f.severity)!.push(f);\n }\n\n lines.push(\"## Findings by Severity\");\n lines.push(\"\");\n\n for (const sev of SEVERITY_ORDER) {\n const findings = grouped.get(sev)!;\n const icon = SEVERITY_ICON[sev];\n lines.push(`### ${icon} ${sev.charAt(0)}${sev.slice(1).toLowerCase()}`);\n lines.push(\"\");\n\n if (findings.length === 0) {\n lines.push(`No ${sev.toLowerCase()} findings.`);\n lines.push(\"\");\n continue;\n }\n\n // Sort by riskScore descending\n findings.sort((a, b) => b.riskScore - a.riskScore);\n for (const f of findings) {\n lines.push(renderFinding(f));\n lines.push(\"\");\n }\n }\n }\n\n // Scan Statistics\n lines.push(\"## Scan Statistics\");\n lines.push(\n \"| Module | Resources Scanned | Findings | Status |\",\n );\n lines.push(\"|--------|------------------|----------|--------|\");\n for (const m of modules) {\n const status = m.status === \"success\" ? \"✅\" : \"❌\";\n lines.push(\n `| ${m.module} | ${m.resourcesScanned} | ${m.findingsCount} | ${status} |`,\n );\n }\n lines.push(\"\");\n\n // Recommendations\n if (summary.totalFindings > 0) {\n const allFindings: Finding[] = modules.flatMap((m) => m.findings);\n allFindings.sort((a, b) => b.riskScore - a.riskScore);\n\n lines.push(\"## Recommendations (Priority Order)\");\n for (let i = 0; i < allFindings.length; i++) {\n const f = allFindings[i];\n lines.push(`${i + 1}. [${f.priority}] ${f.title}: ${f.remediationSteps[0] ?? \"Review and remediate.\"}`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n","import type { FullScanResult, Finding } from \"../types.js\";\n\nexport interface MlpsCheck {\n id: string;\n category: string;\n name: string;\n modules: string[];\n findingPatterns: string[];\n}\n\nexport const MLPS_CHECKS: MlpsCheck[] = [\n // 一、身份鉴别\n {\n id: \"8.1.4.1a\",\n category: \"身份鉴别\",\n name: \"密码策略\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"password policy\", \"password length\", \"complexity\", \"password expiry\", \"reuse prevention\", \"IAM.7\", \"IAM.10\"],\n },\n {\n id: \"8.1.4.1a\",\n category: \"身份鉴别\",\n name: \"密钥轮换\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"access key older\", \"access key rotated\", \"IAM.3\", \"IAM.4\"],\n },\n {\n id: \"8.1.4.1d\",\n category: \"身份鉴别\",\n name: \"双因素认证\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"MFA\", \"IAM.5\", \"IAM.6\"],\n },\n // 二、访问控制\n {\n id: \"8.1.4.2c\",\n category: \"访问控制\",\n name: \"最小权限\",\n modules: [\"iam_privilege_escalation\", \"security_hub_findings\"],\n findingPatterns: [\n \"AdministratorAccess\", \"PowerUserAccess\", \"IAMFullAccess\",\n \"over-permissive\", \"privilege escalation\",\n \"self-grant\", \"iam:*\", \"create admin\", \"Lambda role passing\",\n \"CreateAccessKey\", \"AssumeRole\",\n ],\n },\n {\n id: \"8.1.4.2\",\n category: \"访问控制\",\n name: \"安全组\",\n modules: [\"network_reachability\", \"security_hub_findings\"],\n findingPatterns: [\"allows all ports\", \"allows SSH\", \"allows RDP\", \"MySQL\", \"PostgreSQL\", \"MongoDB\", \"Redis\", \"high-risk port\", \"security group\", \"EC2.18\", \"EC2.19\"],\n },\n // 三、安全审计\n {\n id: \"8.1.4.3a\",\n category: \"安全审计\",\n name: \"审计功能\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"CloudTrail\", \"not enabled\", \"multi-region\", \"not logging\", \"CloudTrail.1\"],\n },\n {\n id: \"8.1.4.3b\",\n category: \"安全审计\",\n name: \"审计完整性\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"log file validation\", \"log integrity\", \"log validation\", \"CloudTrail.4\", \"CloudTrail.5\"],\n },\n {\n id: \"8.1.4.3c\",\n category: \"安全审计\",\n name: \"审计保护\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"CloudTrail\", \"S3 bucket\", \"encryption\", \"versioning\", \"Block Public Access\", \"CloudTrail.6\", \"CloudTrail.7\"],\n },\n // 四、入侵防范\n {\n id: \"8.1.4.4a\",\n category: \"入侵防范\",\n name: \"GuardDuty 威胁检测\",\n modules: [\"service_detection\", \"guardduty_findings\"],\n findingPatterns: [\"GuardDuty\"],\n },\n {\n id: \"8.1.4.4a\",\n category: \"入侵防范\",\n name: \"Inspector 漏洞扫描\",\n modules: [\"service_detection\", \"inspector_findings\"],\n findingPatterns: [\"Inspector\", \"CVE-\"],\n },\n // 五、数据安全\n {\n id: \"8.1.4.5a\",\n category: \"数据安全\",\n name: \"传输加密\",\n modules: [\"ssl_certificate\", \"security_hub_findings\"],\n findingPatterns: [\"HTTPS\", \"TLS\", \"HTTP listener\", \"certificate\", \"ELB.1\"],\n },\n {\n id: \"8.1.4.5b\",\n category: \"数据安全\",\n name: \"S3 存储加密\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"no default encryption\", \"not encrypted\", \"S3.4\"],\n },\n {\n id: \"8.1.4.5b\",\n category: \"数据安全\",\n name: \"EBS 默认加密\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"EBS default encryption\", \"EC2.7\"],\n },\n {\n id: \"8.1.4.5b\",\n category: \"数据安全\",\n name: \"RDS 存储加密\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"storage is not encrypted\", \"RDS.3\"],\n },\n // 六、网络安全\n {\n id: \"8.1.3.1a\",\n category: \"网络安全\",\n name: \"网络架构\",\n modules: [\"security_hub_findings\"],\n findingPatterns: [\"default VPC\", \"EC2.2\"],\n },\n {\n id: \"8.1.3.2a\",\n category: \"网络安全\",\n name: \"边界防护\",\n modules: [\"network_reachability\", \"security_hub_findings\"],\n findingPatterns: [\"allows all ports\", \"allows SSH\", \"allows RDP\", \"security group\", \"EC2.18\", \"EC2.19\"],\n },\n];\n\nexport const CATEGORY_ORDER = [\n \"身份鉴别\",\n \"访问控制\",\n \"安全审计\",\n \"入侵防范\",\n \"数据安全\",\n \"网络安全\",\n];\n\nexport const CATEGORY_SECTION: Record<string, string> = {\n \"身份鉴别\": \"一、身份鉴别\",\n \"访问控制\": \"二、访问控制\",\n \"安全审计\": \"三、安全审计\",\n \"入侵防范\": \"四、入侵防范\",\n \"数据安全\": \"五、数据安全\",\n \"网络安全\": \"六、网络安全\",\n};\n\nexport interface CheckResult {\n check: MlpsCheck;\n status: \"pass\" | \"fail\" | \"unknown\";\n relatedFindings: Finding[];\n}\n\nexport function evaluateCheck(\n check: MlpsCheck,\n allFindings: Finding[],\n scanModules: Array<{ module: string; status: string }>,\n): CheckResult {\n // Verify all required modules ran successfully\n const allModulesPresent = check.modules.every((mod) =>\n scanModules.some((m) => m.module === mod && m.status === \"success\"),\n );\n\n if (!allModulesPresent) {\n return { check, status: \"unknown\", relatedFindings: [] };\n }\n\n // Find findings from the relevant modules that match any of the patterns\n const relatedFindings = allFindings.filter((f) => {\n const moduleMatch = check.modules.some((mod) => f.module === mod);\n if (!moduleMatch) return false;\n\n const text = `${f.title} ${f.description}`.toLowerCase();\n return check.findingPatterns.some((pattern) =>\n text.includes(pattern.toLowerCase()),\n );\n });\n\n return {\n check,\n status: relatedFindings.length === 0 ? \"pass\" : \"fail\",\n relatedFindings,\n };\n}\n\nexport function generateMlps3Report(scanResults: FullScanResult): string {\n const { accountId, region, scanStart } = scanResults;\n const scanTime = scanStart.replace(\"T\", \" \").replace(/\\.\\d+Z$/, \" UTC\");\n\n // Collect all findings with module info\n const allFindings: Finding[] = scanResults.modules.flatMap((m) =>\n m.findings.map((f) => ({ ...f, module: f.module ?? m.module })),\n );\n\n // Evaluate all checks (pass scan module info for missing-module detection)\n const scanModules = scanResults.modules.map((m) => ({\n module: m.module,\n status: m.status,\n }));\n const results = MLPS_CHECKS.map((check) =>\n evaluateCheck(check, allFindings, scanModules),\n );\n\n const passCount = results.filter((r) => r.status === \"pass\").length;\n const failCount = results.filter((r) => r.status === \"fail\").length;\n const unknownCount = results.filter((r) => r.status === \"unknown\").length;\n const checkedTotal = passCount + failCount;\n const total = results.length;\n const percent = checkedTotal > 0 ? Math.round((passCount / checkedTotal) * 100) : 0;\n\n const lines: string[] = [];\n\n // Header\n lines.push(\"# 等保三级预检报告\");\n lines.push(\"> **本报告为等保预检参考,仅覆盖 AWS 云平台配置检查。完整等保测评需由持证测评机构执行。**\");\n lines.push(\"\");\n\n // Account info\n lines.push(\"## 账户信息\");\n lines.push(`- Account: ${accountId} | Region: ${region} | 扫描时间: ${scanTime}`);\n lines.push(\"\");\n\n // Summary\n lines.push(\"## 预检总览\");\n lines.push(`- 检查项: ${total} | 通过: ${passCount} | 不通过: ${failCount}${unknownCount > 0 ? ` | 未检查: ${unknownCount}` : \"\"}`);\n lines.push(`- 通过率: ${percent}%${unknownCount > 0 ? \"(未检查项不计入通过率)\" : \"\"}`);\n lines.push(\"\");\n\n // Group results by category\n for (const category of CATEGORY_ORDER) {\n const sectionTitle = CATEGORY_SECTION[category];\n const categoryResults = results.filter((r) => r.check.category === category);\n if (categoryResults.length === 0) continue;\n\n lines.push(`## ${sectionTitle}`);\n lines.push(\"\");\n\n // Group by check ID within category\n const byId = new Map<string, CheckResult[]>();\n for (const r of categoryResults) {\n const existing = byId.get(r.check.id) ?? [];\n existing.push(r);\n byId.set(r.check.id, existing);\n }\n\n for (const [checkId, checkResults] of byId) {\n lines.push(`### ${checkId} ${checkResults[0].check.name}`);\n for (const r of checkResults) {\n const icon = r.status === \"pass\" ? \"\\u2705\" : r.status === \"fail\" ? \"\\u274c\" : \"\\u26a0\\ufe0f\";\n const label = r.status === \"unknown\" ? \" 未检查\" : \"\";\n lines.push(`- [${icon}] ${r.check.name}${label}`);\n if (r.status === \"fail\" && r.relatedFindings.length > 0) {\n for (const f of r.relatedFindings.slice(0, 3)) {\n lines.push(` - ${f.severity}: ${f.title}`);\n }\n if (r.relatedFindings.length > 3) {\n lines.push(` - ... 及其他 ${r.relatedFindings.length - 3} 项`);\n }\n }\n }\n lines.push(\"\");\n }\n }\n\n // Remediation recommendations sorted by priority\n const failedResults = results.filter((r) => r.status === \"fail\");\n if (failedResults.length > 0) {\n lines.push(\"## 建议整改项(按优先级)\");\n lines.push(\"\");\n\n // Collect all related findings from failed checks, deduplicate, sort by riskScore\n const allFailedFindings = new Map<string, Finding>();\n for (const r of failedResults) {\n for (const f of r.relatedFindings) {\n const key = `${f.resourceId}:${f.title}`;\n if (!allFailedFindings.has(key)) {\n allFailedFindings.set(key, f);\n }\n }\n }\n\n const sorted = [...allFailedFindings.values()].sort(\n (a, b) => b.riskScore - a.riskScore,\n );\n\n for (let i = 0; i < sorted.length; i++) {\n const f = sorted[i];\n const priority = f.riskScore >= 9.0 ? \"P0\" : f.riskScore >= 7.0 ? \"P1\" : f.riskScore >= 4.0 ? \"P2\" : \"P3\";\n const remediation = f.remediationSteps[0] ?? \"Review and remediate.\";\n lines.push(`${i + 1}. [${priority}] ${f.title} — ${remediation}`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n","import type { FullScanResult, Finding, Severity, DashboardHistoryEntry, ScanResult } from \"../types.js\";\nimport {\n MLPS_CHECKS,\n CATEGORY_ORDER,\n CATEGORY_SECTION,\n evaluateCheck,\n} from \"./mlps-report.js\";\nimport { VERSION } from \"../version.js\";\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction esc(s: string): string {\n return s\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction calcScore(summary: FullScanResult[\"summary\"]): number {\n const raw =\n 100 -\n summary.critical * 15 -\n summary.high * 5 -\n summary.medium * 2 -\n summary.low * 0.5;\n return Math.max(0, Math.min(100, Math.round(raw)));\n}\n\nfunction formatDuration(start: string, end: string): string {\n const ms = new Date(end).getTime() - new Date(start).getTime();\n if (ms < 1000) return `${ms}ms`;\n const secs = Math.round(ms / 1000);\n if (secs < 60) return `${secs}s`;\n return `${Math.floor(secs / 60)}m ${secs % 60}s`;\n}\n\nconst SEV_COLOR: Record<Severity, string> = {\n CRITICAL: \"#ef4444\",\n HIGH: \"#f97316\",\n MEDIUM: \"#eab308\",\n LOW: \"#22c55e\",\n};\n\nconst SEVERITY_ORDER: Severity[] = [\"CRITICAL\", \"HIGH\", \"MEDIUM\", \"LOW\"];\n\nfunction scoreColor(score: number): string {\n if (score >= 80) return \"#22c55e\";\n if (score >= 50) return \"#eab308\";\n return \"#ef4444\";\n}\n\n// ---------------------------------------------------------------------------\n// Service Dependency Reminder\n// ---------------------------------------------------------------------------\n\nconst SERVICE_RECOMMENDATIONS: Record<string, { icon: string; service: string; impact: string; action: string }> = {\n security_hub_findings: {\n icon: \"\\ud83d\\udd34\",\n service: \"Security Hub\",\n impact: \"\\u65e0\\u6cd5\\u83b7\\u53d6 300+ \\u9879\\u81ea\\u52a8\\u5316\\u5b89\\u5168\\u68c0\\u67e5\\uff08FSBP/CIS/PCI DSS \\u6807\\u51c6\\uff09\",\n action: \"\\u542f\\u7528 Security Hub \\u83b7\\u5f97\\u6700\\u5168\\u9762\\u7684\\u5b89\\u5168\\u6001\\u52bf\\u8bc4\\u4f30\",\n },\n guardduty_findings: {\n icon: \"\\ud83d\\udd34\",\n service: \"GuardDuty\",\n impact: \"\\u65e0\\u6cd5\\u68c0\\u6d4b\\u5a01\\u80c1\\u6d3b\\u52a8\\uff08\\u6076\\u610f IP\\u3001\\u5f02\\u5e38 API \\u8c03\\u7528\\u3001\\u52a0\\u5bc6\\u8d27\\u5e01\\u6316\\u77ff\\u7b49\\uff09\",\n action: \"\\u542f\\u7528 GuardDuty \\u83b7\\u5f97\\u6301\\u7eed\\u5a01\\u80c1\\u68c0\\u6d4b\\u80fd\\u529b\",\n },\n inspector_findings: {\n icon: \"\\ud83d\\udfe1\",\n service: \"Inspector\",\n impact: \"\\u65e0\\u6cd5\\u626b\\u63cf EC2/Lambda/\\u5bb9\\u5668\\u7684\\u8f6f\\u4ef6\\u6f0f\\u6d1e\\uff08CVE\\uff09\",\n action: \"\\u542f\\u7528 Inspector \\u53d1\\u73b0\\u5df2\\u77e5\\u5b89\\u5168\\u6f0f\\u6d1e\",\n },\n trusted_advisor_findings: {\n icon: \"\\ud83d\\udfe1\",\n service: \"Trusted Advisor\",\n impact: \"\\u65e0\\u6cd5\\u83b7\\u53d6 AWS \\u6700\\u4f73\\u5b9e\\u8df5\\u5b89\\u5168\\u68c0\\u67e5\",\n action: \"\\u5347\\u7ea7\\u81f3 Business/Enterprise Support \\u8ba1\\u5212\\u4ee5\\u4f7f\\u7528 Trusted Advisor \\u5b89\\u5168\\u68c0\\u67e5\",\n },\n config_rules_findings: {\n icon: \"\\ud83d\\udfe1\",\n service: \"AWS Config\",\n impact: \"\\u65e0\\u6cd5\\u68c0\\u67e5\\u8d44\\u6e90\\u914d\\u7f6e\\u5408\\u89c4\\u72b6\\u6001\",\n action: \"\\u542f\\u7528 AWS Config \\u5e76\\u914d\\u7f6e Config Rules\",\n },\n access_analyzer_findings: {\n icon: \"\\ud83d\\udfe1\",\n service: \"IAM Access Analyzer\",\n impact: \"\\u65e0\\u6cd5\\u68c0\\u6d4b\\u8d44\\u6e90\\u662f\\u5426\\u88ab\\u5916\\u90e8\\u8d26\\u53f7\\u6216\\u516c\\u7f51\\u8bbf\\u95ee\",\n action: \"\\u521b\\u5efa IAM Access Analyzer\\uff08\\u8d26\\u6237\\u7ea7\\u6216\\u7ec4\\u7ec7\\u7ea7\\uff09\",\n },\n patch_compliance_findings: {\n icon: \"\\ud83d\\udfe1\",\n service: \"SSM Patch Manager\",\n impact: \"\\u65e0\\u6cd5\\u68c0\\u67e5\\u5b9e\\u4f8b\\u8865\\u4e01\\u5408\\u89c4\\u72b6\\u6001\",\n action: \"\\u5b89\\u88c5 SSM Agent \\u5e76\\u914d\\u7f6e Patch Manager\",\n },\n};\n\nconst SERVICE_NOT_ENABLED_PATTERNS = [\n \"not enabled\",\n \"not found\",\n \"No IAM Access Analyzer\",\n \"No SSM-managed instances\",\n \"requires AWS Business or Enterprise Support\",\n \"not available\",\n \"is not enabled\",\n];\n\nfunction getDisabledServices(modules: ScanResult[]): Array<{ icon: string; service: string; impact: string; action: string }> {\n const disabled: Array<{ icon: string; service: string; impact: string; action: string }> = [];\n for (const mod of modules) {\n const rec = SERVICE_RECOMMENDATIONS[mod.module];\n if (!rec) continue;\n if (!mod.warnings?.length) continue;\n const hasNotEnabled = mod.warnings.some((w) =>\n SERVICE_NOT_ENABLED_PATTERNS.some((p) => w.includes(p)),\n );\n if (hasNotEnabled) {\n disabled.push(rec);\n }\n }\n return disabled;\n}\n\nfunction buildServiceReminderHtml(modules: ScanResult[]): string {\n const disabled = getDisabledServices(modules);\n if (disabled.length === 0) return \"\";\n\n const items = disabled.map((svc) => `\n <div style=\"margin-bottom:12px\">\n <div style=\"font-weight:600;font-size:15px\">${esc(svc.icon)} ${esc(svc.service)} \\u672a\\u542f\\u7528</div>\n <div style=\"margin-left:28px;color:#cbd5e1;font-size:13px\">\\u5f71\\u54cd\\uff1a${esc(svc.impact)}</div>\n <div style=\"margin-left:28px;color:#cbd5e1;font-size:13px\">\\u5efa\\u8bae\\uff1a${esc(svc.action)}</div>\n </div>`).join(\"\\n\");\n\n return `\n <section>\n <div style=\"background:#2d1f00;border:1px solid #b45309;border-radius:8px;padding:20px;margin-bottom:32px\">\n <div style=\"font-size:17px;font-weight:700;margin-bottom:12px\">&#9889; \\u4ee5\\u4e0b\\u5b89\\u5168\\u670d\\u52a1\\u672a\\u542f\\u7528\\uff0c\\u90e8\\u5206\\u68c0\\u67e5\\u65e0\\u6cd5\\u6267\\u884c\\uff1a</div>\n ${items}\n <div style=\"margin-top:12px;font-size:13px;color:#fbbf24;font-weight:500\">\\u542f\\u7528\\u4ee5\\u4e0a\\u670d\\u52a1\\u540e\\u91cd\\u65b0\\u626b\\u63cf\\u53ef\\u83b7\\u5f97\\u66f4\\u5b8c\\u6574\\u7684\\u5b89\\u5168\\u8bc4\\u4f30\\u3002</div>\n </div>\n </section>`;\n}\n\n// ---------------------------------------------------------------------------\n// CSS\n// ---------------------------------------------------------------------------\n\nfunction sharedCss(): string {\n return `\n *{margin:0;padding:0;box-sizing:border-box}\n body{background:#0f172a;color:#f8fafc;font-family:Inter,system-ui,-apple-system,sans-serif;line-height:1.6;font-size:14px}\n .container{max-width:900px;margin:0 auto;padding:40px 24px}\n header{text-align:center;margin-bottom:40px;border-bottom:1px solid #334155;padding-bottom:24px}\n header h1{font-size:28px;font-weight:700;margin-bottom:8px;letter-spacing:-0.5px}\n .meta{color:#94a3b8;font-size:13px}\n .disclaimer{color:#94a3b8;font-size:12px;font-style:italic;margin-top:8px;max-width:640px;margin-left:auto;margin-right:auto}\n h2{font-size:20px;font-weight:600;margin:32px 0 16px;padding-bottom:8px;border-bottom:1px solid #334155}\n h3{font-size:16px;font-weight:600;margin:16px 0 8px}\n h4{font-size:14px;font-weight:600;margin:12px 0 4px}\n .card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:20px;margin-bottom:16px}\n .summary{display:flex;gap:24px;margin-bottom:32px;flex-wrap:wrap}\n .score-card{background:#1e293b;border:1px solid #334155;border-radius:12px;padding:24px 32px;text-align:center;flex:0 0 auto}\n .score-value{font-size:48px;font-weight:700}\n .score-label{color:#94a3b8;font-size:13px;margin-top:4px}\n .severity-stats{display:flex;gap:12px;flex-wrap:wrap;flex:1;align-items:center;justify-content:center}\n .stat-card{border-radius:8px;padding:16px 20px;text-align:center;min-width:100px;border:1px solid #334155;background:#1e293b}\n .stat-count{font-size:28px;font-weight:700}\n .stat-label{font-size:12px;color:#94a3b8;margin-top:2px}\n .stat-critical .stat-count{color:#ef4444}\n .stat-high .stat-count{color:#f97316}\n .stat-medium .stat-count{color:#eab308}\n .stat-low .stat-count{color:#22c55e}\n .charts{display:flex;gap:24px;margin-bottom:32px;flex-wrap:wrap;justify-content:center}\n .chart-box{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:20px;flex:1;min-width:280px}\n .chart-title{font-size:14px;font-weight:600;margin-bottom:12px;text-align:center;color:#cbd5e1}\n .sev-critical{border-left-color:#ef4444}\n .sev-high{border-left-color:#f97316}\n .sev-medium{border-left-color:#eab308}\n .sev-low{border-left-color:#22c55e}\n .badge{display:inline-block;padding:2px 10px;border-radius:4px;font-size:11px;font-weight:700;letter-spacing:0.5px;color:#fff}\n .badge-critical{background:#ef4444}\n .badge-high{background:#f97316}\n .badge-medium{background:#eab308;color:#1e293b}\n .badge-low{background:#22c55e;color:#1e293b}\n .finding-title{font-size:15px;font-weight:600;margin-bottom:8px}\n .finding-detail{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n .finding-detail strong{color:#f8fafc}\n .remediation-steps{margin-top:8px;padding-left:20px}\n .remediation-steps li{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n table{width:100%;border-collapse:collapse;margin-bottom:16px}\n th{background:#334155;color:#f8fafc;padding:10px 12px;text-align:left;font-size:13px;font-weight:600}\n td{padding:8px 12px;border-bottom:1px solid #334155;font-size:13px;color:#cbd5e1}\n tr:hover td{background:rgba(51,65,85,0.3)}\n .recommendations ol{padding-left:24px}\n .recommendations li{margin-bottom:8px;color:#cbd5e1;font-size:13px}\n .priority-p0{color:#ef4444;font-weight:700}\n .priority-p1{color:#f97316;font-weight:700}\n .priority-p2{color:#eab308;font-weight:700}\n .priority-p3{color:#22c55e;font-weight:700}\n footer{margin-top:48px;padding-top:24px;border-top:1px solid #334155;text-align:center}\n footer p{color:#64748b;font-size:12px;margin-bottom:4px}\n .check-item{display:flex;align-items:flex-start;gap:8px;padding:8px 12px;border-radius:6px;margin-bottom:4px;font-size:14px}\n .check-pass{background:rgba(34,197,94,0.1)}\n .check-fail{background:rgba(239,68,68,0.1)}\n .check-unknown{background:rgba(148,163,184,0.1)}\n .check-icon{font-size:16px;flex-shrink:0}\n .check-name{font-weight:500}\n .check-findings{margin-left:28px;margin-top:4px}\n .check-findings li{color:#94a3b8;font-size:12px;margin-bottom:2px;list-style:none}\n .no-findings{text-align:center;padding:40px;color:#22c55e;font-size:18px;font-weight:600}\n .finding-fold{background:#1e293b;border:1px solid #334155;border-radius:8px;margin-bottom:12px;border-left:4px solid;overflow:hidden}\n .finding-fold>summary{cursor:pointer;padding:12px 20px;display:flex;align-items:center;gap:12px;list-style:none;user-select:none}\n .finding-fold>summary::-webkit-details-marker{display:none}\n .finding-fold>summary::marker{content:\"\"}\n .finding-fold>summary .badge{margin-bottom:0}\n .finding-fold>summary::after{content:\"\\\\25B6\";font-size:10px;color:#64748b;flex-shrink:0;transition:transform 0.2s}\n .finding-fold[open]>summary::after{transform:rotate(90deg)}\n .finding-fold[open]>summary{border-bottom:1px solid #334155}\n .finding-body{padding:12px 20px 16px}\n .finding-summary-title{font-weight:600;font-size:14px;flex:1}\n .finding-summary-score{color:#94a3b8;font-size:13px;font-weight:600;white-space:nowrap}\n .top5-card{display:flex;gap:16px;background:#1e293b;border:1px solid #334155;border-radius:12px;padding:24px;margin-bottom:16px;border-left:4px solid}\n .top5-card .badge{margin-bottom:0}\n .top5-rank{font-size:28px;font-weight:800;color:#475569;min-width:44px;display:flex;align-items:flex-start;justify-content:center}\n .top5-content{flex:1}\n .top5-title{font-size:17px;font-weight:700;margin:8px 0}\n .top5-detail{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n .top5-detail strong{color:#f8fafc}\n .top5-remediation{margin-top:8px;padding-left:20px}\n .top5-remediation li{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n .trend-section{margin-bottom:32px}\n .trend-chart{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:20px;margin-bottom:16px}\n .trend-title{font-size:14px;font-weight:600;margin-bottom:12px;text-align:center;color:#cbd5e1}\n .category-fold{background:#1e293b;border:1px solid #334155;border-radius:8px;margin-bottom:16px;overflow:hidden}\n .category-fold>summary{cursor:pointer;padding:16px 20px;display:flex;align-items:center;gap:12px;list-style:none;font-size:18px;font-weight:600;user-select:none}\n .category-fold>summary::-webkit-details-marker{display:none}\n .category-fold>summary::marker{content:\"\"}\n .category-fold>summary::after{content:\"\\\\25B6\";font-size:12px;color:#64748b;flex-shrink:0;transition:transform 0.2s}\n .category-fold[open]>summary::after{transform:rotate(90deg)}\n .category-fold[open]>summary{border-bottom:1px solid #334155}\n .category-body{padding:12px 20px 16px}\n .category-title{flex:1}\n .category-stats{display:inline-flex;gap:12px;font-size:13px}\n .category-stat-pass{color:#22c55e}\n .category-stat-fail{color:#ef4444}\n .category-stat-unknown{color:#94a3b8}\n .module-fold{background:#1e293b;border:1px solid #334155;border-radius:8px;margin-bottom:16px;overflow:hidden}\n .module-fold>summary{cursor:pointer;padding:16px 20px;display:flex;align-items:center;gap:12px;list-style:none;user-select:none;flex-wrap:wrap}\n .module-fold>summary::-webkit-details-marker{display:none}\n .module-fold>summary::marker{content:\"\"}\n .module-fold>summary h3{margin:0;font-size:16px}\n .module-fold>summary::after{content:\"\\\\25B6\";font-size:12px;color:#64748b;flex-shrink:0;transition:transform 0.2s;margin-left:auto}\n .module-fold[open]>summary::after{transform:rotate(90deg)}\n .module-fold[open]>summary{border-bottom:1px solid #334155}\n .module-body{padding:12px 20px 16px}\n .module-badges{display:inline-flex;gap:6px;flex-wrap:wrap}\n .severity-group{margin-bottom:16px}\n .severity-group-fold{margin-bottom:16px}\n .severity-group-fold>summary{cursor:pointer;padding:4px 0;list-style:none;user-select:none}\n .severity-group-fold>summary::-webkit-details-marker{display:none}\n .severity-group-fold>summary::marker{content:\"\"}\n .severity-group-fold>summary h4{margin:0;display:inline}\n .finding-card{display:flex;align-items:center;gap:8px;padding:8px 12px;margin-bottom:4px;border-radius:6px;border-left:4px solid #334155;background:rgba(30,41,59,0.5);flex-wrap:wrap}\n .finding-title-text{font-weight:600;font-size:13px;flex:1;min-width:200px}\n .finding-resource{color:#94a3b8;font-size:12px;max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n .finding-card>details{width:100%;margin-top:4px}\n .finding-card>details>summary{cursor:pointer;font-size:12px;color:#60a5fa;user-select:none}\n .finding-card-body{padding:8px 0}\n .finding-card-body p{color:#cbd5e1;font-size:13px;margin-bottom:4px}\n .finding-card-body ol{padding-left:20px}\n .finding-card-body li{color:#cbd5e1;font-size:13px;margin-bottom:2px}\n .rec-fold{background:#1e293b;border:1px solid #334155;border-radius:8px;margin-bottom:16px;overflow:hidden}\n .rec-fold>summary{cursor:pointer;padding:16px 20px;display:flex;align-items:center;gap:12px;list-style:none;user-select:none}\n .rec-fold>summary::-webkit-details-marker{display:none}\n .rec-fold>summary::marker{content:\"\"}\n .rec-fold>summary::after{content:\"\\\\25B6\";font-size:12px;color:#64748b;flex-shrink:0;transition:transform 0.2s;margin-left:auto}\n .rec-fold[open]>summary::after{transform:rotate(90deg)}\n .rec-fold[open]>summary{border-bottom:1px solid #334155}\n .rec-body{padding:12px 20px 16px}\n .rec-body ol{padding-left:24px}\n .rec-body li{margin-bottom:8px;color:#cbd5e1;font-size:13px}\n .rec-body .badge{margin-right:6px;vertical-align:middle}\n @media print{\n body{background:#fff;color:#1e293b;-webkit-print-color-adjust:exact;print-color-adjust:exact}\n .container{max-width:100%;padding:20px}\n .card,.score-card,.stat-card,.chart-box,.finding-fold,.top5-card,.trend-chart,.category-fold,.module-fold,.finding-card,.rec-fold{background:#fff;border:1px solid #e2e8f0}\n .badge{border:1px solid}\n header{border-bottom-color:#e2e8f0}\n h2{border-bottom-color:#e2e8f0}\n th{background:#f1f5f9;color:#1e293b}\n td{border-bottom-color:#e2e8f0;color:#475569}\n footer{border-top-color:#e2e8f0}\n .meta,.disclaimer{color:#64748b}\n .finding-detail,.top5-detail{color:#475569}\n .finding-detail strong,.top5-detail strong{color:#1e293b}\n .stat-label,.score-label{color:#64748b}\n .chart-title,.trend-title{color:#475569}\n .remediation-steps li,.top5-remediation li{color:#475569}\n .recommendations li{color:#475569}\n .finding-card-body p,.finding-card-body li{color:#475569}\n .finding-title-text{color:#1e293b}\n .finding-resource{color:#64748b}\n .check-findings li{color:#64748b}\n .finding-fold,.top5-card,.category-fold,.module-fold,.finding-card,.rec-fold{break-inside:avoid}\n .check-item{break-inside:avoid}\n svg text{fill:#1e293b !important}\n .finding-fold[open]>summary,.category-fold[open]>summary,.module-fold[open]>summary,.rec-fold[open]>summary{border-bottom-color:#e2e8f0}\n details{display:block}\n details>summary{display:block}\n details>:not(summary){display:block !important}\n }\n `;\n}\n\n// ---------------------------------------------------------------------------\n// SVG Charts\n// ---------------------------------------------------------------------------\n\nfunction donutChart(summary: FullScanResult[\"summary\"]): string {\n const total = summary.totalFindings;\n const r = 80;\n const circ = 2 * Math.PI * r; // ~502.65\n\n if (total === 0) {\n return [\n '<svg viewBox=\"0 0 200 200\" width=\"200\" height=\"200\">',\n ' <circle cx=\"100\" cy=\"100\" r=\"80\" fill=\"none\" stroke=\"#334155\" stroke-width=\"20\"/>',\n ' <text x=\"100\" y=\"105\" text-anchor=\"middle\" fill=\"#22c55e\" font-size=\"24\" font-weight=\"700\">0</text>',\n \"</svg>\",\n ].join(\"\\n\");\n }\n\n const segments: Array<{ count: number; color: string }> = [\n { count: summary.critical, color: SEV_COLOR.CRITICAL },\n { count: summary.high, color: SEV_COLOR.HIGH },\n { count: summary.medium, color: SEV_COLOR.MEDIUM },\n { count: summary.low, color: SEV_COLOR.LOW },\n ].filter((s) => s.count > 0);\n\n let offset = 0;\n const circles = segments.map((s) => {\n const arc = (s.count / total) * circ;\n const el = `<circle cx=\"100\" cy=\"100\" r=\"80\" fill=\"none\" stroke=\"${s.color}\" stroke-width=\"20\" stroke-dasharray=\"${arc.toFixed(2)} ${(circ - arc).toFixed(2)}\" stroke-dashoffset=\"${(-offset).toFixed(2)}\" transform=\"rotate(-90 100 100)\"/>`;\n offset += arc;\n return el;\n });\n\n return [\n '<svg viewBox=\"0 0 200 200\" width=\"200\" height=\"200\">',\n ...circles.map((c) => ` ${c}`),\n ` <text x=\"100\" y=\"105\" text-anchor=\"middle\" fill=\"#f8fafc\" font-size=\"28\" font-weight=\"700\">${total}</text>`,\n \"</svg>\",\n ].join(\"\\n\");\n}\n\nfunction barChart(modules: FullScanResult[\"modules\"]): string {\n const withFindings = modules\n .filter((m) => m.findingsCount > 0)\n .sort((a, b) => b.findingsCount - a.findingsCount)\n .slice(0, 12);\n\n if (withFindings.length === 0) {\n return [\n '<svg viewBox=\"0 0 400 50\" width=\"100%\">',\n ' <text x=\"200\" y=\"30\" text-anchor=\"middle\" fill=\"#22c55e\" font-size=\"14\" font-weight=\"600\">All modules clean</text>',\n \"</svg>\",\n ].join(\"\\n\");\n }\n\n const maxCount = withFindings[0].findingsCount;\n const barH = 22;\n const gap = 6;\n const labelW = 160;\n const maxBarW = 190;\n const height = withFindings.length * (barH + gap);\n\n const bars = withFindings.map((m, i) => {\n const y = i * (barH + gap);\n const w = Math.max(4, (m.findingsCount / maxCount) * maxBarW);\n const worstSev = m.findings.reduce<Severity>((worst, f) => {\n const idx = SEVERITY_ORDER.indexOf(f.severity);\n return idx < SEVERITY_ORDER.indexOf(worst) ? f.severity : worst;\n }, \"LOW\");\n const color = SEV_COLOR[worstSev];\n return [\n `<text x=\"${labelW - 8}\" y=\"${y + barH / 2 + 4}\" text-anchor=\"end\" fill=\"#94a3b8\" font-size=\"11\">${esc(m.module)}</text>`,\n `<rect x=\"${labelW}\" y=\"${y}\" width=\"${w.toFixed(1)}\" height=\"${barH}\" rx=\"3\" fill=\"${color}\" opacity=\"0.85\"/>`,\n `<text x=\"${labelW + w + 6}\" y=\"${y + barH / 2 + 4}\" fill=\"#f8fafc\" font-size=\"11\">${m.findingsCount}</text>`,\n ].join(\"\\n\");\n });\n\n return [\n `<svg viewBox=\"0 0 400 ${height}\" width=\"100%\">`,\n ...bars,\n \"</svg>\",\n ].join(\"\\n\");\n}\n\nfunction findingsTrendChart(history: DashboardHistoryEntry[]): string {\n const entries = history.slice(-30);\n if (entries.length < 2) return \"\";\n\n const W = 800;\n const H = 260;\n const pad = { top: 30, right: 20, bottom: 50, left: 50 };\n const plotW = W - pad.left - pad.right;\n const plotH = H - pad.top - pad.bottom;\n\n const maxVal = Math.max(\n 1,\n ...entries.flatMap((e) => [e.critical, e.high, e.medium, e.low]),\n );\n\n const xPos = (i: number) =>\n pad.left + (i / Math.max(1, entries.length - 1)) * plotW;\n const yPos = (v: number) => pad.top + plotH - (v / maxVal) * plotH;\n\n const lines: Array<{\n key: \"critical\" | \"high\" | \"medium\" | \"low\";\n color: string;\n label: string;\n }> = [\n { key: \"critical\", color: \"#ef4444\", label: \"Critical\" },\n { key: \"high\", color: \"#f97316\", label: \"High\" },\n { key: \"medium\", color: \"#eab308\", label: \"Medium\" },\n { key: \"low\", color: \"#22c55e\", label: \"Low\" },\n ];\n\n const polylines = lines\n .map((line) => {\n const pts = entries\n .map(\n (e, i) =>\n `${xPos(i).toFixed(1)},${yPos(e[line.key]).toFixed(1)}`,\n )\n .join(\" \");\n return `<polyline points=\"${pts}\" fill=\"none\" stroke=\"${line.color}\" stroke-width=\"2\" stroke-linejoin=\"round\"/>`;\n })\n .join(\"\\n \");\n\n const xLabels = entries\n .map((e, i) => {\n if (i % 5 !== 0 && i !== entries.length - 1) return \"\";\n return `<text x=\"${xPos(i).toFixed(1)}\" y=\"${H - 8}\" text-anchor=\"middle\" fill=\"#94a3b8\" font-size=\"10\">${e.date.slice(5)}</text>`;\n })\n .filter(Boolean)\n .join(\"\\n \");\n\n const ySteps = 5;\n const yLabels = Array.from({ length: ySteps + 1 }, (_, i) => {\n const val = Math.round((maxVal / ySteps) * i);\n return [\n `<text x=\"${pad.left - 8}\" y=\"${yPos(val).toFixed(1)}\" text-anchor=\"end\" fill=\"#94a3b8\" font-size=\"10\" dominant-baseline=\"middle\">${val}</text>`,\n `<line x1=\"${pad.left}\" y1=\"${yPos(val).toFixed(1)}\" x2=\"${W - pad.right}\" y2=\"${yPos(val).toFixed(1)}\" stroke=\"#334155\" stroke-width=\"0.5\"/>`,\n ].join(\"\\n \");\n }).join(\"\\n \");\n\n const legend = lines\n .map((line, i) => {\n const lx = pad.left + i * 110;\n return `<rect x=\"${lx}\" y=\"8\" width=\"14\" height=\"3\" rx=\"1\" fill=\"${line.color}\"/><text x=\"${lx + 18}\" y=\"12\" fill=\"#94a3b8\" font-size=\"10\">${line.label}</text>`;\n })\n .join(\"\\n \");\n\n return [\n `<svg viewBox=\"0 0 ${W} ${H}\" width=\"100%\" preserveAspectRatio=\"xMidYMid meet\">`,\n ` ${legend}`,\n ` ${yLabels}`,\n ` ${polylines}`,\n ` ${xLabels}`,\n \"</svg>\",\n ].join(\"\\n\");\n}\n\nfunction scoreTrendChart(history: DashboardHistoryEntry[]): string {\n const entries = history.slice(-30);\n if (entries.length < 2) return \"\";\n\n const W = 800;\n const H = 220;\n const pad = { top: 20, right: 20, bottom: 50, left: 50 };\n const plotW = W - pad.left - pad.right;\n const plotH = H - pad.top - pad.bottom;\n\n const xPos = (i: number) =>\n pad.left + (i / Math.max(1, entries.length - 1)) * plotW;\n const yPos = (v: number) => pad.top + plotH - (v / 100) * plotH;\n\n const pts = entries\n .map((e, i) => `${xPos(i).toFixed(1)},${yPos(e.score).toFixed(1)}`)\n .join(\" \");\n\n const zones = [\n `<rect x=\"${pad.left}\" y=\"${yPos(100).toFixed(1)}\" width=\"${plotW}\" height=\"${(yPos(80) - yPos(100)).toFixed(1)}\" fill=\"#22c55e\" opacity=\"0.06\"/>`,\n `<rect x=\"${pad.left}\" y=\"${yPos(80).toFixed(1)}\" width=\"${plotW}\" height=\"${(yPos(50) - yPos(80)).toFixed(1)}\" fill=\"#eab308\" opacity=\"0.06\"/>`,\n `<rect x=\"${pad.left}\" y=\"${yPos(50).toFixed(1)}\" width=\"${plotW}\" height=\"${(yPos(0) - yPos(50)).toFixed(1)}\" fill=\"#ef4444\" opacity=\"0.06\"/>`,\n ].join(\"\\n \");\n\n const xLabels = entries\n .map((e, i) => {\n if (i % 5 !== 0 && i !== entries.length - 1) return \"\";\n return `<text x=\"${xPos(i).toFixed(1)}\" y=\"${H - 8}\" text-anchor=\"middle\" fill=\"#94a3b8\" font-size=\"10\">${e.date.slice(5)}</text>`;\n })\n .filter(Boolean)\n .join(\"\\n \");\n\n const yVals = [0, 25, 50, 75, 100];\n const yLabels = yVals\n .map(\n (val) =>\n `<text x=\"${pad.left - 8}\" y=\"${yPos(val).toFixed(1)}\" text-anchor=\"end\" fill=\"#94a3b8\" font-size=\"10\" dominant-baseline=\"middle\">${val}</text>\\n <line x1=\"${pad.left}\" y1=\"${yPos(val).toFixed(1)}\" x2=\"${W - pad.right}\" y2=\"${yPos(val).toFixed(1)}\" stroke=\"#334155\" stroke-width=\"0.5\"/>`,\n )\n .join(\"\\n \");\n\n return [\n `<svg viewBox=\"0 0 ${W} ${H}\" width=\"100%\" preserveAspectRatio=\"xMidYMid meet\">`,\n ` ${zones}`,\n ` ${yLabels}`,\n ` <polyline points=\"${pts}\" fill=\"none\" stroke=\"#60a5fa\" stroke-width=\"2.5\" stroke-linejoin=\"round\"/>`,\n ` ${xLabels}`,\n \"</svg>\",\n ].join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// General HTML Report\n// ---------------------------------------------------------------------------\n\nexport function generateHtmlReport(\n scanResults: FullScanResult,\n history?: DashboardHistoryEntry[],\n): string {\n const { summary, modules, accountId, region, scanStart, scanEnd } =\n scanResults;\n const date = scanStart.split(\"T\")[0];\n const duration = formatDuration(scanStart, scanEnd);\n const score = calcScore(summary);\n\n const allFindings: Finding[] = modules.flatMap((m) =>\n m.findings.map((f) => ({ ...f, module: f.module ?? m.module })),\n );\n\n // --- Top 5 Findings ---\n let top5Html = \"\";\n if (allFindings.length > 0) {\n const top5 = [...allFindings]\n .sort((a, b) => b.riskScore - a.riskScore)\n .slice(0, 5);\n const cards = top5\n .map(\n (f, i) => `\n <div class=\"top5-card sev-${esc(f.severity.toLowerCase())}\">\n <div class=\"top5-rank\">#${i + 1}</div>\n <div class=\"top5-content\">\n <span class=\"badge badge-${esc(f.severity.toLowerCase())}\">${esc(f.severity)}</span>\n <div class=\"top5-title\">${esc(f.title)}</div>\n <div class=\"top5-detail\"><strong>Resource:</strong> ${esc(f.resourceId)}</div>\n <div class=\"top5-detail\"><strong>Impact:</strong> ${esc(f.impact)}</div>\n <div class=\"top5-detail\"><strong>Risk Score:</strong> ${f.riskScore}/10</div>\n <h4>Remediation</h4>\n <ol class=\"top5-remediation\">${f.remediationSteps.map((s) => `<li>${esc(s)}</li>`).join(\"\")}</ol>\n </div>\n </div>`,\n )\n .join(\"\\n\");\n top5Html = `\n <section>\n <h2>Top ${top5.length} Highest Risk Findings</h2>\n ${cards}\n </section>`;\n }\n\n // --- Findings HTML (grouped by module, then severity) ---\n let findingsHtml: string;\n if (summary.totalFindings === 0) {\n findingsHtml = '<div class=\"no-findings\">No security issues found.</div>';\n } else {\n const FOLD_THRESHOLD = 20;\n\n const renderCard = (f: Finding): string => {\n const sev = f.severity.toLowerCase();\n return `<div class=\"finding-card sev-${esc(sev)}\">\n <span class=\"badge badge-${esc(sev)}\">${esc(f.severity)}</span>\n <span class=\"finding-title-text\">${esc(f.title)}</span>\n <span class=\"finding-resource\">${esc(f.resourceArn || f.resourceId)}</span>\n <details><summary>Details</summary><div class=\"finding-card-body\">\n <p>${esc(f.description)}</p>\n <p><strong>Remediation:</strong></p>\n <ol>${f.remediationSteps.map((s) => `<li>${esc(s)}</li>`).join(\"\")}</ol>\n </div></details>\n </div>`;\n };\n\n const renderCards = (findings: Finding[]): string => {\n if (findings.length <= FOLD_THRESHOLD) {\n return findings.map(renderCard).join(\"\\n\");\n }\n const first = findings.slice(0, FOLD_THRESHOLD).map(renderCard).join(\"\\n\");\n const rest = findings.slice(FOLD_THRESHOLD).map(renderCard).join(\"\\n\");\n return `${first}\\n<details><summary>Show remaining ${findings.length - FOLD_THRESHOLD} findings...</summary>\\n${rest}\\n</details>`;\n };\n\n const SEV_EMOJI: Record<string, string> = {\n CRITICAL: \"&#128308;\",\n HIGH: \"&#128992;\",\n MEDIUM: \"&#128993;\",\n LOW: \"&#128309;\",\n };\n\n // Group findings by module\n const moduleMap = new Map<string, Finding[]>();\n for (const f of allFindings) {\n const mod = f.module ?? \"unknown\";\n if (!moduleMap.has(mod)) moduleMap.set(mod, []);\n moduleMap.get(mod)!.push(f);\n }\n\n // Sort modules: those with critical/high first, then by count\n const moduleEntries = [...moduleMap.entries()].sort((a, b) => {\n const aHasCritHigh = a[1].some((f) => f.severity === \"CRITICAL\" || f.severity === \"HIGH\");\n const bHasCritHigh = b[1].some((f) => f.severity === \"CRITICAL\" || f.severity === \"HIGH\");\n if (aHasCritHigh !== bHasCritHigh) return aHasCritHigh ? -1 : 1;\n return b[1].length - a[1].length;\n });\n\n findingsHtml = moduleEntries.map(([modName, modFindings]) => {\n const sevCounts: Record<string, number> = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 };\n for (const f of modFindings) sevCounts[f.severity]++;\n\n const badges = SEVERITY_ORDER\n .filter((sev) => sevCounts[sev] > 0)\n .map((sev) => `<span class=\"badge badge-${sev.toLowerCase()}\">${sevCounts[sev]} ${sev.charAt(0) + sev.slice(1).toLowerCase()}</span>`)\n .join(\" \");\n\n const sevGroups = SEVERITY_ORDER.map((sev) => {\n const findings = modFindings.filter((f) => f.severity === sev);\n if (findings.length === 0) return \"\";\n findings.sort((a, b) => b.riskScore - a.riskScore);\n\n const emoji = SEV_EMOJI[sev] ?? \"\";\n const label = sev.charAt(0) + sev.slice(1).toLowerCase();\n\n return `<details class=\"severity-group-fold\">\n <summary><h4>${emoji} ${label} (${findings.length})</h4></summary>\n ${renderCards(findings)}\n </details>`;\n }).filter(Boolean).join(\"\\n\");\n\n return `<details class=\"module-fold\">\n <summary>\n <h3>&#128274; ${esc(modName)} (${modFindings.length})</h3>\n <span class=\"module-badges\">${badges}</span>\n </summary>\n <div class=\"module-body\">\n ${sevGroups}\n </div>\n </details>`;\n }).join(\"\\n\");\n }\n\n // --- Trend Charts ---\n let trendHtml = \"\";\n if (history && history.length >= 2) {\n trendHtml = `\n <section class=\"trend-section\">\n <h2>30-Day Trends</h2>\n <div class=\"trend-chart\">\n <div class=\"trend-title\">Findings by Severity</div>\n ${findingsTrendChart(history)}\n </div>\n <div class=\"trend-chart\">\n <div class=\"trend-title\">Security Score</div>\n ${scoreTrendChart(history)}\n </div>\n </section>`;\n }\n\n // --- Statistics table ---\n const statsRows = modules\n .map(\n (m) =>\n `<tr><td>${esc(m.module)}</td><td>${m.resourcesScanned}</td><td>${m.findingsCount}</td><td>${m.status === \"success\" ? \"&#10003;\" : \"&#10007;\"}</td></tr>`,\n )\n .join(\"\\n\");\n\n // --- Recommendations (deduplicated) ---\n let recsHtml = \"\";\n if (summary.totalFindings > 0) {\n const recMap = new Map<string, { text: string; severity: Severity; count: number }>();\n for (const f of allFindings) {\n const rem = f.remediationSteps[0] ?? \"Review and remediate.\";\n const existing = recMap.get(rem);\n if (existing) {\n existing.count++;\n if (SEVERITY_ORDER.indexOf(f.severity) < SEVERITY_ORDER.indexOf(existing.severity)) {\n existing.severity = f.severity;\n }\n } else {\n recMap.set(rem, { text: rem, severity: f.severity, count: 1 });\n }\n }\n const uniqueRecs = [...recMap.values()].sort((a, b) => {\n const sevDiff = SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity);\n if (sevDiff !== 0) return sevDiff;\n return b.count - a.count;\n });\n\n const renderRec = (r: { text: string; severity: Severity; count: number }): string => {\n const sev = r.severity.toLowerCase();\n const countLabel = r.count > 1 ? ` (&times; ${r.count})` : \"\";\n return `<li><span class=\"badge badge-${esc(sev)}\">${esc(r.severity)}</span> ${esc(r.text)}${countLabel}</li>`;\n };\n\n const TOP_N = 10;\n const topItems = uniqueRecs.slice(0, TOP_N).map(renderRec).join(\"\\n\");\n const remaining = uniqueRecs.slice(TOP_N);\n const moreHtml = remaining.length > 0\n ? `\\n<details><summary>Show ${remaining.length} more&hellip;</summary>\\n${remaining.map(renderRec).join(\"\\n\")}\\n</details>`\n : \"\";\n\n recsHtml = `\n <details class=\"rec-fold\">\n <summary><h2 style=\"margin:0;border:0;display:inline\">Recommendations (${uniqueRecs.length} unique)</h2></summary>\n <div class=\"rec-body\">\n <ol>${topItems}${moreHtml}</ol>\n </div>\n </details>`;\n }\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>AWS Security Scan Report &mdash; ${esc(date)}</title>\n<style>${sharedCss()}</style>\n</head>\n<body>\n<div class=\"container\">\n\n<header>\n <h1>&#128737;&#65039; AWS Security Scan Report</h1>\n <div class=\"meta\">Account: ${esc(accountId)} | Region: ${esc(region)} | ${esc(date)} | Duration: ${esc(duration)}</div>\n</header>\n\n<section class=\"summary\">\n <div class=\"score-card\">\n <div class=\"score-value\" style=\"color:${scoreColor(score)}\">${score}</div>\n <div class=\"score-label\">Security Score</div>\n </div>\n <div class=\"severity-stats\">\n <div class=\"stat-card stat-critical\"><div class=\"stat-count\">${summary.critical}</div><div class=\"stat-label\">Critical</div></div>\n <div class=\"stat-card stat-high\"><div class=\"stat-count\">${summary.high}</div><div class=\"stat-label\">High</div></div>\n <div class=\"stat-card stat-medium\"><div class=\"stat-count\">${summary.medium}</div><div class=\"stat-label\">Medium</div></div>\n <div class=\"stat-card stat-low\"><div class=\"stat-count\">${summary.low}</div><div class=\"stat-label\">Low</div></div>\n </div>\n</section>\n\n<section class=\"charts\">\n <div class=\"chart-box\">\n <div class=\"chart-title\">Severity Distribution</div>\n <div style=\"text-align:center\">${donutChart(summary)}</div>\n </div>\n <div class=\"chart-box\">\n <div class=\"chart-title\">Findings by Module</div>\n ${barChart(modules)}\n </div>\n</section>\n\n${trendHtml}\n\n${top5Html}\n\n${buildServiceReminderHtml(modules)}\n\n<section>\n <h2>Scan Statistics</h2>\n <table>\n <thead><tr><th>Module</th><th>Resources</th><th>Findings</th><th>Status</th></tr></thead>\n <tbody>${statsRows}</tbody>\n </table>\n</section>\n\n<section>\n <h2>All Findings</h2>\n ${findingsHtml}\n</section>\n\n${recsHtml}\n\n<footer>\n <p>Generated by AWS Security MCP Server v${VERSION}</p>\n <p>This report is for informational purposes only.</p>\n</footer>\n\n</div>\n</body>\n</html>`;\n}\n\n// ---------------------------------------------------------------------------\n// MLPS Level 3 HTML Report (等保三级)\n// ---------------------------------------------------------------------------\n\nexport function generateMlps3HtmlReport(\n scanResults: FullScanResult,\n history?: DashboardHistoryEntry[],\n): string {\n const { accountId, region, scanStart } = scanResults;\n const date = scanStart.split(\"T\")[0];\n const scanTime = scanStart.replace(\"T\", \" \").replace(/\\.\\d+Z$/, \" UTC\");\n\n const allFindings: Finding[] = scanResults.modules.flatMap((m) =>\n m.findings.map((f) => ({ ...f, module: f.module ?? m.module })),\n );\n\n const scanModules = scanResults.modules.map((m) => ({\n module: m.module,\n status: m.status,\n }));\n const results = MLPS_CHECKS.map((check) =>\n evaluateCheck(check, allFindings, scanModules),\n );\n\n const passCount = results.filter((r) => r.status === \"pass\").length;\n const failCount = results.filter((r) => r.status === \"fail\").length;\n const unknownCount = results.filter((r) => r.status === \"unknown\").length;\n const checkedTotal = passCount + failCount;\n const percent =\n checkedTotal > 0 ? Math.round((passCount / checkedTotal) * 100) : 0;\n\n // --- Trend Charts ---\n let trendHtml = \"\";\n if (history && history.length >= 2) {\n trendHtml = `\n <section class=\"trend-section\">\n <h2>30日趋势</h2>\n <div class=\"trend-chart\">\n <div class=\"trend-title\">按严重性分类的发现</div>\n ${findingsTrendChart(history)}\n </div>\n <div class=\"trend-chart\">\n <div class=\"trend-title\">安全评分</div>\n ${scoreTrendChart(history)}\n </div>\n </section>`;\n }\n\n // --- Category sections (folded) ---\n const categorySections = CATEGORY_ORDER.map((category) => {\n const sectionTitle = CATEGORY_SECTION[category];\n const categoryResults = results.filter(\n (r) => r.check.category === category,\n );\n if (categoryResults.length === 0) return \"\";\n\n const catPass = categoryResults.filter((r) => r.status === \"pass\").length;\n const catFail = categoryResults.filter((r) => r.status === \"fail\").length;\n const catUnknown = categoryResults.filter(\n (r) => r.status === \"unknown\",\n ).length;\n const byId = new Map<string, typeof categoryResults>();\n for (const r of categoryResults) {\n const existing = byId.get(r.check.id) ?? [];\n existing.push(r);\n byId.set(r.check.id, existing);\n }\n\n const groups = [...byId.entries()]\n .map(([checkId, checkResults]) => {\n const grpPass = checkResults.filter((r) => r.status === \"pass\").length;\n const grpFail = checkResults.filter((r) => r.status === \"fail\").length;\n const grpUnknown = checkResults.filter((r) => r.status === \"unknown\").length;\n\n const items = checkResults\n .map((r) => {\n const icon =\n r.status === \"pass\"\n ? \"&#10004;\"\n : r.status === \"fail\"\n ? \"&#10008;\"\n : \"&#9888;\";\n const cls = `check-${r.status}`;\n const label = r.status === \"unknown\" ? \" (未检查)\" : \"\";\n let findingsHtml = \"\";\n if (r.status === \"fail\" && r.relatedFindings.length > 0) {\n const items = r.relatedFindings\n .slice(0, 3)\n .map(\n (f) =>\n `<li>${esc(f.severity)}: ${esc(f.title)}</li>`,\n );\n if (r.relatedFindings.length > 3) {\n items.push(\n `<li>... 及其他 ${r.relatedFindings.length - 3} 项</li>`,\n );\n }\n findingsHtml = `<ul class=\"check-findings\">${items.join(\"\")}</ul>`;\n }\n return `<div class=\"check-item ${cls}\"><span class=\"check-icon\">${icon}</span><span class=\"check-name\">${esc(r.check.name)}${label}</span></div>${findingsHtml}`;\n })\n .join(\"\\n\");\n\n const statusBadges = [\n grpPass > 0 ? `<span class=\"category-stat-pass\">&#10003; ${grpPass}</span>` : \"\",\n grpFail > 0 ? `<span class=\"category-stat-fail\">&#10007; ${grpFail}</span>` : \"\",\n grpUnknown > 0 ? `<span class=\"category-stat-unknown\">? ${grpUnknown}</span>` : \"\",\n ].filter(Boolean).join(\" \");\n\n return `<details class=\"severity-group-fold\"><summary><h4>${esc(checkId)} ${esc(checkResults[0].check.name)} <span class=\"category-stats\">${statusBadges}</span></h4></summary>\\n${items}\\n</details>`;\n })\n .join(\"\\n\");\n\n const statsHtml = [\n catPass > 0\n ? `<span class=\"category-stat-pass\">&#10003; ${catPass}</span>`\n : \"\",\n catFail > 0\n ? `<span class=\"category-stat-fail\">&#10007; ${catFail}</span>`\n : \"\",\n catUnknown > 0\n ? `<span class=\"category-stat-unknown\">? ${catUnknown}</span>`\n : \"\",\n ]\n .filter(Boolean)\n .join(\"\");\n\n return `<details class=\"category-fold\">\n <summary>\n <span class=\"category-title\">${esc(sectionTitle)}</span>\n <span class=\"category-stats\">${statsHtml}</span>\n </summary>\n <div class=\"category-body\">${groups}</div>\n</details>`;\n })\n .filter(Boolean)\n .join(\"\\n\");\n\n // --- Remediation (deduplicated) ---\n const failedResults = results.filter((r) => r.status === \"fail\");\n let remediationHtml = \"\";\n if (failedResults.length > 0) {\n const mlpsRecMap = new Map<string, { text: string; severity: Severity; count: number }>();\n for (const r of failedResults) {\n for (const f of r.relatedFindings) {\n const rem = f.remediationSteps[0] ?? \"Review and remediate.\";\n const existing = mlpsRecMap.get(rem);\n if (existing) {\n existing.count++;\n if (SEVERITY_ORDER.indexOf(f.severity) < SEVERITY_ORDER.indexOf(existing.severity)) {\n existing.severity = f.severity;\n }\n } else {\n mlpsRecMap.set(rem, { text: rem, severity: f.severity, count: 1 });\n }\n }\n }\n const mlpsUniqueRecs = [...mlpsRecMap.values()].sort((a, b) => {\n const sevDiff = SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity);\n if (sevDiff !== 0) return sevDiff;\n return b.count - a.count;\n });\n\n const renderMlpsRec = (r: { text: string; severity: Severity; count: number }): string => {\n const sev = r.severity.toLowerCase();\n const countLabel = r.count > 1 ? ` (&times; ${r.count})` : \"\";\n return `<li><span class=\"badge badge-${esc(sev)}\">${esc(r.severity)}</span> ${esc(r.text)}${countLabel}</li>`;\n };\n\n const MLPS_TOP_N = 10;\n const mlpsTopItems = mlpsUniqueRecs.slice(0, MLPS_TOP_N).map(renderMlpsRec).join(\"\\n\");\n const mlpsRemaining = mlpsUniqueRecs.slice(MLPS_TOP_N);\n const mlpsMoreHtml = mlpsRemaining.length > 0\n ? `\\n<details><summary>显示其余 ${mlpsRemaining.length} 项&hellip;</summary>\\n${mlpsRemaining.map(renderMlpsRec).join(\"\\n\")}\\n</details>`\n : \"\";\n\n remediationHtml = `\n <details class=\"rec-fold\">\n <summary><h2 style=\"margin:0;border:0;display:inline\">建议整改项(${mlpsUniqueRecs.length} 项去重)</h2></summary>\n <div class=\"rec-body\">\n <ol>${mlpsTopItems}${mlpsMoreHtml}</ol>\n </div>\n </details>`;\n }\n\n const passRateColor =\n percent >= 80 ? \"#22c55e\" : percent >= 50 ? \"#eab308\" : \"#ef4444\";\n const unknownNote =\n unknownCount > 0\n ? `<div style=\"color:#94a3b8;font-size:12px;margin-top:8px\">(未检查项不计入通过率)</div>`\n : \"\";\n\n return `<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<title>等保三级预检报告 &mdash; ${esc(date)}</title>\n<style>${sharedCss()}</style>\n</head>\n<body>\n<div class=\"container\">\n\n<header>\n <h1>&#128737;&#65039; 等保三级预检报告</h1>\n <div class=\"disclaimer\">本报告为等保预检参考,仅覆盖 AWS 云平台配置检查。完整等保测评需由持证测评机构执行。</div>\n <div class=\"meta\">账户: ${esc(accountId)} | 区域: ${esc(region)} | 扫描时间: ${esc(scanTime)}</div>\n</header>\n\n<section class=\"summary\">\n <div class=\"score-card\">\n <div class=\"score-value\" style=\"color:${passRateColor}\">${percent}%</div>\n <div class=\"score-label\">通过率</div>\n </div>\n <div class=\"severity-stats\">\n <div class=\"stat-card\" style=\"border-color:#22c55e30\"><div class=\"stat-count\" style=\"color:#22c55e\">${passCount}</div><div class=\"stat-label\">通过</div></div>\n <div class=\"stat-card\" style=\"border-color:#ef444430\"><div class=\"stat-count\" style=\"color:#ef4444\">${failCount}</div><div class=\"stat-label\">不通过</div></div>\n ${unknownCount > 0 ? `<div class=\"stat-card\" style=\"border-color:#94a3b830\"><div class=\"stat-count\" style=\"color:#94a3b8\">${unknownCount}</div><div class=\"stat-label\">未检查</div></div>` : \"\"}\n </div>\n</section>\n${unknownNote}\n\n${trendHtml}\n\n${buildServiceReminderHtml(scanResults.modules)}\n\n${categorySections}\n\n${remediationHtml}\n\n<footer>\n <p>由 AWS Security MCP Server v${VERSION} 生成</p>\n <p>本报告仅供参考。完整等保测评需由持证测评机构执行。</p>\n</footer>\n\n</div>\n</body>\n</html>`;\n}\n","import { writeFileSync, readFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nimport type {\n FullScanResult,\n DashboardData,\n DashboardHistoryEntry,\n} from \"../types.js\";\n\nexport function calculateScore(summary: FullScanResult[\"summary\"]): number {\n const raw =\n 100 -\n summary.critical * 15 -\n summary.high * 5 -\n summary.medium * 2 -\n summary.low * 0.5;\n return Math.max(0, Math.min(100, raw));\n}\n\nexport function saveResults(\n scanResults: FullScanResult,\n outputDir?: string,\n): string {\n const baseDir = outputDir ?? join(homedir(), \".aws-security\");\n const today = scanResults.scanStart.slice(0, 10); // YYYY-MM-DD\n\n // Create directories\n const scanDir = join(baseDir, \"scans\", today);\n const dashboardDir = join(baseDir, \"dashboard\");\n mkdirSync(scanDir, { recursive: true });\n mkdirSync(dashboardDir, { recursive: true });\n\n // Write raw scan\n writeFileSync(join(scanDir, \"scan.json\"), JSON.stringify(scanResults, null, 2));\n\n // Read existing dashboard data\n const dataPath = join(dashboardDir, \"data.json\");\n let existing: DashboardData | null = null;\n if (existsSync(dataPath)) {\n try {\n existing = JSON.parse(readFileSync(dataPath, \"utf-8\")) as DashboardData;\n } catch {\n // Corrupt or invalid JSON — start fresh\n existing = null;\n }\n }\n\n // Build history entry for today\n const historyEntry: DashboardHistoryEntry = {\n date: today,\n score: calculateScore(scanResults.summary),\n critical: scanResults.summary.critical,\n high: scanResults.summary.high,\n medium: scanResults.summary.medium,\n low: scanResults.summary.low,\n totalFindings: scanResults.summary.totalFindings,\n };\n\n // Merge history: replace same-date entry or append\n let history = existing?.history ?? [];\n const idx = history.findIndex((h) => h.date === today);\n if (idx >= 0) {\n history[idx] = historyEntry;\n } else {\n history.push(historyEntry);\n }\n // Keep only last 30 entries\n history = history.slice(-30);\n\n // Build dashboard data\n const dashboardData: DashboardData = {\n lastScan: {\n scanStart: scanResults.scanStart,\n scanEnd: scanResults.scanEnd,\n region: scanResults.region,\n accountId: scanResults.accountId,\n summary: scanResults.summary,\n modules: scanResults.modules.map((m) => ({\n module: m.module,\n findingsCount: m.findingsCount,\n status: m.status,\n })),\n findings: scanResults.modules.flatMap((m) =>\n m.findings.map((f) => ({ ...f, module: m.module })),\n ),\n },\n history,\n meta: {\n generatedAt: new Date().toISOString(),\n version: \"1.0.0\",\n dataRetentionDays: 30,\n },\n };\n\n writeFileSync(dataPath, JSON.stringify(dashboardData, null, 2));\n return dataPath;\n}\n","export interface FindingsFilter {\n /** Filter Security Hub findings by category keywords (case-insensitive match on title/description/impact) */\n securityHubCategories?: string[];\n /** Filter GuardDuty findings by type prefix (matched against impact field) */\n guardDutyTypes?: string[];\n /** Filter Inspector findings by type (matched against impact field) */\n inspectorTypes?: string[];\n /** Filter by minimum severity */\n minSeverity?: string;\n}\n\nconst SEVERITY_ORDER: Record<string, number> = {\n LOW: 0,\n MEDIUM: 1,\n HIGH: 2,\n CRITICAL: 3,\n};\n\nexport function applyFindingsFilter(\n moduleName: string,\n findings: import(\"../types.js\").Finding[],\n filter: FindingsFilter,\n): import(\"../types.js\").Finding[] {\n let result = findings;\n\n // Apply severity filter\n if (filter.minSeverity) {\n const minLevel = SEVERITY_ORDER[filter.minSeverity.toUpperCase()] ?? 0;\n result = result.filter((f) => (SEVERITY_ORDER[f.severity] ?? 0) >= minLevel);\n }\n\n // Apply module-specific category filters\n if (moduleName === \"security_hub_findings\" && filter.securityHubCategories?.length) {\n const keywords = filter.securityHubCategories;\n result = result.filter((f) =>\n keywords.some((kw) => {\n const lower = kw.toLowerCase();\n return (\n f.title.toLowerCase().includes(lower) ||\n f.description.toLowerCase().includes(lower) ||\n f.impact.toLowerCase().includes(lower)\n );\n }),\n );\n }\n\n if (moduleName === \"guardduty_findings\" && filter.guardDutyTypes?.length) {\n const prefixes = filter.guardDutyTypes;\n result = result.filter((f) =>\n prefixes.some((prefix) => f.impact.includes(prefix)),\n );\n }\n\n if (moduleName === \"inspector_findings\" && filter.inspectorTypes?.length) {\n const types = filter.inspectorTypes;\n result = result.filter((f) =>\n types.some((t) => f.impact.includes(t)),\n );\n }\n\n return result;\n}\n\nexport const SCAN_GROUPS: Record<string, {\n name: string;\n description: string;\n modules: string[];\n reportType?: string;\n findingsFilter?: FindingsFilter;\n}> = {\n mlps3_precheck: {\n name: \"等保三级预检\",\n description: \"GB/T 22239-2019 等保三级 AWS 云租户层配置检查\",\n modules: [\"service_detection\", \"secret_exposure\", \"ssl_certificate\", \"dns_dangling\", \"network_reachability\", \"iam_privilege_escalation\", \"tag_compliance\", \"disaster_recovery\", \"security_hub_findings\", \"guardduty_findings\", \"inspector_findings\", \"trusted_advisor_findings\", \"config_rules_findings\", \"access_analyzer_findings\", \"patch_compliance_findings\", \"imdsv2_enforcement\", \"waf_coverage\"],\n reportType: \"mlps3\",\n },\n hw_defense: {\n name: \"护网蓝队加固\",\n description: \"护网前安全自查 — 攻击面+弱点评估\",\n modules: [\"service_detection\", \"secret_exposure\", \"network_reachability\", \"dns_dangling\", \"ssl_certificate\", \"iam_privilege_escalation\", \"security_hub_findings\", \"guardduty_findings\", \"inspector_findings\", \"config_rules_findings\", \"access_analyzer_findings\", \"patch_compliance_findings\", \"imdsv2_enforcement\", \"waf_coverage\"],\n findingsFilter: {\n guardDutyTypes: [\"Backdoor\", \"Trojan\", \"PenTest\", \"CryptoCurrency\"],\n minSeverity: \"MEDIUM\",\n },\n },\n exposure: {\n name: \"公网暴露面评估\",\n description: \"评估公网可达的资源和端口\",\n modules: [\"network_reachability\", \"dns_dangling\", \"public_access_verify\", \"ssl_certificate\", \"security_hub_findings\", \"access_analyzer_findings\", \"imdsv2_enforcement\", \"waf_coverage\"],\n findingsFilter: {\n securityHubCategories: [\"network\", \"public\", \"exposure\", \"port\"],\n },\n },\n data_encryption: {\n name: \"数据加密审计\",\n description: \"全面检查存储和传输加密状态\",\n modules: [\"ssl_certificate\", \"security_hub_findings\"],\n findingsFilter: {\n securityHubCategories: [\"encryption\", \"Encryption\"],\n },\n },\n least_privilege: {\n name: \"最小权限审计\",\n description: \"IAM 权限最小化评估\",\n modules: [\"iam_privilege_escalation\", \"security_hub_findings\", \"access_analyzer_findings\"],\n findingsFilter: {\n securityHubCategories: [\"IAM\", \"iam\", \"access\", \"privilege\"],\n },\n },\n log_integrity: {\n name: \"日志完整性审计\",\n description: \"审计日志完整性和保护\",\n modules: [\"service_detection\", \"security_hub_findings\"],\n findingsFilter: {\n securityHubCategories: [\"logging\", \"CloudTrail\", \"audit\"],\n },\n },\n disaster_recovery: {\n name: \"灾备评估\",\n description: \"备份和灾备能力评估\",\n modules: [\"disaster_recovery\", \"security_hub_findings\"],\n },\n idle_resources: {\n name: \"闲置资源清理\",\n description: \"发现未使用的资源\",\n modules: [\"idle_resources\", \"trusted_advisor_findings\"],\n },\n tag_compliance: {\n name: \"资源标签合规\",\n description: \"检查必需标签\",\n modules: [\"tag_compliance\"],\n },\n new_account_baseline: {\n name: \"新账户基线检查\",\n description: \"新 AWS 账户安全基线\",\n modules: [\"service_detection\", \"secret_exposure\", \"iam_privilege_escalation\", \"security_hub_findings\", \"guardduty_findings\", \"access_analyzer_findings\", \"imdsv2_enforcement\"],\n },\n aggregation: {\n name: \"安全服务聚合\",\n description: \"从 Security Hub / GuardDuty / Inspector / Trusted Advisor / Config Rules / Access Analyzer / Patch Compliance 聚合所有安全发现\",\n modules: [\"security_hub_findings\", \"guardduty_findings\", \"inspector_findings\", \"trusted_advisor_findings\", \"config_rules_findings\", \"access_analyzer_findings\", \"patch_compliance_findings\"],\n },\n};\n","export const SECURITY_RULES_CONTENT = `# AWS Security Scan Modules & Rules (19 modules)\n\n## 1. Service Detection (service_detection)\nDetects which AWS security services are enabled and assesses overall security maturity.\n- **Security Hub not enabled** — Risk 7.5: Provides 300+ automated security checks.\n- **GuardDuty not enabled** — Risk 7.5: Provides continuous threat detection.\n- **Inspector not enabled** — Risk 6.0: Scans for software vulnerabilities.\n- **AWS Config not enabled** — Risk 6.0: Tracks configuration changes.\n- **Macie not enabled** — Risk 5.0: Detects sensitive data in S3 (not available in China regions).\n- CloudTrail detection is included for coverage metrics.\n\n### Maturity Levels\n| Enabled Services | Level |\n|------------------|-------|\n| 0–1 | Basic |\n| 2–3 | Intermediate |\n| 4–5 | Advanced |\n| 6 | Comprehensive |\n\n## 2. Security Hub Findings (security_hub_findings)\nAggregates active findings from AWS Security Hub. Replaces individual config scanners (SG, S3, IAM, CloudTrail, RDS, EBS, VPC, etc.) with centralized compliance checks from FSBP, CIS, and PCI DSS standards.\n- Findings are filtered to ACTIVE + NEW/NOTIFIED workflow status.\n- Severity mapped: CRITICAL → 9.5, HIGH → 8.0, MEDIUM → 5.5, LOW → 3.0.\n- INFORMATIONAL findings are skipped.\n\n## 3. GuardDuty Findings (guardduty_findings)\nAggregates threat detection findings from Amazon GuardDuty.\n- Covers account compromise, instance compromise, and reconnaissance.\n- Severity mapped from GuardDuty 0–10 scale: ≥7 → HIGH, ≥4 → MEDIUM, <4 → LOW.\n- Only non-archived findings are included.\n\n## 4. Inspector Findings (inspector_findings)\nAggregates vulnerability findings from Amazon Inspector v2.\n- Covers CVEs in EC2 instances, Lambda functions, and container images.\n- Severity mapped: CRITICAL → 9.5, HIGH → 8.0, MEDIUM → 5.5, LOW → 3.0.\n- CVE IDs are included in finding titles when available.\n\n## 5. Trusted Advisor Findings (trusted_advisor_findings)\nAggregates security checks from AWS Trusted Advisor.\n- Requires AWS Business or Enterprise Support plan.\n- In China regions, uses cn-north-1 as the Support API endpoint.\n- Status mapped: error (RED) → 8.0, warning (YELLOW) → 5.5, ok (GREEN) → skip.\n\n## 6. Secret Exposure (secret_exposure)\nChecks Lambda env vars and EC2 userData for exposed secrets (AWS keys, private keys, passwords).\n\n## 7. SSL Certificate (ssl_certificate)\nChecks ACM certificates for expiry, failed status, and upcoming renewals.\n\n## 8. Dangling DNS (dns_dangling)\nChecks Route53 CNAME records for dangling DNS (subdomain takeover risk).\n\n## 9. Network Reachability (network_reachability)\nAnalyzes true network reachability by combining Security Group + NACL rules for public EC2 instances.\n\n## 10. IAM Privilege Escalation (iam_privilege_escalation)\nDetects IAM privilege escalation paths — users/roles that can escalate to admin via policy manipulation, role creation, or service abuse.\n\n## 11. Public Access Verify (public_access_verify)\nVerifies actual public accessibility of resources marked as public (S3 HTTP check, RDS DNS resolution).\n\n## 12. Tag Compliance (tag_compliance)\nChecks EC2, RDS, and S3 resources for required tags (Environment, Project, Owner).\n\n## 13. Idle Resources (idle_resources)\nFinds unused/idle AWS resources (unattached EBS volumes, unused EIPs, stopped instances, unused security groups).\n\n## 14. Disaster Recovery (disaster_recovery)\nAssesses disaster recovery readiness — RDS Multi-AZ & backups, EBS snapshot coverage, S3 versioning & cross-region replication.\n\n## 15. Config Rules Findings (config_rules_findings)\nPulls non-compliant AWS Config Rule evaluation results.\n- Lists all Config Rules and their compliance status.\n- For NON_COMPLIANT rules, retrieves specific non-compliant resources.\n- Security-related rules (encryption, IAM, public access, etc.) mapped to HIGH severity (7.5).\n- Other non-compliant rules mapped to MEDIUM severity (5.5).\n- Gracefully handles regions where AWS Config is not enabled.\n\n## 16. IAM Access Analyzer Findings (access_analyzer_findings)\nPulls active IAM Access Analyzer findings — resources accessible from outside the account.\n- Lists active analyzers (ACCOUNT or ORGANIZATION type).\n- Retrieves ACTIVE findings showing external access to resources.\n- Covers S3 buckets, IAM roles, SQS queues, Lambda functions, KMS keys, and more.\n- Severity mapped: CRITICAL → 9.5, HIGH → 8.0, MEDIUM → 5.5, LOW → 3.0.\n- Returns warning if no analyzer is configured.\n\n## 17. SSM Patch Compliance (patch_compliance_findings)\nChecks patch compliance status for SSM-managed instances.\n- Lists all managed instances via SSM.\n- Retrieves patch compliance state for each instance.\n- Missing security patches or failed patches → HIGH (7.5).\n- Missing non-security patches → MEDIUM (5.5).\n- Instances without patch data flagged as LOW (3.0) for visibility.\n- Includes platform info, missing/failed counts, and last scan time.\n\n## 18. IMDSv2 Enforcement (imdsv2_enforcement)\nChecks if EC2 instances enforce IMDSv2 (Instance Metadata Service v2).\n- Lists all running EC2 instances and checks MetadataOptions.HttpTokens.\n- **HttpTokens != \"required\"** — Risk 7.5: IMDSv1 allows credential theft via SSRF attacks.\n- Also checks HttpPutResponseHopLimit — values >1 on containerized workloads noted as warning.\n- Remediation: Set HttpTokens to \"required\" via modify-instance-metadata-options.\n\n## 19. WAF Coverage (waf_coverage)\nChecks if internet-facing ALBs have WAF Web ACL associated for protection.\n- Lists all ELBv2 load balancers, filters to internet-facing only.\n- For each internet-facing ALB, checks WAFv2 Web ACL association.\n- **No WAF Web ACL** — Risk 7.5: ALB exposed to SQL injection, XSS, and OWASP Top 10 attacks.\n- NLBs (L4) are skipped as WAF does not apply — noted in warnings.\n- Gracefully handles WAFv2 access denied or unavailable regions.\n`;\n\nexport const RISK_SCORING_CONTENT = `# Risk Scoring Model\n\n## Score Ranges\nEach finding is assigned a risk score from 0.0 to 10.0 based on potential impact and exploitability.\n\n| Score Range | Severity | Priority | Description |\n|-------------|----------|----------|-------------|\n| 9.0 – 10.0 | CRITICAL | P0 | Immediate action required. Active exploitation risk. |\n| 7.0 – 8.9 | HIGH | P1 | Address within 24-48 hours. Significant exposure. |\n| 4.0 – 6.9 | MEDIUM | P2 | Address within 1-2 weeks. Moderate risk. |\n| 0.0 – 3.9 | LOW | P3 | Address in next maintenance cycle. Minor risk. |\n\n## Severity Mapping\n\\`\\`\\`\nscore >= 9.0 → CRITICAL\nscore >= 7.0 → HIGH\nscore >= 4.0 → MEDIUM\nscore < 4.0 → LOW\n\\`\\`\\`\n\n## Priority Mapping\n\\`\\`\\`\nCRITICAL → P0 (Immediate)\nHIGH → P1 (Urgent)\nMEDIUM → P2 (Normal)\nLOW → P3 (Low)\n\\`\\`\\`\n\n## Scoring Factors\n- **Exploitability**: How easily can this misconfiguration be exploited?\n- **Blast radius**: What data or systems are at risk?\n- **Public exposure**: Is the resource internet-facing?\n- **Compliance**: Does this violate common compliance frameworks (CIS, SOC2)?\n- **Data sensitivity**: Could sensitive data be exposed or lost?\n\n## Examples\n- Root account without MFA → 10.0 (total account compromise risk)\n- Public S3 ACL → 9.5 (data breach via public access)\n- Missing encryption at rest → 6.0 (data exposure if storage is compromised)\n- Versioning disabled → 3.0 (data loss risk, low exploitability)\n`;\n","#!/usr/bin/env node\n\nimport { startServer } from \"../src/index.js\";\nimport { VERSION } from \"../src/version.js\";\n\nconst args = process.argv.slice(2);\nconst subcommand = args[0];\n\nconst HELP = `Usage: aws-security-mcp [command] [options]\n\nCommands:\n (default) Start MCP server (stdio, for Kiro/Claude Code)\n dashboard Start local HTTP server serving the security dashboard\n deploy-dashboard Deploy dashboard to an S3 bucket as a static website\n\nOptions:\n --region <region> AWS region (default: AWS_REGION env or us-east-1)\n --version Print version and exit\n --help, -h Show this help message\n\nDashboard options:\n --port <port> Port for local dashboard server (default: 3000)\n\nDeploy options:\n --bucket <name> S3 bucket name (required)\n --region <region> AWS region for the S3 bucket\n\nEnvironment variables:\n AWS_REGION Default AWS region\n AWS_DEFAULT_REGION Fallback default region\n\nThe MCP server communicates over stdio using the MCP protocol.`;\n\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n console.log(HELP);\n process.exit(0);\n}\n\nif (args.includes(\"--version\")) {\n console.log(`aws-security-mcp ${VERSION}`);\n process.exit(0);\n}\n\nfunction getArg(name: string): string | undefined {\n const idx = args.indexOf(name);\n if (idx !== -1 && args[idx + 1]) return args[idx + 1];\n return undefined;\n}\n\nfunction getRegion(): string {\n return (\n getArg(\"--region\") ??\n process.env.AWS_REGION ??\n process.env.AWS_DEFAULT_REGION ??\n \"us-east-1\"\n );\n}\n\nif (subcommand === \"dashboard\") {\n const port = Number(getArg(\"--port\")) || 3000;\n import(\"../src/commands/dashboard.js\").then(({ startDashboard }) => {\n startDashboard(port);\n });\n} else if (subcommand === \"deploy-dashboard\") {\n const bucket = getArg(\"--bucket\");\n if (!bucket) {\n console.error(\"Error: --bucket <name> is required for deploy-dashboard\");\n process.exit(1);\n }\n const region = getRegion();\n import(\"../src/commands/deploy-dashboard.js\").then(({ deployDashboard }) => {\n deployDashboard(bucket, region).catch((err) => {\n console.error(\"Deploy failed:\", err.message || err);\n process.exit(1);\n });\n });\n} else if (subcommand && !subcommand.startsWith(\"--\")) {\n console.error(`Unknown command: ${subcommand}`);\n console.error('Run \"aws-security-mcp --help\" for usage.');\n process.exit(1);\n} else {\n // Default: start MCP server\n const region = getRegion();\n startServer(region).catch((err) => {\n console.error(\"Fatal:\", err);\n process.exit(1);\n });\n}\n"],"mappings":"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","names":["createServer","join","existsSync","fileURLToPath","readFileSync","existsSync","copyFileSync","join","extname","fileURLToPath","S3Client","__dirname","__filename","STSClient","GetCallerIdentityCommand","STSClient","makeFinding","makeFinding","makeFinding","EC2Client","DescribeInstancesCommand","makeFinding","EC2Client","DescribeInstancesCommand","makeFinding","S3Client","dns","makeFinding","S3Client","dns","EC2Client","DescribeInstancesCommand","RDSClient","DescribeDBInstancesCommand","S3Client","ListBucketsCommand","makeFinding","EC2Client","DescribeInstancesCommand","RDSClient","DescribeDBInstancesCommand","S3Client","ListBucketsCommand","EC2Client","DescribeAddressesCommand","DescribeInstancesCommand","DescribeSecurityGroupsCommand","makeFinding","EC2Client","DescribeAddressesCommand","DescribeInstancesCommand","DescribeSecurityGroupsCommand","RDSClient","DescribeDBInstancesCommand","EC2Client","DescribeVolumesCommand","S3Client","ListBucketsCommand","makeFinding","RDSClient","DescribeDBInstancesCommand","EC2Client","DescribeVolumesCommand","S3Client","ListBucketsCommand","SecurityHubClient","SecurityHubClient","isNotEnabled","GuardDutyClient","ListDetectorsCommand","GetFindingsCommand","GuardDutyClient","ListDetectorsCommand","GetFindingsCommand","Inspector2Client","ListFindingsCommand","Inspector2Client","ListFindingsCommand","isAccessDenied","isNotEnabled","ConfigServiceClient","ConfigServiceClient","riskScore","severity","EC2Client","DescribeInstancesCommand","makeFinding","EC2Client","DescribeInstancesCommand","makeFinding","formatDuration","SEVERITY_ORDER","items","SEVERITY_ORDER","readFileSync","join","SERVICE_RECOMMENDATIONS","SERVICE_NOT_ENABLED_PATTERNS","startDashboard","deployDashboard"]}