aws-security-mcp 0.7.0 → 0.7.2
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-BXloWmhE.css +2 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/bin/aws-security-mcp.js +478 -12
- package/dist/bin/aws-security-mcp.js.map +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.js +479 -12
- package/dist/src/index.js.map +1 -1
- package/package.json +2 -2
- package/dashboard/dist/assets/index-UN8P_PO6.css +0 -2
- /package/dashboard/dist/assets/{index-AKJ_-GfD.js → index-DsWFAp9v.js} +0 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
|
|
2
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--leading-tight:1.25;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.end{inset-inline-end:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-16{top:calc(var(--spacing) * 16)}.right-0{right:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-16{margin-top:calc(var(--spacing) * 16)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-\[300px\]{height:300px}.min-h-screen{min-height:100vh}.w-5{width:calc(var(--spacing) * 5)}.w-56{width:calc(var(--spacing) * 56)}.w-full{width:100%}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[200px\]{min-width:200px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-pointer{cursor:pointer}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:.25rem}.rounded-lg{border-radius:var(--radius-lg)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-blue-500\/30{border-color:#3080ff4d}@supports (color:color-mix(in lab, red, red)){.border-blue-500\/30{border-color:color-mix(in oklab, var(--color-blue-500) 30%, transparent)}}.border-current{border-color:currentColor}.border-green-500\/30{border-color:#00c7584d}@supports (color:color-mix(in lab, red, red)){.border-green-500\/30{border-color:color-mix(in oklab, var(--color-green-500) 30%, transparent)}}.border-orange-500\/30{border-color:#fe6e004d}@supports (color:color-mix(in lab, red, red)){.border-orange-500\/30{border-color:color-mix(in oklab, var(--color-orange-500) 30%, transparent)}}.border-red-500\/30{border-color:#fb2c364d}@supports (color:color-mix(in lab, red, red)){.border-red-500\/30{border-color:color-mix(in oklab, var(--color-red-500) 30%, transparent)}}.border-slate-600{border-color:var(--color-slate-600)}.border-slate-700{border-color:var(--color-slate-700)}.border-transparent{border-color:#0000}.border-yellow-500\/20{border-color:#edb20033}@supports (color:color-mix(in lab, red, red)){.border-yellow-500\/20{border-color:color-mix(in oklab, var(--color-yellow-500) 20%, transparent)}}.border-yellow-500\/30{border-color:#edb2004d}@supports (color:color-mix(in lab, red, red)){.border-yellow-500\/30{border-color:color-mix(in oklab, var(--color-yellow-500) 30%, transparent)}}.bg-blue-500\/20{background-color:#3080ff33}@supports (color:color-mix(in lab, red, red)){.bg-blue-500\/20{background-color:color-mix(in oklab, var(--color-blue-500) 20%, transparent)}}.bg-green-500\/20{background-color:#00c75833}@supports (color:color-mix(in lab, red, red)){.bg-green-500\/20{background-color:color-mix(in oklab, var(--color-green-500) 20%, transparent)}}.bg-orange-500\/20{background-color:#fe6e0033}@supports (color:color-mix(in lab, red, red)){.bg-orange-500\/20{background-color:color-mix(in oklab, var(--color-orange-500) 20%, transparent)}}.bg-red-500\/20{background-color:#fb2c3633}@supports (color:color-mix(in lab, red, red)){.bg-red-500\/20{background-color:color-mix(in oklab, var(--color-red-500) 20%, transparent)}}.bg-slate-700{background-color:var(--color-slate-700)}.bg-slate-800{background-color:var(--color-slate-800)}.bg-slate-800\/30{background-color:#1d293d4d}@supports (color:color-mix(in lab, red, red)){.bg-slate-800\/30{background-color:color-mix(in oklab, var(--color-slate-800) 30%, transparent)}}.bg-slate-800\/50{background-color:#1d293d80}@supports (color:color-mix(in lab, red, red)){.bg-slate-800\/50{background-color:color-mix(in oklab, var(--color-slate-800) 50%, transparent)}}.bg-slate-800\/80{background-color:#1d293dcc}@supports (color:color-mix(in lab, red, red)){.bg-slate-800\/80{background-color:color-mix(in oklab, var(--color-slate-800) 80%, transparent)}}.bg-slate-900{background-color:var(--color-slate-900)}.bg-yellow-500\/5{background-color:#edb2000d}@supports (color:color-mix(in lab, red, red)){.bg-yellow-500\/5{background-color:color-mix(in oklab, var(--color-yellow-500) 5%, transparent)}}.bg-yellow-500\/20{background-color:#edb20033}@supports (color:color-mix(in lab, red, red)){.bg-yellow-500\/20{background-color:color-mix(in oklab, var(--color-yellow-500) 20%, transparent)}}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-8{padding-block:calc(var(--spacing) * 8)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.text-blue-400{color:var(--color-blue-400)}.text-green-400{color:var(--color-green-400)}.text-orange-400{color:var(--color-orange-400)}.text-red-400{color:var(--color-red-400)}.text-slate-50{color:var(--color-slate-50)}.text-slate-100{color:var(--color-slate-100)}.text-slate-200{color:var(--color-slate-200)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-yellow-400{color:var(--color-yellow-400)}.text-yellow-400\/80{color:#fac800cc}@supports (color:color-mix(in lab, red, red)){.text-yellow-400\/80{color:color-mix(in oklab, var(--color-yellow-400) 80%, transparent)}}.text-yellow-500\/60{color:#edb20099}@supports (color:color-mix(in lab, red, red)){.text-yellow-500\/60{color:color-mix(in oklab, var(--color-yellow-500) 60%, transparent)}}.placeholder-slate-500::placeholder{color:var(--color-slate-500)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.hover\:border-slate-400:hover{border-color:var(--color-slate-400)}.hover\:border-slate-500:hover{border-color:var(--color-slate-500)}.hover\:bg-slate-700\/50:hover{background-color:#31415880}@supports (color:color-mix(in lab, red, red)){.hover\:bg-slate-700\/50:hover{background-color:color-mix(in oklab, var(--color-slate-700) 50%, transparent)}}.hover\:text-slate-200:hover{color:var(--color-slate-200)}}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}@media (width>=40rem){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width>=48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width>=64rem){.lg\:mt-0{margin-top:calc(var(--spacing) * 0)}.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}}body{color:#f8fafc;background-color:#0f172a;margin:0;font-family:Inter,system-ui,-apple-system,sans-serif}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:#1e293b}::-webkit-scrollbar-thumb{background:#475569;border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#64748b}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>AWS Security Dashboard</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DsWFAp9v.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BXloWmhE.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body class="bg-slate-900 text-slate-50">
|
|
12
12
|
<div id="root"></div>
|
|
@@ -237,7 +237,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
237
237
|
import { z } from "zod";
|
|
238
238
|
|
|
239
239
|
// src/version.ts
|
|
240
|
-
var VERSION = "0.7.
|
|
240
|
+
var VERSION = "0.7.2";
|
|
241
241
|
|
|
242
242
|
// src/utils/aws-client.ts
|
|
243
243
|
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
|
|
@@ -1245,7 +1245,7 @@ async function dnsResolves(hostname) {
|
|
|
1245
1245
|
var DnsDanglingScanner = class {
|
|
1246
1246
|
moduleName = "dns_dangling";
|
|
1247
1247
|
async scan(ctx) {
|
|
1248
|
-
const { region, partition
|
|
1248
|
+
const { region, partition } = ctx;
|
|
1249
1249
|
const startMs = Date.now();
|
|
1250
1250
|
const findings = [];
|
|
1251
1251
|
const warnings = [];
|
|
@@ -4012,6 +4012,39 @@ var zhI18n = {
|
|
|
4012
4012
|
action: "\u5B89\u88C5 SSM Agent \u5E76\u914D\u7F6E Patch Manager"
|
|
4013
4013
|
}
|
|
4014
4014
|
},
|
|
4015
|
+
// HW Defense HTML Report
|
|
4016
|
+
hwReportTitle: "\u62A4\u7F51\u84DD\u961F\u5B89\u5168\u8BC4\u4F30\u62A5\u544A",
|
|
4017
|
+
hwAutoCheck: "\u81EA\u52A8\u5316\u68C0\u67E5",
|
|
4018
|
+
hwManualCheck: "\u4EBA\u5DE5\u786E\u8BA4\u4E8B\u9879",
|
|
4019
|
+
hwNoAutoCheck: "\u6B64\u9879\u65E0\u81EA\u52A8\u5316\u68C0\u67E5",
|
|
4020
|
+
hwClean: "\u672A\u53D1\u73B0\u95EE\u9898",
|
|
4021
|
+
hwTotalFindings: "\u53D1\u73B0\u603B\u6570",
|
|
4022
|
+
hwSectionsChecked: "\u68C0\u67E5\u5206\u7C7B",
|
|
4023
|
+
hwAutoVerified: "\u81EA\u52A8\u9A8C\u8BC1",
|
|
4024
|
+
hwManualPending: "\u4EBA\u5DE5\u5F85\u786E\u8BA4",
|
|
4025
|
+
hwManualCount: (n) => `${n} \u9879\u4EBA\u5DE5\u786E\u8BA4`,
|
|
4026
|
+
hwAffectedResources: (n) => `\u67E5\u770B\u53D7\u5F71\u54CD\u8D44\u6E90 (${n})`,
|
|
4027
|
+
hwRemediation: "\u4FEE\u590D\u5EFA\u8BAE",
|
|
4028
|
+
hwSectionNames: {
|
|
4029
|
+
attack_surface: { name: "\u653B\u51FB\u9762\u6536\u655B", icon: "\u{1F3AF}" },
|
|
4030
|
+
vulnerability_patch: { name: "\u6F0F\u6D1E\u4E0E\u8865\u4E01\u7BA1\u7406", icon: "\u{1FA79}" },
|
|
4031
|
+
identity_credential: { name: "\u8EAB\u4EFD\u4E0E\u51ED\u8BC1\u5B89\u5168", icon: "\u{1F511}" },
|
|
4032
|
+
transport_security: { name: "\u4F20\u8F93\u4E0E\u5B9E\u4F8B\u5B89\u5168", icon: "\u{1F512}" },
|
|
4033
|
+
security_services: { name: "\u5B89\u5168\u670D\u52A1\u72B6\u6001", icon: "\u{1F6E1}\uFE0F" },
|
|
4034
|
+
emergency_response: { name: "\u5E94\u6025\u54CD\u5E94\u51C6\u5907", icon: "\u{1F6A8}" },
|
|
4035
|
+
environment_control: { name: "\u73AF\u5883\u5904\u7F6E", icon: "\u{1F3D7}\uFE0F" },
|
|
4036
|
+
post_review: { name: "\u62A4\u7F51\u540E\u4F18\u5316", icon: "\u{1F4CA}" }
|
|
4037
|
+
},
|
|
4038
|
+
hwManualItems: {
|
|
4039
|
+
attack_surface: ["\u7ED8\u5236\u51FA\u5165\u7AD9\u8DEF\u5F84\u67B6\u6784\u56FE\uFF0C\u6807\u6CE8\u6240\u6709\u4E92\u8054\u7F51/DX\u4E13\u7EBF\u51FA\u5165\u7AD9\u8DEF\u5F84"],
|
|
4040
|
+
vulnerability_patch: ["\u8054\u7CFB\u5B89\u5168\u5382\u5546\u8FDB\u884C\u6A21\u62DF\u653B\u51FB\u6F14\u7EC3\uFF08\u6E17\u900F\u6D4B\u8BD5\uFF09", "\u5173\u6CE8 AWS \u5B89\u5168\u516C\u544A\uFF08\u5DF2\u77E5\u6F0F\u6D1E\u4E0E\u8865\u4E01\uFF09"],
|
|
4041
|
+
identity_credential: ["\u6240\u6709 IAM \u7528\u6237\u7ED1\u5B9A MFA", "AKSK \u8F6E\u8F6C\u5468\u671F \u2264 90 \u5929", "\u907F\u514D\u5171\u4EAB\u8D26\u6237\u4F7F\u7528", "S3/Lambda/\u5E94\u7528\u4EE3\u7801\u4E2D\u65E0\u660E\u6587\u5BC6\u7801"],
|
|
4042
|
+
transport_security: ["\u786E\u8BA4\u6240\u6709\u5BF9\u5916\u670D\u52A1\u4F7F\u7528 TLS 1.2+", "\u68C0\u67E5\u5185\u90E8\u670D\u52A1\u95F4\u901A\u4FE1\u662F\u5426\u52A0\u5BC6"],
|
|
4043
|
+
security_services: ["\u786E\u8BA4 Security Hub \u5DF2\u5F00\u542F\u5E76\u914D\u7F6E\u6807\u51C6", "\u786E\u8BA4 GuardDuty \u5DF2\u5728\u6240\u6709\u533A\u57DF\u5F00\u542F", "\u786E\u8BA4 CloudTrail \u591A\u533A\u57DF\u65E5\u5FD7\u8BB0\u5F55\u5DF2\u5F00\u542F", "\u786E\u8BA4 Config Rules \u5DF2\u914D\u7F6E"],
|
|
4044
|
+
emergency_response: ["\u51C6\u5907\u4E13\u7528\u9694\u79BB\u5B89\u5168\u7EC4\uFF08\u65E0 Inbound/Outbound \u89C4\u5219\uFF09", "\u5236\u5B9A\u5B9E\u4F8B\u9694\u79BB SOP\uFF1A\u544A\u8B66 \u2192 \u6392\u67E5 \u2192 \u5C01\u9501\u653B\u51FBIP \u2192 \u7F51\u7EDC\u9694\u79BB \u2192 \u5B89\u5168\u5904\u7F6E \u2192 \u8BB0\u5F55\u653B\u51FB\u9879", "\u7EC4\u5EFA 7\xD724 \u76D1\u63A7\u5FEB\u901F\u54CD\u5E94\u56E2\u961F", "\u521B\u5EFA\u62A4\u7F51\u671F\u95F4\u4E13\u7528\u6C9F\u901A\u6E20\u9053\uFF08\u4F01\u5FAE/\u9489\u9489/\u98DE\u4E66/Chime\uFF09", "\u4E0E AWS TAM \u5EFA\u7ACB WAR-ROOM \u8054\u7CFB\uFF08\u4F01\u4E1A\u7EA7\u652F\u6301\u5BA2\u6237\uFF09"],
|
|
4045
|
+
environment_control: ["\u975E\u6838\u5FC3\u7CFB\u7EDF\u5728\u62A4\u7F51\u671F\u95F4\u5173\u95ED", "\u6D4B\u8BD5/\u5F00\u53D1\u73AF\u5883\u5173\u95ED\u6216\u4E0E\u751F\u4EA7\u4FDD\u6301\u540C\u7B49\u5B89\u5168\u57FA\u7EBF", "\u786E\u8BA4\u54EA\u4E9B\u73AF\u5883\u53EF\u4EE5\u7D27\u6025\u5173\u505C\uFF0C\u907F\u514D\u653B\u51FB\u6269\u6563"],
|
|
4046
|
+
post_review: ["\u9488\u5BF9\u653B\u51FB\u62A5\u544A\u9010\u9879\u5E94\u7B54\u4E0E\u4FEE\u590D", "\u4E0E\u5B89\u5168\u56E2\u961F\u5EFA\u7ACB\u5468\u671F\u6027\u5B89\u5168\u7EF4\u62A4\u6D41\u7A0B", "\u6301\u7EED\u8865\u5168\u5B89\u5168\u98CE\u9669"]
|
|
4047
|
+
},
|
|
4015
4048
|
// HW Checklist (full composite)
|
|
4016
4049
|
hwChecklist: `
|
|
4017
4050
|
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
@@ -4288,6 +4321,39 @@ var enI18n = {
|
|
|
4288
4321
|
action: "Install SSM Agent and configure Patch Manager"
|
|
4289
4322
|
}
|
|
4290
4323
|
},
|
|
4324
|
+
// HW Defense HTML Report
|
|
4325
|
+
hwReportTitle: "HW Defense Security Assessment Report",
|
|
4326
|
+
hwAutoCheck: "Automated Checks",
|
|
4327
|
+
hwManualCheck: "Manual Verification Items",
|
|
4328
|
+
hwNoAutoCheck: "No automated checks for this section",
|
|
4329
|
+
hwClean: "No issues found",
|
|
4330
|
+
hwTotalFindings: "Total Findings",
|
|
4331
|
+
hwSectionsChecked: "Sections Checked",
|
|
4332
|
+
hwAutoVerified: "Auto-Verified",
|
|
4333
|
+
hwManualPending: "Manual Pending",
|
|
4334
|
+
hwManualCount: (n) => `${n} manual item${n === 1 ? "" : "s"}`,
|
|
4335
|
+
hwAffectedResources: (n) => `View affected resources (${n})`,
|
|
4336
|
+
hwRemediation: "Remediation",
|
|
4337
|
+
hwSectionNames: {
|
|
4338
|
+
attack_surface: { name: "Attack Surface Reduction", icon: "\u{1F3AF}" },
|
|
4339
|
+
vulnerability_patch: { name: "Vulnerability & Patch Management", icon: "\u{1FA79}" },
|
|
4340
|
+
identity_credential: { name: "Identity & Credential Security", icon: "\u{1F511}" },
|
|
4341
|
+
transport_security: { name: "Transport & Instance Security", icon: "\u{1F512}" },
|
|
4342
|
+
security_services: { name: "Security Service Status", icon: "\u{1F6E1}\uFE0F" },
|
|
4343
|
+
emergency_response: { name: "Emergency Response Readiness", icon: "\u{1F6A8}" },
|
|
4344
|
+
environment_control: { name: "Environment Control", icon: "\u{1F3D7}\uFE0F" },
|
|
4345
|
+
post_review: { name: "Post-Drill Optimization", icon: "\u{1F4CA}" }
|
|
4346
|
+
},
|
|
4347
|
+
hwManualItems: {
|
|
4348
|
+
attack_surface: ["Draw ingress/egress path architecture diagram, mark all Internet/DX dedicated line paths"],
|
|
4349
|
+
vulnerability_patch: ["Contact security vendors for simulated attack drills (penetration testing)", "Monitor AWS security advisories (known vulnerabilities and patches)"],
|
|
4350
|
+
identity_credential: ["All IAM users must have MFA enabled", "Access key rotation cycle \u2264 90 days", "Avoid shared account usage", "No plaintext passwords in S3/Lambda/application code"],
|
|
4351
|
+
transport_security: ["Verify all external-facing services use TLS 1.2+", "Check internal service-to-service communication encryption"],
|
|
4352
|
+
security_services: ["Verify Security Hub is enabled with standards configured", "Verify GuardDuty is enabled in all regions", "Verify CloudTrail multi-region logging is enabled", "Verify Config Rules are configured"],
|
|
4353
|
+
emergency_response: ["Prepare dedicated isolation security groups (no Inbound/Outbound rules)", "Establish instance isolation SOP: Alert \u2192 Investigate \u2192 Block attacker IP \u2192 Network isolation \u2192 Security response \u2192 Log attack details", "Form 7\xD724 monitoring rapid response team", "Create dedicated communication channels for the drill period (Teams/Slack/Chime)", "Establish WAR-ROOM connection with AWS TAM (Enterprise Support customers)"],
|
|
4354
|
+
environment_control: ["Shut down non-critical systems during the drill period", "Shut down test/dev environments or maintain same security baseline as production", "Confirm which environments can be emergency-stopped to prevent attack propagation"],
|
|
4355
|
+
post_review: ["Address and remediate each item from the attack report", "Establish periodic security maintenance processes with the security team", "Continuously fill security risk gaps"]
|
|
4356
|
+
},
|
|
4291
4357
|
// HW Checklist (full composite)
|
|
4292
4358
|
hwChecklist: `
|
|
4293
4359
|
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
@@ -7262,11 +7328,24 @@ function generateMlps3Report(scanResults, lang) {
|
|
|
7262
7328
|
function esc(s) {
|
|
7263
7329
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
7264
7330
|
}
|
|
7331
|
+
function safeUrl(url) {
|
|
7332
|
+
try {
|
|
7333
|
+
const u = new URL(url);
|
|
7334
|
+
if (u.protocol === "https:" || u.protocol === "http:") return url;
|
|
7335
|
+
return null;
|
|
7336
|
+
} catch {
|
|
7337
|
+
return null;
|
|
7338
|
+
}
|
|
7339
|
+
}
|
|
7265
7340
|
function escWithLinks(s) {
|
|
7266
7341
|
const parts = s.split(/(https?:\/\/\S+)/);
|
|
7267
7342
|
return parts.map((part, i) => {
|
|
7268
7343
|
if (i % 2 === 1) {
|
|
7269
|
-
|
|
7344
|
+
const safe = safeUrl(part);
|
|
7345
|
+
if (safe) {
|
|
7346
|
+
return `<a href="${esc(safe)}" style="color:#60a5fa" target="_blank" rel="noopener">${esc(part)}</a>`;
|
|
7347
|
+
}
|
|
7348
|
+
return esc(part);
|
|
7270
7349
|
}
|
|
7271
7350
|
return esc(part);
|
|
7272
7351
|
}).join("");
|
|
@@ -7994,7 +8073,8 @@ ${rest}
|
|
|
7994
8073
|
const renderRec = (r) => {
|
|
7995
8074
|
const sev = r.severity.toLowerCase();
|
|
7996
8075
|
const countLabel = r.count > 1 ? ` (× ${r.count})` : "";
|
|
7997
|
-
const
|
|
8076
|
+
const safeLink = r.url ? safeUrl(r.url) : null;
|
|
8077
|
+
const linkHtml = safeLink ? ` <a href="${esc(safeLink)}" style="color:#60a5fa" target="_blank" rel="noopener">📖</a>` : "";
|
|
7998
8078
|
return `<li><span class="badge badge-${esc(sev)}">${esc(r.severity)}</span> ${esc(r.text)}${countLabel}${linkHtml}</li>`;
|
|
7999
8079
|
};
|
|
8000
8080
|
const TOP_N = 10;
|
|
@@ -8153,7 +8233,6 @@ function generateMlps3HtmlReport(scanResults, history, lang) {
|
|
|
8153
8233
|
</section>`;
|
|
8154
8234
|
}
|
|
8155
8235
|
const isEn = (lang ?? "zh") === "en";
|
|
8156
|
-
const itemCat = (r) => isEn ? r.item.categoryEn : r.item.categoryCn;
|
|
8157
8236
|
const itemControl = (r) => isEn ? r.item.controlEn : r.item.controlCn;
|
|
8158
8237
|
const itemReq = (r) => isEn ? r.item.requirementEn : r.item.requirementCn;
|
|
8159
8238
|
const categoryMap = /* @__PURE__ */ new Map();
|
|
@@ -8355,7 +8434,8 @@ ${itemsHtml}
|
|
|
8355
8434
|
const renderMlpsRec = (r) => {
|
|
8356
8435
|
const sev = r.severity.toLowerCase();
|
|
8357
8436
|
const countLabel = r.count > 1 ? ` (× ${r.count})` : "";
|
|
8358
|
-
const
|
|
8437
|
+
const safeLink = r.url ? safeUrl(r.url) : null;
|
|
8438
|
+
const linkHtml = safeLink ? ` <a href="${esc(safeLink)}" style="color:#60a5fa" target="_blank" rel="noopener">📖</a>` : "";
|
|
8359
8439
|
return `<li><span class="badge badge-${esc(sev)}">${esc(r.severity)}</span> ${esc(r.text)}${countLabel}${linkHtml}</li>`;
|
|
8360
8440
|
};
|
|
8361
8441
|
const MLPS_TOP_N = 10;
|
|
@@ -8448,6 +8528,374 @@ ${naNote}
|
|
|
8448
8528
|
</html>`;
|
|
8449
8529
|
}
|
|
8450
8530
|
|
|
8531
|
+
// src/tools/hw-report.ts
|
|
8532
|
+
function esc2(s) {
|
|
8533
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
8534
|
+
}
|
|
8535
|
+
function safeUrl2(url) {
|
|
8536
|
+
try {
|
|
8537
|
+
const u = new URL(url);
|
|
8538
|
+
if (u.protocol === "https:" || u.protocol === "http:") return url;
|
|
8539
|
+
return null;
|
|
8540
|
+
} catch {
|
|
8541
|
+
return null;
|
|
8542
|
+
}
|
|
8543
|
+
}
|
|
8544
|
+
function escWithLinks2(s) {
|
|
8545
|
+
const parts = s.split(/(https?:\/\/\S+)/);
|
|
8546
|
+
return parts.map((part, i) => {
|
|
8547
|
+
if (i % 2 === 1) {
|
|
8548
|
+
const safe = safeUrl2(part);
|
|
8549
|
+
if (safe) {
|
|
8550
|
+
return `<a href="${esc2(safe)}" style="color:#60a5fa" target="_blank" rel="noopener">${esc2(part)}</a>`;
|
|
8551
|
+
}
|
|
8552
|
+
return esc2(part);
|
|
8553
|
+
}
|
|
8554
|
+
return esc2(part);
|
|
8555
|
+
}).join("");
|
|
8556
|
+
}
|
|
8557
|
+
var SEVERITY_ORDER3 = ["CRITICAL", "HIGH", "MEDIUM", "LOW"];
|
|
8558
|
+
var HW_SECTIONS = [
|
|
8559
|
+
{
|
|
8560
|
+
id: "attack_surface",
|
|
8561
|
+
autoModules: ["network_reachability", "dns_dangling", "public_access_verify", "waf_coverage"],
|
|
8562
|
+
shKeywords: ["network", "public", "exposure", "port", "waf", "firewall", "vpc", "securitygroup"]
|
|
8563
|
+
},
|
|
8564
|
+
{
|
|
8565
|
+
id: "vulnerability_patch",
|
|
8566
|
+
autoModules: ["patch_compliance_findings"],
|
|
8567
|
+
shKeywords: ["vulnerability", "patch", "cve", "inspector", "software"]
|
|
8568
|
+
},
|
|
8569
|
+
{
|
|
8570
|
+
id: "identity_credential",
|
|
8571
|
+
autoModules: ["iam_privilege_escalation", "secret_exposure"],
|
|
8572
|
+
shKeywords: ["iam", "access", "privilege", "credential", "password", "mfa", "key rotation"]
|
|
8573
|
+
},
|
|
8574
|
+
{
|
|
8575
|
+
id: "transport_security",
|
|
8576
|
+
autoModules: ["ssl_certificate", "imdsv2_enforcement"],
|
|
8577
|
+
shKeywords: ["ssl", "tls", "certificate", "imds", "metadata"]
|
|
8578
|
+
},
|
|
8579
|
+
{
|
|
8580
|
+
id: "security_services",
|
|
8581
|
+
autoModules: ["service_detection"],
|
|
8582
|
+
shKeywords: []
|
|
8583
|
+
},
|
|
8584
|
+
{
|
|
8585
|
+
id: "emergency_response",
|
|
8586
|
+
autoModules: [],
|
|
8587
|
+
shKeywords: []
|
|
8588
|
+
},
|
|
8589
|
+
{
|
|
8590
|
+
id: "environment_control",
|
|
8591
|
+
autoModules: [],
|
|
8592
|
+
shKeywords: []
|
|
8593
|
+
},
|
|
8594
|
+
{
|
|
8595
|
+
id: "post_review",
|
|
8596
|
+
autoModules: [],
|
|
8597
|
+
shKeywords: []
|
|
8598
|
+
}
|
|
8599
|
+
];
|
|
8600
|
+
function hwCss() {
|
|
8601
|
+
return `
|
|
8602
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
8603
|
+
body{background:#0f172a;color:#f8fafc;font-family:Inter,system-ui,-apple-system,sans-serif;line-height:1.6;font-size:14px}
|
|
8604
|
+
.container{max-width:900px;margin:0 auto;padding:40px 24px}
|
|
8605
|
+
header{text-align:center;margin-bottom:40px;border-bottom:1px solid #334155;padding-bottom:24px}
|
|
8606
|
+
header h1{font-size:28px;font-weight:700;margin-bottom:8px;letter-spacing:-0.5px}
|
|
8607
|
+
.meta{color:#94a3b8;font-size:13px}
|
|
8608
|
+
h2{font-size:20px;font-weight:600;margin:32px 0 16px;padding-bottom:8px;border-bottom:1px solid #334155}
|
|
8609
|
+
h3{font-size:16px;font-weight:600;margin:16px 0 8px}
|
|
8610
|
+
h4{font-size:14px;font-weight:600;margin:12px 0 4px}
|
|
8611
|
+
.summary-cards{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:32px;justify-content:center}
|
|
8612
|
+
.summary-card{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:16px 20px;text-align:center;min-width:100px;flex:1}
|
|
8613
|
+
.summary-card .stat-count{font-size:28px;font-weight:700}
|
|
8614
|
+
.summary-card .stat-label{font-size:12px;color:#94a3b8;margin-top:2px}
|
|
8615
|
+
.badge{display:inline-block;padding:2px 10px;border-radius:4px;font-size:11px;font-weight:700;letter-spacing:0.5px;color:#fff}
|
|
8616
|
+
.badge-critical{background:#ef4444}
|
|
8617
|
+
.badge-high{background:#f97316}
|
|
8618
|
+
.badge-medium{background:#eab308;color:#1e293b}
|
|
8619
|
+
.badge-low{background:#22c55e;color:#1e293b}
|
|
8620
|
+
.hw-section{background:#1e293b;border:1px solid #334155;border-radius:8px;margin-bottom:16px;overflow:hidden}
|
|
8621
|
+
.hw-section>summary{cursor:pointer;padding:16px 20px;display:flex;align-items:center;gap:12px;list-style:none;font-size:16px;font-weight:600;user-select:none;flex-wrap:wrap}
|
|
8622
|
+
.hw-section>summary::-webkit-details-marker{display:none}
|
|
8623
|
+
.hw-section>summary::marker{content:""}
|
|
8624
|
+
.hw-section>summary::after{content:"\\25B6";font-size:12px;color:#64748b;flex-shrink:0;transition:transform 0.2s;margin-left:auto}
|
|
8625
|
+
.hw-section[open]>summary::after{transform:rotate(90deg)}
|
|
8626
|
+
.hw-section[open]>summary{border-bottom:1px solid #334155}
|
|
8627
|
+
.hw-section-body{padding:16px 20px}
|
|
8628
|
+
.hw-section-icon{font-size:20px}
|
|
8629
|
+
.hw-section-title{flex:1}
|
|
8630
|
+
.hw-section-stats{display:inline-flex;gap:8px;font-size:12px;flex-wrap:wrap}
|
|
8631
|
+
.hw-section-stats .badge{font-size:10px;padding:1px 8px}
|
|
8632
|
+
.hw-auto-section{margin-bottom:16px}
|
|
8633
|
+
.hw-auto-section h4{color:#60a5fa;margin-bottom:8px}
|
|
8634
|
+
.hw-manual-section h4{color:#fbbf24;margin-bottom:8px}
|
|
8635
|
+
.hw-clean{color:#22c55e;font-size:14px;padding:8px 12px;background:rgba(34,197,94,0.1);border-radius:6px}
|
|
8636
|
+
.hw-no-auto{color:#94a3b8;font-size:14px;padding:8px 12px;background:rgba(148,163,184,0.08);border-radius:6px}
|
|
8637
|
+
.hw-manual-item{display:flex;align-items:flex-start;gap:8px;padding:6px 12px;margin-bottom:4px;font-size:14px;color:#cbd5e1;border-radius:4px;background:rgba(148,163,184,0.06)}
|
|
8638
|
+
.hw-manual-checkbox{color:#fbbf24;font-size:16px;flex-shrink:0}
|
|
8639
|
+
.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}
|
|
8640
|
+
.sev-critical{border-left-color:#ef4444}
|
|
8641
|
+
.sev-high{border-left-color:#f97316}
|
|
8642
|
+
.sev-medium{border-left-color:#eab308}
|
|
8643
|
+
.sev-low{border-left-color:#22c55e}
|
|
8644
|
+
.finding-title-text{font-weight:600;font-size:13px;flex:1;min-width:200px}
|
|
8645
|
+
.finding-resource{color:#94a3b8;font-size:12px;max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
8646
|
+
.finding-card>details{width:100%;margin-top:4px}
|
|
8647
|
+
.finding-card>details>summary{cursor:pointer;font-size:12px;color:#60a5fa;user-select:none}
|
|
8648
|
+
.finding-card-body{padding:8px 0}
|
|
8649
|
+
.finding-card-body p{color:#cbd5e1;font-size:13px;margin-bottom:4px}
|
|
8650
|
+
.finding-card-body ol{padding-left:20px}
|
|
8651
|
+
.finding-card-body li{color:#cbd5e1;font-size:13px;margin-bottom:2px}
|
|
8652
|
+
.hw-finding-group{background:#1e293b;border:1px solid #334155;border-radius:8px;padding:12px 16px;margin-bottom:8px}
|
|
8653
|
+
.hw-finding-header{display:flex;align-items:center;gap:8px}
|
|
8654
|
+
.hw-finding-title{color:#e2e8f0;font-size:14px;flex:1}
|
|
8655
|
+
.hw-finding-count{color:#94a3b8;font-size:13px;font-weight:600;background:#334155;padding:2px 8px;border-radius:4px}
|
|
8656
|
+
.hw-finding-resources{padding:8px 0}
|
|
8657
|
+
.hw-resource-item{font-size:12px;color:#94a3b8;padding:2px 0;font-family:monospace}
|
|
8658
|
+
.hw-finding-remediation{border-top:1px solid #334155;margin-top:8px;padding-top:8px}
|
|
8659
|
+
.hw-finding-remediation ol{margin:4px 0;padding-left:20px;font-size:13px;color:#cbd5e1}
|
|
8660
|
+
footer{margin-top:48px;padding-top:24px;border-top:1px solid #334155;text-align:center}
|
|
8661
|
+
footer p{color:#64748b;font-size:12px;margin-bottom:4px}
|
|
8662
|
+
@media print{
|
|
8663
|
+
body{background:#fff;color:#1e293b;-webkit-print-color-adjust:exact;print-color-adjust:exact}
|
|
8664
|
+
.container{max-width:100%;padding:20px}
|
|
8665
|
+
.hw-section,.summary-card,.finding-card{background:#fff;border:1px solid #e2e8f0}
|
|
8666
|
+
.badge{border:1px solid}
|
|
8667
|
+
header{border-bottom-color:#e2e8f0}
|
|
8668
|
+
h2{border-bottom-color:#e2e8f0}
|
|
8669
|
+
footer{border-top-color:#e2e8f0}
|
|
8670
|
+
.summary-card .stat-label{color:#64748b}
|
|
8671
|
+
.finding-title-text{color:#1e293b}
|
|
8672
|
+
.finding-resource{color:#64748b}
|
|
8673
|
+
.finding-card-body p,.finding-card-body li{color:#475569}
|
|
8674
|
+
.hw-section[open]>summary{border-bottom-color:#e2e8f0}
|
|
8675
|
+
.hw-manual-item{color:#475569}
|
|
8676
|
+
details{display:block}
|
|
8677
|
+
details>summary{display:block}
|
|
8678
|
+
details>:not(summary){display:block !important}
|
|
8679
|
+
}
|
|
8680
|
+
`;
|
|
8681
|
+
}
|
|
8682
|
+
function generateHwDefenseHtmlReport(scanResults, lang) {
|
|
8683
|
+
const t = getI18n(lang ?? "zh");
|
|
8684
|
+
const htmlLang = (lang ?? "zh") === "zh" ? "zh-CN" : "en";
|
|
8685
|
+
const { accountId, region, scanStart } = scanResults;
|
|
8686
|
+
const date = scanStart.split("T")[0];
|
|
8687
|
+
const scanTime = scanStart.replace("T", " ").replace(/\.\d+Z$/, " UTC");
|
|
8688
|
+
const moduleMap = /* @__PURE__ */ new Map();
|
|
8689
|
+
for (const mod of scanResults.modules) {
|
|
8690
|
+
const findings = mod.findings.map((f) => ({ ...f, module: f.module ?? mod.module }));
|
|
8691
|
+
moduleMap.set(mod.module, findings);
|
|
8692
|
+
}
|
|
8693
|
+
const assignedShFindings = /* @__PURE__ */ new Set();
|
|
8694
|
+
function shFindingKey(f) {
|
|
8695
|
+
return `${f.title}|${f.resourceId}|${f.resourceArn}`;
|
|
8696
|
+
}
|
|
8697
|
+
const sectionResults = [];
|
|
8698
|
+
for (const section of HW_SECTIONS) {
|
|
8699
|
+
const findings = [];
|
|
8700
|
+
for (const mod of section.autoModules) {
|
|
8701
|
+
if (mod === "security_hub_findings") continue;
|
|
8702
|
+
const modFindings = moduleMap.get(mod) ?? [];
|
|
8703
|
+
findings.push(...modFindings);
|
|
8704
|
+
}
|
|
8705
|
+
if (section.shKeywords.length > 0) {
|
|
8706
|
+
const shFindings = moduleMap.get("security_hub_findings") ?? [];
|
|
8707
|
+
for (const f of shFindings) {
|
|
8708
|
+
const key = shFindingKey(f);
|
|
8709
|
+
if (assignedShFindings.has(key)) continue;
|
|
8710
|
+
const searchText = `${f.title} ${f.description} ${f.impact}`.toLowerCase();
|
|
8711
|
+
if (section.shKeywords.some((kw) => searchText.includes(kw))) {
|
|
8712
|
+
findings.push(f);
|
|
8713
|
+
assignedShFindings.add(key);
|
|
8714
|
+
}
|
|
8715
|
+
}
|
|
8716
|
+
}
|
|
8717
|
+
const hasAutoModules = section.autoModules.length > 0 || section.shKeywords.length > 0;
|
|
8718
|
+
const hasAutoResults = hasAutoModules && (section.autoModules.some((m) => moduleMap.has(m)) || section.shKeywords.length > 0 && moduleMap.has("security_hub_findings"));
|
|
8719
|
+
const manualItems = t.hwManualItems[section.id] ?? [];
|
|
8720
|
+
sectionResults.push({
|
|
8721
|
+
id: section.id,
|
|
8722
|
+
findings,
|
|
8723
|
+
manualItems,
|
|
8724
|
+
hasAutoModules,
|
|
8725
|
+
hasAutoResults
|
|
8726
|
+
});
|
|
8727
|
+
}
|
|
8728
|
+
const totalFindings = sectionResults.reduce((sum, s) => sum + s.findings.length, 0);
|
|
8729
|
+
const sectionsChecked = sectionResults.filter((s) => s.hasAutoResults || s.manualItems.length > 0).length;
|
|
8730
|
+
const autoVerified = sectionResults.filter((s) => s.hasAutoResults).length;
|
|
8731
|
+
const totalManualItems = sectionResults.reduce((sum, s) => sum + s.manualItems.length, 0);
|
|
8732
|
+
function groupFindings(findings) {
|
|
8733
|
+
const groups = /* @__PURE__ */ new Map();
|
|
8734
|
+
const groupTitles = /* @__PURE__ */ new Map();
|
|
8735
|
+
for (const f of findings) {
|
|
8736
|
+
const cveMatch = f.title.match(/CVE-\d{4}-\d+/i);
|
|
8737
|
+
if (cveMatch) {
|
|
8738
|
+
const key2 = `cve:${cveMatch[0].toUpperCase()}`;
|
|
8739
|
+
if (!groups.has(key2)) {
|
|
8740
|
+
groups.set(key2, []);
|
|
8741
|
+
groupTitles.set(key2, f.title);
|
|
8742
|
+
}
|
|
8743
|
+
groups.get(key2).push(f);
|
|
8744
|
+
continue;
|
|
8745
|
+
}
|
|
8746
|
+
const controlMatch = f.title.match(/[A-Z]+\.\d+/);
|
|
8747
|
+
if (controlMatch) {
|
|
8748
|
+
const key2 = `ctrl:${controlMatch[0]}`;
|
|
8749
|
+
if (!groups.has(key2)) {
|
|
8750
|
+
groups.set(key2, []);
|
|
8751
|
+
groupTitles.set(key2, f.title);
|
|
8752
|
+
}
|
|
8753
|
+
groups.get(key2).push(f);
|
|
8754
|
+
continue;
|
|
8755
|
+
}
|
|
8756
|
+
const key = `title:${f.title}`;
|
|
8757
|
+
if (!groups.has(key)) {
|
|
8758
|
+
groups.set(key, []);
|
|
8759
|
+
groupTitles.set(key, f.title);
|
|
8760
|
+
}
|
|
8761
|
+
groups.get(key).push(f);
|
|
8762
|
+
}
|
|
8763
|
+
const result = [];
|
|
8764
|
+
for (const [key, gFindings] of groups) {
|
|
8765
|
+
let highestSeverity = "LOW";
|
|
8766
|
+
for (const f of gFindings) {
|
|
8767
|
+
if (SEVERITY_ORDER3.indexOf(f.severity) < SEVERITY_ORDER3.indexOf(highestSeverity)) {
|
|
8768
|
+
highestSeverity = f.severity;
|
|
8769
|
+
}
|
|
8770
|
+
}
|
|
8771
|
+
result.push({ title: groupTitles.get(key), findings: gFindings, highestSeverity });
|
|
8772
|
+
}
|
|
8773
|
+
return result;
|
|
8774
|
+
}
|
|
8775
|
+
const renderGroup = (group) => {
|
|
8776
|
+
const sev = group.highestSeverity.toLowerCase();
|
|
8777
|
+
const count = group.findings.length;
|
|
8778
|
+
const first = group.findings[0];
|
|
8779
|
+
const resourceItems = group.findings.map((f) => `<div class="hw-resource-item">${esc2(f.resourceId)} — ${esc2(f.resourceArn)}</div>`).join("\n");
|
|
8780
|
+
const remediationSteps = first.remediationSteps.map((s) => `<li>${escWithLinks2(s)}</li>`).join("");
|
|
8781
|
+
return `<div class="hw-finding-group">
|
|
8782
|
+
<div class="hw-finding-header">
|
|
8783
|
+
<span class="badge badge-${esc2(sev)}">${esc2(group.highestSeverity)}</span>
|
|
8784
|
+
<span class="hw-finding-title">${esc2(group.title)}</span>
|
|
8785
|
+
<span class="hw-finding-count">×${count}</span>
|
|
8786
|
+
</div>
|
|
8787
|
+
<details>
|
|
8788
|
+
<summary>${t.hwAffectedResources(count)}</summary>
|
|
8789
|
+
<div class="hw-finding-resources">
|
|
8790
|
+
${resourceItems}
|
|
8791
|
+
</div>
|
|
8792
|
+
<div class="hw-finding-remediation">
|
|
8793
|
+
<strong>${esc2(t.hwRemediation)}:</strong>
|
|
8794
|
+
<ol>${remediationSteps}</ol>
|
|
8795
|
+
</div>
|
|
8796
|
+
</details>
|
|
8797
|
+
</div>`;
|
|
8798
|
+
};
|
|
8799
|
+
const sectionsHtml = sectionResults.map((section) => {
|
|
8800
|
+
const meta = t.hwSectionNames[section.id];
|
|
8801
|
+
if (!meta) return "";
|
|
8802
|
+
const sectionName = meta.name;
|
|
8803
|
+
const sectionIcon = meta.icon ?? "";
|
|
8804
|
+
const statBadges = [];
|
|
8805
|
+
if (section.findings.length > 0) {
|
|
8806
|
+
const sevCounts = {};
|
|
8807
|
+
for (const f of section.findings) {
|
|
8808
|
+
sevCounts[f.severity] = (sevCounts[f.severity] ?? 0) + 1;
|
|
8809
|
+
}
|
|
8810
|
+
for (const sev of SEVERITY_ORDER3) {
|
|
8811
|
+
if (sevCounts[sev]) {
|
|
8812
|
+
statBadges.push(
|
|
8813
|
+
`<span class="badge badge-${sev.toLowerCase()}">${sevCounts[sev]} ${sev}</span>`
|
|
8814
|
+
);
|
|
8815
|
+
}
|
|
8816
|
+
}
|
|
8817
|
+
} else if (section.hasAutoResults) {
|
|
8818
|
+
statBadges.push(`<span style="color:#22c55e;font-size:12px">✓ ${esc2(t.hwClean)}</span>`);
|
|
8819
|
+
}
|
|
8820
|
+
if (section.manualItems.length > 0) {
|
|
8821
|
+
statBadges.push(`<span style="color:#fbbf24;font-size:12px">☐ ${esc2(t.hwManualCount(section.manualItems.length))}</span>`);
|
|
8822
|
+
}
|
|
8823
|
+
let autoHtml;
|
|
8824
|
+
if (!section.hasAutoModules) {
|
|
8825
|
+
autoHtml = `<div class="hw-no-auto">⚪ ${esc2(t.hwNoAutoCheck)}</div>`;
|
|
8826
|
+
} else if (!section.hasAutoResults) {
|
|
8827
|
+
autoHtml = `<div class="hw-no-auto">⚪ ${esc2(t.hwNoAutoCheck)}</div>`;
|
|
8828
|
+
} else if (section.findings.length === 0) {
|
|
8829
|
+
autoHtml = `<div class="hw-clean">✔ ${esc2(t.hwClean)}</div>`;
|
|
8830
|
+
} else {
|
|
8831
|
+
const sorted = [...section.findings].sort((a, b) => {
|
|
8832
|
+
const sevDiff = SEVERITY_ORDER3.indexOf(a.severity) - SEVERITY_ORDER3.indexOf(b.severity);
|
|
8833
|
+
if (sevDiff !== 0) return sevDiff;
|
|
8834
|
+
return b.riskScore - a.riskScore;
|
|
8835
|
+
});
|
|
8836
|
+
const groups = groupFindings(sorted);
|
|
8837
|
+
autoHtml = groups.map(renderGroup).join("\n");
|
|
8838
|
+
}
|
|
8839
|
+
let manualHtml = "";
|
|
8840
|
+
if (section.manualItems.length > 0) {
|
|
8841
|
+
const items = section.manualItems.map((item) => `<div class="hw-manual-item"><span class="hw-manual-checkbox">□</span>${esc2(item)}</div>`).join("\n");
|
|
8842
|
+
manualHtml = `
|
|
8843
|
+
<div class="hw-manual-section">
|
|
8844
|
+
<h4>📋 ${esc2(t.hwManualCheck)}</h4>
|
|
8845
|
+
${items}
|
|
8846
|
+
</div>`;
|
|
8847
|
+
}
|
|
8848
|
+
return `<details class="hw-section">
|
|
8849
|
+
<summary>
|
|
8850
|
+
<span class="hw-section-icon">${esc2(sectionIcon)}</span>
|
|
8851
|
+
<span class="hw-section-title">${esc2(sectionName)}</span>
|
|
8852
|
+
<span class="hw-section-stats">${statBadges.join(" ")}</span>
|
|
8853
|
+
</summary>
|
|
8854
|
+
<div class="hw-section-body">
|
|
8855
|
+
<div class="hw-auto-section">
|
|
8856
|
+
<h4>🤖 ${esc2(t.hwAutoCheck)}</h4>
|
|
8857
|
+
${autoHtml}
|
|
8858
|
+
</div>
|
|
8859
|
+
${manualHtml}
|
|
8860
|
+
</div>
|
|
8861
|
+
</details>`;
|
|
8862
|
+
}).filter(Boolean).join("\n");
|
|
8863
|
+
const findingsColor = totalFindings === 0 ? "#22c55e" : totalFindings <= 5 ? "#eab308" : "#ef4444";
|
|
8864
|
+
return `<!DOCTYPE html>
|
|
8865
|
+
<html lang="${htmlLang}">
|
|
8866
|
+
<head>
|
|
8867
|
+
<meta charset="UTF-8">
|
|
8868
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
8869
|
+
<title>${esc2(t.hwReportTitle)} — ${esc2(date)}</title>
|
|
8870
|
+
<style>${hwCss()}</style>
|
|
8871
|
+
</head>
|
|
8872
|
+
<body>
|
|
8873
|
+
<div class="container">
|
|
8874
|
+
|
|
8875
|
+
<header>
|
|
8876
|
+
<h1>🛡️ ${esc2(t.hwReportTitle)}</h1>
|
|
8877
|
+
<div class="meta">${esc2(t.account)}: ${esc2(accountId)} | ${esc2(t.region)}: ${esc2(region)} | ${esc2(t.scanTime)}: ${esc2(scanTime)}</div>
|
|
8878
|
+
</header>
|
|
8879
|
+
|
|
8880
|
+
<section class="summary-cards">
|
|
8881
|
+
<div class="summary-card"><div class="stat-count" style="color:${findingsColor}">${totalFindings}</div><div class="stat-label">${esc2(t.hwTotalFindings)}</div></div>
|
|
8882
|
+
<div class="summary-card"><div class="stat-count" style="color:#60a5fa">${sectionsChecked}</div><div class="stat-label">${esc2(t.hwSectionsChecked)}</div></div>
|
|
8883
|
+
<div class="summary-card"><div class="stat-count" style="color:#22c55e">${autoVerified}</div><div class="stat-label">${esc2(t.hwAutoVerified)}</div></div>
|
|
8884
|
+
<div class="summary-card"><div class="stat-count" style="color:#fbbf24">${totalManualItems}</div><div class="stat-label">${esc2(t.hwManualPending)}</div></div>
|
|
8885
|
+
</section>
|
|
8886
|
+
|
|
8887
|
+
${sectionsHtml}
|
|
8888
|
+
|
|
8889
|
+
<footer>
|
|
8890
|
+
<p>${esc2(t.generatedBy)} v${VERSION}</p>
|
|
8891
|
+
|
|
8892
|
+
</footer>
|
|
8893
|
+
|
|
8894
|
+
</div>
|
|
8895
|
+
</body>
|
|
8896
|
+
</html>`;
|
|
8897
|
+
}
|
|
8898
|
+
|
|
8451
8899
|
// src/tools/save-results.ts
|
|
8452
8900
|
import { writeFileSync, readFileSync, mkdirSync, existsSync } from "fs";
|
|
8453
8901
|
import { join } from "path";
|
|
@@ -8518,7 +8966,7 @@ function saveResults(scanResults, outputDir) {
|
|
|
8518
8966
|
}
|
|
8519
8967
|
|
|
8520
8968
|
// src/tools/scan-groups.ts
|
|
8521
|
-
var
|
|
8969
|
+
var SEVERITY_ORDER4 = {
|
|
8522
8970
|
LOW: 0,
|
|
8523
8971
|
MEDIUM: 1,
|
|
8524
8972
|
HIGH: 2,
|
|
@@ -8527,8 +8975,8 @@ var SEVERITY_ORDER3 = {
|
|
|
8527
8975
|
function applyFindingsFilter(moduleName, findings, filter) {
|
|
8528
8976
|
let result = findings;
|
|
8529
8977
|
if (filter.minSeverity) {
|
|
8530
|
-
const minLevel =
|
|
8531
|
-
result = result.filter((f) => (
|
|
8978
|
+
const minLevel = SEVERITY_ORDER4[filter.minSeverity.toUpperCase()] ?? 0;
|
|
8979
|
+
result = result.filter((f) => (SEVERITY_ORDER4[f.severity] ?? 0) >= minLevel);
|
|
8532
8980
|
}
|
|
8533
8981
|
if (moduleName === "security_hub_findings" && filter.securityHubCategories?.length) {
|
|
8534
8982
|
const keywords = filter.securityHubCategories;
|
|
@@ -8562,10 +9010,10 @@ var SCAN_GROUPS = {
|
|
|
8562
9010
|
},
|
|
8563
9011
|
hw_defense: {
|
|
8564
9012
|
name: "\u62A4\u7F51\u84DD\u961F\u52A0\u56FA",
|
|
8565
|
-
description: "\u62A4\u7F51\u524D\u5B89\u5168\u81EA\u67E5 \u2014 \u653B\u51FB\u9762+\u5F31\u70B9\u8BC4\u4F30",
|
|
8566
|
-
modules: ["service_detection", "
|
|
9013
|
+
description: "\u62A4\u7F51\u524D\u5B89\u5168\u81EA\u67E5 \u2014 \u653B\u51FB\u8005\u89C6\u89D2\u7684\u653B\u51FB\u9762+\u5F31\u70B9\u8BC4\u4F30",
|
|
9014
|
+
modules: ["service_detection", "network_reachability", "dns_dangling", "public_access_verify", "ssl_certificate", "waf_coverage", "imdsv2_enforcement", "secret_exposure", "iam_privilege_escalation", "patch_compliance_findings", "security_hub_findings"],
|
|
8567
9015
|
findingsFilter: {
|
|
8568
|
-
|
|
9016
|
+
securityHubCategories: ["network", "public", "exposure", "port", "WAF", "vulnerability", "patch", "IAM", "iam", "access", "privilege", "secret", "credential", "password", "IMDS", "firewall", "VPC", "vpc", "SecurityGroup", "securitygroup", "CVE", "cve", "Inspector", "inspector", "software", "MFA", "mfa", "key rotation", "SSL", "ssl", "TLS", "tls", "certificate", "metadata", "CloudTrail", "cloudtrail", "logging", "audit", "encryption"],
|
|
8569
9017
|
minSeverity: "MEDIUM"
|
|
8570
9018
|
}
|
|
8571
9019
|
},
|
|
@@ -9087,6 +9535,7 @@ function createServer(defaultRegion) {
|
|
|
9087
9535
|
const summaryContent = content[0];
|
|
9088
9536
|
if (summaryContent && summaryContent.type === "text") {
|
|
9089
9537
|
summaryContent.text += "\n\n" + getHwDefenseChecklist(lang ?? "zh");
|
|
9538
|
+
summaryContent.text += "\n\n\u{1F4A1} Tip: Call generate_hw_defense_report with these scan results to get a dedicated HTML report organized by HW Defense SOP checklist categories.";
|
|
9090
9539
|
}
|
|
9091
9540
|
}
|
|
9092
9541
|
return { content };
|
|
@@ -9185,6 +9634,23 @@ function createServer(defaultRegion) {
|
|
|
9185
9634
|
}
|
|
9186
9635
|
}
|
|
9187
9636
|
);
|
|
9637
|
+
server.tool(
|
|
9638
|
+
"generate_hw_defense_report",
|
|
9639
|
+
"Generate an HTML report organized by HW Defense (\u62A4\u7F51) SOP checklist categories. Save as .html file.",
|
|
9640
|
+
{
|
|
9641
|
+
scan_results: z.string().describe("JSON string of FullScanResult from scan_group hw_defense or scan_all"),
|
|
9642
|
+
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
|
|
9643
|
+
},
|
|
9644
|
+
async ({ scan_results, lang }) => {
|
|
9645
|
+
try {
|
|
9646
|
+
const parsed = JSON.parse(scan_results);
|
|
9647
|
+
const report = generateHwDefenseHtmlReport(parsed, lang ?? "zh");
|
|
9648
|
+
return { content: [{ type: "text", text: report }] };
|
|
9649
|
+
} catch (err) {
|
|
9650
|
+
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
9651
|
+
}
|
|
9652
|
+
}
|
|
9653
|
+
);
|
|
9188
9654
|
server.tool(
|
|
9189
9655
|
"generate_maturity_report",
|
|
9190
9656
|
"Generate a security maturity assessment report from scan_all results. Requires service_detection module output. Read-only.",
|