aws-security-mcp 0.7.1 → 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.
@@ -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-AKJ_-GfD.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-UN8P_PO6.css">
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.1";
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";
@@ -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
@@ -8462,6 +8528,374 @@ ${naNote}
8462
8528
  </html>`;
8463
8529
  }
8464
8530
 
8531
+ // src/tools/hw-report.ts
8532
+ function esc2(s) {
8533
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
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)} &mdash; ${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">&times;${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">&#10003; ${esc2(t.hwClean)}</span>`);
8819
+ }
8820
+ if (section.manualItems.length > 0) {
8821
+ statBadges.push(`<span style="color:#fbbf24;font-size:12px">&#9744; ${esc2(t.hwManualCount(section.manualItems.length))}</span>`);
8822
+ }
8823
+ let autoHtml;
8824
+ if (!section.hasAutoModules) {
8825
+ autoHtml = `<div class="hw-no-auto">&#9898; ${esc2(t.hwNoAutoCheck)}</div>`;
8826
+ } else if (!section.hasAutoResults) {
8827
+ autoHtml = `<div class="hw-no-auto">&#9898; ${esc2(t.hwNoAutoCheck)}</div>`;
8828
+ } else if (section.findings.length === 0) {
8829
+ autoHtml = `<div class="hw-clean">&#10004; ${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">&#9633;</span>${esc2(item)}</div>`).join("\n");
8842
+ manualHtml = `
8843
+ <div class="hw-manual-section">
8844
+ <h4>&#128203; ${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>&#129302; ${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)} &mdash; ${esc2(date)}</title>
8870
+ <style>${hwCss()}</style>
8871
+ </head>
8872
+ <body>
8873
+ <div class="container">
8874
+
8875
+ <header>
8876
+ <h1>&#128737;&#65039; ${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
+
8465
8899
  // src/tools/save-results.ts
8466
8900
  import { writeFileSync, readFileSync, mkdirSync, existsSync } from "fs";
8467
8901
  import { join } from "path";
@@ -8532,7 +8966,7 @@ function saveResults(scanResults, outputDir) {
8532
8966
  }
8533
8967
 
8534
8968
  // src/tools/scan-groups.ts
8535
- var SEVERITY_ORDER3 = {
8969
+ var SEVERITY_ORDER4 = {
8536
8970
  LOW: 0,
8537
8971
  MEDIUM: 1,
8538
8972
  HIGH: 2,
@@ -8541,8 +8975,8 @@ var SEVERITY_ORDER3 = {
8541
8975
  function applyFindingsFilter(moduleName, findings, filter) {
8542
8976
  let result = findings;
8543
8977
  if (filter.minSeverity) {
8544
- const minLevel = SEVERITY_ORDER3[filter.minSeverity.toUpperCase()] ?? 0;
8545
- result = result.filter((f) => (SEVERITY_ORDER3[f.severity] ?? 0) >= minLevel);
8978
+ const minLevel = SEVERITY_ORDER4[filter.minSeverity.toUpperCase()] ?? 0;
8979
+ result = result.filter((f) => (SEVERITY_ORDER4[f.severity] ?? 0) >= minLevel);
8546
8980
  }
8547
8981
  if (moduleName === "security_hub_findings" && filter.securityHubCategories?.length) {
8548
8982
  const keywords = filter.securityHubCategories;
@@ -8576,10 +9010,10 @@ var SCAN_GROUPS = {
8576
9010
  },
8577
9011
  hw_defense: {
8578
9012
  name: "\u62A4\u7F51\u84DD\u961F\u52A0\u56FA",
8579
- description: "\u62A4\u7F51\u524D\u5B89\u5168\u81EA\u67E5 \u2014 \u653B\u51FB\u9762+\u5F31\u70B9\u8BC4\u4F30",
8580
- 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"],
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"],
8581
9015
  findingsFilter: {
8582
- guardDutyTypes: ["Backdoor", "Trojan", "PenTest", "CryptoCurrency"],
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"],
8583
9017
  minSeverity: "MEDIUM"
8584
9018
  }
8585
9019
  },
@@ -9101,6 +9535,7 @@ function createServer(defaultRegion) {
9101
9535
  const summaryContent = content[0];
9102
9536
  if (summaryContent && summaryContent.type === "text") {
9103
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.";
9104
9539
  }
9105
9540
  }
9106
9541
  return { content };
@@ -9199,6 +9634,23 @@ function createServer(defaultRegion) {
9199
9634
  }
9200
9635
  }
9201
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
+ );
9202
9654
  server.tool(
9203
9655
  "generate_maturity_report",
9204
9656
  "Generate a security maturity assessment report from scan_all results. Requires service_detection module output. Read-only.",