aws-security-mcp 0.6.2 → 0.7.0
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.
- package/dashboard/dist/assets/index-AKJ_-GfD.js +46 -0
- package/dashboard/dist/assets/index-UN8P_PO6.css +2 -0
- package/dashboard/dist/data.json +293 -105
- package/dashboard/dist/index.html +2 -2
- package/dist/bin/aws-security-mcp.js +116 -25
- package/dist/bin/aws-security-mcp.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +116 -25
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/dashboard/dist/assets/index-BYE-UdjR.js +0 -46
- package/dashboard/dist/assets/index-CQyERuqT.css +0 -2
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
6
6
|
// src/version.ts
|
|
7
|
-
var VERSION = "0.
|
|
7
|
+
var VERSION = "0.7.0";
|
|
8
8
|
|
|
9
9
|
// src/utils/aws-client.ts
|
|
10
10
|
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
|
|
@@ -2639,6 +2639,22 @@ import {
|
|
|
2639
2639
|
SecurityHubClient as SecurityHubClient2,
|
|
2640
2640
|
GetFindingsCommand
|
|
2641
2641
|
} from "@aws-sdk/client-securityhub";
|
|
2642
|
+
|
|
2643
|
+
// src/utils/sh-source.ts
|
|
2644
|
+
function getSecurityHubSource(finding) {
|
|
2645
|
+
const impact = finding.impact ?? "";
|
|
2646
|
+
const match = impact.match(/^Source:\s*([^(]+)/);
|
|
2647
|
+
if (!match) return "Other";
|
|
2648
|
+
const product = match[1].trim();
|
|
2649
|
+
if (product === "Security Hub" || product.includes("Foundational")) return "FSBP";
|
|
2650
|
+
if (product === "Inspector" || product.includes("Inspector")) return "Inspector";
|
|
2651
|
+
if (product === "GuardDuty" || product.includes("GuardDuty")) return "GuardDuty";
|
|
2652
|
+
if (product === "Config" || product.includes("Config")) return "Config";
|
|
2653
|
+
if (product === "IAM Access Analyzer" || product.includes("Access Analyzer")) return "Access Analyzer";
|
|
2654
|
+
return "Other";
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
// src/scanners/security-hub-findings.ts
|
|
2642
2658
|
function shSeverityToScore(label) {
|
|
2643
2659
|
switch (label) {
|
|
2644
2660
|
case "CRITICAL":
|
|
@@ -2708,7 +2724,7 @@ var SecurityHubFindingsScanner = class {
|
|
|
2708
2724
|
if (recText && !["See References", "None Provided", ""].includes(recText.trim())) {
|
|
2709
2725
|
remediationSteps.push(recText);
|
|
2710
2726
|
}
|
|
2711
|
-
|
|
2727
|
+
const finding = {
|
|
2712
2728
|
severity,
|
|
2713
2729
|
title: f.Title ?? "Security Hub Finding",
|
|
2714
2730
|
resourceType,
|
|
@@ -2722,7 +2738,9 @@ var SecurityHubFindingsScanner = class {
|
|
|
2722
2738
|
priority: priorityFromSeverity(severity),
|
|
2723
2739
|
module: this.moduleName,
|
|
2724
2740
|
accountId: f.AwsAccountId ?? accountId
|
|
2725
|
-
}
|
|
2741
|
+
};
|
|
2742
|
+
finding.source = getSecurityHubSource(finding);
|
|
2743
|
+
findings.push(finding);
|
|
2726
2744
|
}
|
|
2727
2745
|
nextToken = resp.NextToken;
|
|
2728
2746
|
} while (nextToken);
|
|
@@ -3646,6 +3664,12 @@ var zhI18n = {
|
|
|
3646
3664
|
trendTitle: "30\u65E5\u8D8B\u52BF",
|
|
3647
3665
|
findingsBySeverity: "\u6309\u4E25\u91CD\u6027\u5206\u7C7B\u7684\u53D1\u73B0",
|
|
3648
3666
|
showMoreCount: (n) => `\u663E\u793A\u5269\u4F59 ${n} \u9879\u2026`,
|
|
3667
|
+
// Filter toolbar
|
|
3668
|
+
filterSeverity: "\u4E25\u91CD\u6027\uFF1A",
|
|
3669
|
+
filterModule: "\u6A21\u5757\uFF1A",
|
|
3670
|
+
filterAll: "\u5168\u90E8",
|
|
3671
|
+
filterAllModules: "\u5168\u90E8\u6A21\u5757",
|
|
3672
|
+
filterCountTpl: "\u663E\u793A {shown} / {total} \u4E2A\u53D1\u73B0",
|
|
3649
3673
|
// Extended — MLPS extras
|
|
3650
3674
|
// Markdown report
|
|
3651
3675
|
executiveSummary: "\u6267\u884C\u6458\u8981",
|
|
@@ -3916,6 +3940,12 @@ var enI18n = {
|
|
|
3916
3940
|
trendTitle: "30-Day Trends",
|
|
3917
3941
|
findingsBySeverity: "Findings by Severity",
|
|
3918
3942
|
showMoreCount: (n) => `Show ${n} more\u2026`,
|
|
3943
|
+
// Filter toolbar
|
|
3944
|
+
filterSeverity: "Severity:",
|
|
3945
|
+
filterModule: "Module:",
|
|
3946
|
+
filterAll: "All",
|
|
3947
|
+
filterAllModules: "All Modules",
|
|
3948
|
+
filterCountTpl: "Showing {shown} / {total} findings",
|
|
3919
3949
|
// Extended \u2014 MLPS extras
|
|
3920
3950
|
// Markdown report
|
|
3921
3951
|
executiveSummary: "Executive Summary",
|
|
@@ -7034,18 +7064,6 @@ var SEVERITY_ORDER2 = ["CRITICAL", "HIGH", "MEDIUM", "LOW"];
|
|
|
7034
7064
|
function getRecommendationTemplate(rem) {
|
|
7035
7065
|
return rem.replace(/\b(i-[0-9a-f]+)\b/g, "{instance}").replace(/\b(vol-[0-9a-f]+)\b/g, "{volume}").replace(/\b(sg-[0-9a-f]+)\b/g, "{sg}").replace(/\b(eipalloc-[0-9a-f]+)\b/g, "{eip}").replace(/\b(arn:aws[-\w]*:[^"\s]+)\b/g, "{arn}").replace(/"[^"]+"/g, "{name}").replace(/bucket \S+/g, "bucket {name}").replace(/instance \S+/g, "instance {id}").replace(/volume \S+/g, "volume {id}").replace(/rule \S+/g, "rule {name}");
|
|
7036
7066
|
}
|
|
7037
|
-
function getSecurityHubSource(finding) {
|
|
7038
|
-
const impact = finding.impact ?? "";
|
|
7039
|
-
const match = impact.match(/^Source:\s*([^(]+)/);
|
|
7040
|
-
if (!match) return "Other";
|
|
7041
|
-
const product = match[1].trim();
|
|
7042
|
-
if (product === "Security Hub" || product.includes("Foundational")) return "FSBP";
|
|
7043
|
-
if (product === "Inspector" || product.includes("Inspector")) return "Inspector";
|
|
7044
|
-
if (product === "GuardDuty" || product.includes("GuardDuty")) return "GuardDuty";
|
|
7045
|
-
if (product === "Config" || product.includes("Config")) return "Config";
|
|
7046
|
-
if (product === "IAM Access Analyzer" || product.includes("Access Analyzer")) return "Access Analyzer";
|
|
7047
|
-
return "Other";
|
|
7048
|
-
}
|
|
7049
7067
|
var SECURITY_HUB_SUB_CAT_ORDER = ["FSBP", "Inspector", "GuardDuty", "Config", "Access Analyzer", "Other"];
|
|
7050
7068
|
function scoreColor(score) {
|
|
7051
7069
|
if (score >= 80) return "#22c55e";
|
|
@@ -7231,7 +7249,17 @@ function sharedCss() {
|
|
|
7231
7249
|
.rec-body ol{padding-left:24px}
|
|
7232
7250
|
.rec-body li{margin-bottom:8px;color:#cbd5e1;font-size:13px}
|
|
7233
7251
|
.rec-body .badge{margin-right:6px;vertical-align:middle}
|
|
7252
|
+
.filter-toolbar{display:flex;flex-wrap:wrap;gap:16px;align-items:center;margin-bottom:20px;padding:12px 16px;background:#1e293b;border:1px solid #334155;border-radius:8px}
|
|
7253
|
+
.filter-group{display:flex;align-items:center;gap:8px}
|
|
7254
|
+
.filter-label{color:#94a3b8;font-size:13px}
|
|
7255
|
+
.filter-btn{padding:4px 12px;border-radius:4px;border:1px solid #475569;background:transparent;color:#cbd5e1;cursor:pointer;font-size:13px}
|
|
7256
|
+
.filter-btn:hover{background:#334155}
|
|
7257
|
+
.filter-btn.active{background:#3b82f6;border-color:#3b82f6;color:#fff}
|
|
7258
|
+
.filter-select{padding:4px 8px;border-radius:4px;border:1px solid #475569;background:#0f172a;color:#cbd5e1;font-size:13px}
|
|
7259
|
+
.filter-count{color:#64748b;font-size:13px;margin-left:auto}
|
|
7234
7260
|
@media print{
|
|
7261
|
+
.filter-toolbar{display:none !important}
|
|
7262
|
+
.finding-card,.module-fold{display:block !important}
|
|
7235
7263
|
body{background:#fff;color:#1e293b;-webkit-print-color-adjust:exact;print-color-adjust:exact}
|
|
7236
7264
|
.container{max-width:100%;padding:20px}
|
|
7237
7265
|
.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}
|
|
@@ -7490,13 +7518,14 @@ function generateHtmlReport(scanResults, history, lang) {
|
|
|
7490
7518
|
</section>`;
|
|
7491
7519
|
}
|
|
7492
7520
|
let findingsHtml;
|
|
7521
|
+
let filterToolbarHtml = "";
|
|
7493
7522
|
if (summary.totalFindings === 0) {
|
|
7494
7523
|
findingsHtml = `<div class="no-findings">${esc(t.noIssuesFound)}</div>`;
|
|
7495
7524
|
} else {
|
|
7496
7525
|
const FOLD_THRESHOLD = 20;
|
|
7497
|
-
const renderCard = (f) => {
|
|
7526
|
+
const renderCard = (f, moduleKey) => {
|
|
7498
7527
|
const sev = f.severity.toLowerCase();
|
|
7499
|
-
return `<div class="finding-card sev-${esc(sev)}">
|
|
7528
|
+
return `<div class="finding-card sev-${esc(sev)}" data-severity="${esc(f.severity)}" data-module="${esc(moduleKey)}">
|
|
7500
7529
|
<span class="badge badge-${esc(sev)}">${esc(f.severity)}</span>
|
|
7501
7530
|
<span class="finding-title-text">${esc(f.title)}</span>
|
|
7502
7531
|
<span class="finding-resource">${esc(f.resourceArn || f.resourceId)}</span>
|
|
@@ -7507,12 +7536,12 @@ function generateHtmlReport(scanResults, history, lang) {
|
|
|
7507
7536
|
</div></details>
|
|
7508
7537
|
</div>`;
|
|
7509
7538
|
};
|
|
7510
|
-
const renderCards = (findings) => {
|
|
7539
|
+
const renderCards = (findings, moduleKey) => {
|
|
7511
7540
|
if (findings.length <= FOLD_THRESHOLD) {
|
|
7512
|
-
return findings.map(renderCard).join("\n");
|
|
7541
|
+
return findings.map((f) => renderCard(f, moduleKey)).join("\n");
|
|
7513
7542
|
}
|
|
7514
|
-
const first = findings.slice(0, FOLD_THRESHOLD).map(renderCard).join("\n");
|
|
7515
|
-
const rest = findings.slice(FOLD_THRESHOLD).map(renderCard).join("\n");
|
|
7543
|
+
const first = findings.slice(0, FOLD_THRESHOLD).map((f) => renderCard(f, moduleKey)).join("\n");
|
|
7544
|
+
const rest = findings.slice(FOLD_THRESHOLD).map((f) => renderCard(f, moduleKey)).join("\n");
|
|
7516
7545
|
return `${first}
|
|
7517
7546
|
<details><summary>${t.showRemainingFindings(findings.length - FOLD_THRESHOLD)}</summary>
|
|
7518
7547
|
${rest}
|
|
@@ -7547,7 +7576,7 @@ ${rest}
|
|
|
7547
7576
|
if (aHasCritHigh !== bHasCritHigh) return aHasCritHigh ? -1 : 1;
|
|
7548
7577
|
return b[1].length - a[1].length;
|
|
7549
7578
|
});
|
|
7550
|
-
const renderSeverityGroups = (findings) => {
|
|
7579
|
+
const renderSeverityGroups = (findings, moduleKey) => {
|
|
7551
7580
|
return SEVERITY_ORDER2.map((sev) => {
|
|
7552
7581
|
const sevFindings = findings.filter((f) => f.severity === sev);
|
|
7553
7582
|
if (sevFindings.length === 0) return "";
|
|
@@ -7556,7 +7585,7 @@ ${rest}
|
|
|
7556
7585
|
const label = sev.charAt(0) + sev.slice(1).toLowerCase();
|
|
7557
7586
|
return `<details class="severity-group-fold">
|
|
7558
7587
|
<summary><h4>${emoji} ${label} (${sevFindings.length})</h4></summary>
|
|
7559
|
-
${renderCards(sevFindings)}
|
|
7588
|
+
${renderCards(sevFindings, moduleKey)}
|
|
7560
7589
|
</details>`;
|
|
7561
7590
|
}).filter(Boolean).join("\n");
|
|
7562
7591
|
};
|
|
@@ -7568,16 +7597,38 @@ ${rest}
|
|
|
7568
7597
|
findingsHtml = moduleEntries.map(([modName, modFindings, subCatLabel]) => {
|
|
7569
7598
|
const badges = renderModuleBadges(modFindings);
|
|
7570
7599
|
const displayName = subCatLabel ?? (t.moduleNames[modName] ?? modName);
|
|
7571
|
-
return `<details class="module-fold">
|
|
7600
|
+
return `<details class="module-fold" data-module="${esc(modName)}">
|
|
7572
7601
|
<summary>
|
|
7573
7602
|
<h3>🔒 ${esc(displayName)} (${modFindings.length})</h3>
|
|
7574
7603
|
<span class="module-badges">${badges}</span>
|
|
7575
7604
|
</summary>
|
|
7576
7605
|
<div class="module-body">
|
|
7577
|
-
${renderSeverityGroups(modFindings)}
|
|
7606
|
+
${renderSeverityGroups(modFindings, modName)}
|
|
7578
7607
|
</div>
|
|
7579
7608
|
</details>`;
|
|
7580
7609
|
}).join("\n");
|
|
7610
|
+
const moduleOptions = moduleEntries.map(([modKey, , subCatLabel]) => {
|
|
7611
|
+
const label = subCatLabel ?? (t.moduleNames[modKey] ?? modKey);
|
|
7612
|
+
return `<option value="${esc(modKey)}">${esc(label)}</option>`;
|
|
7613
|
+
}).join("\n ");
|
|
7614
|
+
filterToolbarHtml = `<div class="filter-toolbar" id="filterBar">
|
|
7615
|
+
<div class="filter-group">
|
|
7616
|
+
<span class="filter-label">${esc(t.filterSeverity)}</span>
|
|
7617
|
+
<button class="filter-btn active" data-severity="ALL">${esc(t.filterAll)}</button>
|
|
7618
|
+
<button class="filter-btn" data-severity="CRITICAL">Critical</button>
|
|
7619
|
+
<button class="filter-btn" data-severity="HIGH">High</button>
|
|
7620
|
+
<button class="filter-btn" data-severity="MEDIUM">Medium</button>
|
|
7621
|
+
<button class="filter-btn" data-severity="LOW">Low</button>
|
|
7622
|
+
</div>
|
|
7623
|
+
<div class="filter-group">
|
|
7624
|
+
<span class="filter-label">${esc(t.filterModule)}</span>
|
|
7625
|
+
<select class="filter-select" id="moduleFilter">
|
|
7626
|
+
<option value="ALL">${esc(t.filterAllModules)}</option>
|
|
7627
|
+
${moduleOptions}
|
|
7628
|
+
</select>
|
|
7629
|
+
</div>
|
|
7630
|
+
<div class="filter-count" id="filterCount" data-tpl="${esc(t.filterCountTpl)}"></div>
|
|
7631
|
+
</div>`;
|
|
7581
7632
|
}
|
|
7582
7633
|
let trendHtml = "";
|
|
7583
7634
|
if (history && history.length >= 2) {
|
|
@@ -7733,6 +7784,44 @@ ${remaining.map(renderRec).join("\n")}
|
|
|
7733
7784
|
</div>
|
|
7734
7785
|
</details>`;
|
|
7735
7786
|
}
|
|
7787
|
+
const filterScript = summary.totalFindings > 0 ? `<script>
|
|
7788
|
+
(function(){
|
|
7789
|
+
var activeSev='ALL',activeMod='ALL';
|
|
7790
|
+
var countEl=document.getElementById('filterCount');
|
|
7791
|
+
var tpl=countEl?countEl.getAttribute('data-tpl'):'';
|
|
7792
|
+
function apply(){
|
|
7793
|
+
var cards=document.querySelectorAll('.finding-card[data-severity]');
|
|
7794
|
+
var shown=0,total=cards.length;
|
|
7795
|
+
cards.forEach(function(c){
|
|
7796
|
+
var sevOk=activeSev==='ALL'||c.getAttribute('data-severity')===activeSev;
|
|
7797
|
+
var modOk=activeMod==='ALL'||c.getAttribute('data-module')===activeMod;
|
|
7798
|
+
c.style.display=(sevOk&&modOk)?'':'none';
|
|
7799
|
+
if(sevOk&&modOk)shown++;
|
|
7800
|
+
});
|
|
7801
|
+
if(countEl)countEl.textContent=tpl.replace('{shown}',shown).replace('{total}',total);
|
|
7802
|
+
document.querySelectorAll('.module-fold').forEach(function(f){
|
|
7803
|
+
var mod=f.getAttribute('data-module');
|
|
7804
|
+
if(activeMod!=='ALL'&&mod!==activeMod){f.style.display='none';return;}
|
|
7805
|
+
var hasVisible=f.querySelectorAll('.finding-card:not([style*="display: none"])').length>0;
|
|
7806
|
+
f.style.display=hasVisible?'':'none';
|
|
7807
|
+
});
|
|
7808
|
+
document.querySelectorAll('.severity-group-fold').forEach(function(g){
|
|
7809
|
+
g.style.display=g.querySelectorAll('.finding-card:not([style*="display: none"])').length?'':'none';
|
|
7810
|
+
});
|
|
7811
|
+
}
|
|
7812
|
+
document.querySelectorAll('.filter-btn[data-severity]').forEach(function(b){
|
|
7813
|
+
b.addEventListener('click',function(){
|
|
7814
|
+
document.querySelectorAll('.filter-btn[data-severity]').forEach(function(x){x.classList.remove('active')});
|
|
7815
|
+
b.classList.add('active');
|
|
7816
|
+
activeSev=b.getAttribute('data-severity');
|
|
7817
|
+
apply();
|
|
7818
|
+
});
|
|
7819
|
+
});
|
|
7820
|
+
var sel=document.getElementById('moduleFilter');
|
|
7821
|
+
if(sel)sel.addEventListener('change',function(){activeMod=sel.value;apply();});
|
|
7822
|
+
apply();
|
|
7823
|
+
})();
|
|
7824
|
+
</script>` : "";
|
|
7736
7825
|
return `<!DOCTYPE html>
|
|
7737
7826
|
<html lang="${htmlLang}">
|
|
7738
7827
|
<head>
|
|
@@ -7789,6 +7878,7 @@ ${buildServiceReminderHtml(modules, lang)}
|
|
|
7789
7878
|
|
|
7790
7879
|
<section>
|
|
7791
7880
|
<h2>${esc(t.allFindings)}</h2>
|
|
7881
|
+
${filterToolbarHtml}
|
|
7792
7882
|
${findingsHtml}
|
|
7793
7883
|
</section>
|
|
7794
7884
|
|
|
@@ -7800,6 +7890,7 @@ ${recsHtml}
|
|
|
7800
7890
|
</footer>
|
|
7801
7891
|
|
|
7802
7892
|
</div>
|
|
7893
|
+
${filterScript}
|
|
7803
7894
|
</body>
|
|
7804
7895
|
</html>`;
|
|
7805
7896
|
}
|