aws-security-mcp 0.7.5 → 0.7.6
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/README.md +68 -2
- package/README.zh-CN.md +311 -0
- package/dashboard/dist/assets/{index-DsWFAp9v.js → index-BoNhDdVm.js} +2 -2
- package/dashboard/dist/assets/index-DY4x_jab.css +2 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/bin/aws-security-mcp.js +239 -38
- package/dist/bin/aws-security-mcp.js.map +1 -1
- package/dist/src/index.d.ts +15 -1
- package/dist/src/index.js +241 -38
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/dashboard/dist/assets/index-BXloWmhE.css +0 -2
|
@@ -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-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--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-indigo-300:oklch(78.5% .115 274.713);--color-indigo-700:oklch(45.7% .24 277.023);--color-indigo-950:oklch(25.7% .09 281.288);--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;--leading-relaxed:1.625;--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-indigo-700\/50{border-color:#432dd780}@supports (color:color-mix(in lab, red, red)){.border-indigo-700\/50{border-color:color-mix(in oklab, var(--color-indigo-700) 50%, 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)}}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-slate-800{--tw-gradient-from:var(--color-slate-800);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-indigo-950{--tw-gradient-to:var(--color-indigo-950);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.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-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.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}.whitespace-pre-wrap{white-space:pre-wrap}.text-blue-400{color:var(--color-blue-400)}.text-green-400{color:var(--color-green-400)}.text-indigo-300{color:var(--color-indigo-300)}.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-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@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-BoNhDdVm.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DY4x_jab.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body class="bg-slate-900 text-slate-50">
|
|
12
12
|
<div id="root"></div>
|
|
@@ -205,7 +205,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
205
205
|
import { z } from "zod";
|
|
206
206
|
|
|
207
207
|
// src/version.ts
|
|
208
|
-
var VERSION = "0.7.
|
|
208
|
+
var VERSION = "0.7.6";
|
|
209
209
|
|
|
210
210
|
// src/utils/aws-client.ts
|
|
211
211
|
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
|
|
@@ -280,8 +280,7 @@ async function listOrgAccounts(region) {
|
|
|
280
280
|
return accounts;
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
// src/
|
|
284
|
-
var DEFAULT_CONCURRENCY = 5;
|
|
283
|
+
// src/utils/concurrency.ts
|
|
285
284
|
async function runWithConcurrency(tasks, limit) {
|
|
286
285
|
const results = [];
|
|
287
286
|
const executing = /* @__PURE__ */ new Set();
|
|
@@ -300,6 +299,9 @@ async function runWithConcurrency(tasks, limit) {
|
|
|
300
299
|
await Promise.all(executing);
|
|
301
300
|
return results;
|
|
302
301
|
}
|
|
302
|
+
|
|
303
|
+
// src/scanners/runner.ts
|
|
304
|
+
var DEFAULT_CONCURRENCY = 5;
|
|
303
305
|
var AGGREGATION_MODULES = /* @__PURE__ */ new Set([
|
|
304
306
|
"security_hub_findings",
|
|
305
307
|
"guardduty_findings",
|
|
@@ -870,24 +872,6 @@ import {
|
|
|
870
872
|
DescribeInstanceAttributeCommand
|
|
871
873
|
} from "@aws-sdk/client-ec2";
|
|
872
874
|
var USERDATA_CONCURRENCY = 5;
|
|
873
|
-
async function runWithConcurrency2(tasks, limit) {
|
|
874
|
-
const results = [];
|
|
875
|
-
const executing = /* @__PURE__ */ new Set();
|
|
876
|
-
for (let i = 0; i < tasks.length; i++) {
|
|
877
|
-
const idx = i;
|
|
878
|
-
const p = tasks[idx]().then((value) => {
|
|
879
|
-
results[idx] = { status: "fulfilled", value };
|
|
880
|
-
}).catch((reason) => {
|
|
881
|
-
results[idx] = { status: "rejected", reason };
|
|
882
|
-
}).finally(() => {
|
|
883
|
-
executing.delete(p);
|
|
884
|
-
});
|
|
885
|
-
executing.add(p);
|
|
886
|
-
if (executing.size >= limit) await Promise.race(executing);
|
|
887
|
-
}
|
|
888
|
-
await Promise.all(executing);
|
|
889
|
-
return results;
|
|
890
|
-
}
|
|
891
875
|
var SECRET_PATTERNS = [
|
|
892
876
|
{ name: "AWS Access Key", pattern: /AKIA[0-9A-Z]{16}/, matchType: "value" },
|
|
893
877
|
{ name: "Private Key", pattern: /-----BEGIN.*PRIVATE KEY-----/, matchType: "value" },
|
|
@@ -998,7 +982,7 @@ var SecretExposureScanner = class {
|
|
|
998
982
|
const raw = attrResp.UserData?.Value;
|
|
999
983
|
return { instId, userData: raw ? Buffer.from(raw, "base64").toString("utf-8") : void 0 };
|
|
1000
984
|
});
|
|
1001
|
-
const settled = await
|
|
985
|
+
const settled = await runWithConcurrency(userDataTasks, USERDATA_CONCURRENCY);
|
|
1002
986
|
for (let i = 0; i < instances.length; i++) {
|
|
1003
987
|
const result = settled[i];
|
|
1004
988
|
const inst = instances[i];
|
|
@@ -1978,7 +1962,8 @@ async function getBucketRegion(client, bucketName, defaultRegion, warnings) {
|
|
|
1978
1962
|
const resp = await client.send(
|
|
1979
1963
|
new GetBucketLocationCommand({ Bucket: bucketName })
|
|
1980
1964
|
);
|
|
1981
|
-
const
|
|
1965
|
+
const rawLoc = String(resp.LocationConstraint ?? "") || "us-east-1";
|
|
1966
|
+
const loc = rawLoc === "EU" ? "eu-west-1" : rawLoc;
|
|
1982
1967
|
return loc;
|
|
1983
1968
|
} catch (e) {
|
|
1984
1969
|
const msg = e instanceof Error ? e.message : String(e);
|
|
@@ -3934,6 +3919,7 @@ var zhI18n = {
|
|
|
3934
3919
|
// Extended — MLPS extras
|
|
3935
3920
|
// Markdown report
|
|
3936
3921
|
executiveSummary: "\u6267\u884C\u6458\u8981",
|
|
3922
|
+
aiSummaryTitle: "AI \u5B89\u5168\u6001\u52BF\u603B\u7ED3",
|
|
3937
3923
|
totalFindingsLabel: "\u53D1\u73B0\u603B\u6570",
|
|
3938
3924
|
description: "\u63CF\u8FF0",
|
|
3939
3925
|
priority: "\u4F18\u5148\u7EA7",
|
|
@@ -4243,6 +4229,7 @@ var enI18n = {
|
|
|
4243
4229
|
// Extended \u2014 MLPS extras
|
|
4244
4230
|
// Markdown report
|
|
4245
4231
|
executiveSummary: "Executive Summary",
|
|
4232
|
+
aiSummaryTitle: "AI Security Summary",
|
|
4246
4233
|
totalFindingsLabel: "Total Findings",
|
|
4247
4234
|
description: "Description",
|
|
4248
4235
|
priority: "Priority",
|
|
@@ -4504,6 +4491,14 @@ function generateMarkdownReport(scanResults, lang) {
|
|
|
4504
4491
|
`- **${t.totalFindingsLabel}:** ${summary.totalFindings} (${SEVERITY_ICON.CRITICAL} ${summary.critical} ${t.critical} | ${SEVERITY_ICON.HIGH} ${summary.high} ${t.high} | ${SEVERITY_ICON.MEDIUM} ${summary.medium} ${t.medium} | ${SEVERITY_ICON.LOW} ${summary.low} ${t.low})`
|
|
4505
4492
|
);
|
|
4506
4493
|
lines.push("");
|
|
4494
|
+
if (scanResults.aiSummary && scanResults.aiSummary.trim()) {
|
|
4495
|
+
lines.push(`> \u2728 **${t.aiSummaryTitle}**`);
|
|
4496
|
+
lines.push(">");
|
|
4497
|
+
for (const ln of scanResults.aiSummary.trim().split(/\r?\n/)) {
|
|
4498
|
+
lines.push(`> ${ln}`);
|
|
4499
|
+
}
|
|
4500
|
+
lines.push("");
|
|
4501
|
+
}
|
|
4507
4502
|
if (summary.totalFindings === 0) {
|
|
4508
4503
|
lines.push(`## ${t.findingsBySeverity}`);
|
|
4509
4504
|
lines.push("");
|
|
@@ -7281,6 +7276,14 @@ function generateMlps3Report(scanResults, lang) {
|
|
|
7281
7276
|
lines.push(`## ${t.accountInfo}`);
|
|
7282
7277
|
lines.push(`- ${t.account}: ${accountId} | ${t.region}: ${region} | ${t.scanTime}: ${scanTime}`);
|
|
7283
7278
|
lines.push("");
|
|
7279
|
+
if (scanResults.aiSummary && scanResults.aiSummary.trim()) {
|
|
7280
|
+
lines.push(`> \u2728 **${t.aiSummaryTitle}**`);
|
|
7281
|
+
lines.push(">");
|
|
7282
|
+
for (const ln of scanResults.aiSummary.trim().split(/\r?\n/)) {
|
|
7283
|
+
lines.push(`> ${ln}`);
|
|
7284
|
+
}
|
|
7285
|
+
lines.push("");
|
|
7286
|
+
}
|
|
7284
7287
|
lines.push(`## ${t.preCheckOverview}`);
|
|
7285
7288
|
lines.push(`- ${t.checkedCount(checkedTotal, autoClean, autoIssues)}`);
|
|
7286
7289
|
if (autoUnknown > 0) {
|
|
@@ -7383,6 +7386,14 @@ function escWithLinks(s) {
|
|
|
7383
7386
|
return esc(part);
|
|
7384
7387
|
}).join("");
|
|
7385
7388
|
}
|
|
7389
|
+
function aiSummaryBlock(summary, title) {
|
|
7390
|
+
const text = (summary ?? "").trim();
|
|
7391
|
+
if (!text) return "";
|
|
7392
|
+
return `<div class="ai-summary">
|
|
7393
|
+
<div class="ai-summary-title">\u2728 ${esc(title)}</div>
|
|
7394
|
+
<div class="ai-summary-body">${esc(text)}</div>
|
|
7395
|
+
</div>`;
|
|
7396
|
+
}
|
|
7386
7397
|
function calcScore(summary) {
|
|
7387
7398
|
const raw = 100 - summary.critical * 15 - summary.high * 5 - summary.medium * 2 - summary.low * 0.5;
|
|
7388
7399
|
return Math.max(0, Math.min(100, Math.round(raw)));
|
|
@@ -7627,7 +7638,13 @@ function sharedCss() {
|
|
|
7627
7638
|
details{display:block}
|
|
7628
7639
|
details>summary{display:block}
|
|
7629
7640
|
details>:not(summary){display:block !important}
|
|
7641
|
+
.ai-summary{background:#f5f3ff !important;border-color:#c7d2fe !important}
|
|
7642
|
+
.ai-summary-title{color:#4338ca !important}
|
|
7643
|
+
.ai-summary-body{color:#1e293b !important}
|
|
7630
7644
|
}
|
|
7645
|
+
.ai-summary{background:linear-gradient(135deg,#1e293b,#1e1b4b);border:1px solid #4338ca;border-radius:10px;padding:16px 20px;margin:0 0 28px}
|
|
7646
|
+
.ai-summary-title{font-size:14px;font-weight:700;color:#a5b4fc;margin-bottom:8px}
|
|
7647
|
+
.ai-summary-body{font-size:14px;line-height:1.7;color:#cbd5e1;white-space:pre-wrap}
|
|
7631
7648
|
`;
|
|
7632
7649
|
}
|
|
7633
7650
|
function donutChart(summary) {
|
|
@@ -8179,6 +8196,8 @@ ${remaining.map(renderRec).join("\n")}
|
|
|
8179
8196
|
<div class="meta">${esc(t.account)}: ${esc(accountId)} | ${esc(t.region)}: ${esc(region)} | ${esc(date)} | ${esc(t.duration)}: ${esc(duration)}</div>
|
|
8180
8197
|
</header>
|
|
8181
8198
|
|
|
8199
|
+
${aiSummaryBlock(scanResults.aiSummary, t.aiSummaryTitle)}
|
|
8200
|
+
|
|
8182
8201
|
<section class="summary">
|
|
8183
8202
|
<div class="score-card">
|
|
8184
8203
|
<div class="score-value" style="color:${scoreColor(score)}">${score}</div>
|
|
@@ -8526,6 +8545,8 @@ ${mlpsRemaining.map(renderMlpsRec).join("\n")}
|
|
|
8526
8545
|
<div class="meta">${esc(t.account)}: ${esc(accountId)} | ${esc(t.region)}: ${esc(region)} | ${esc(t.scanTime)}: ${esc(scanTime)}</div>
|
|
8527
8546
|
</header>
|
|
8528
8547
|
|
|
8548
|
+
${aiSummaryBlock(scanResults.aiSummary, t.aiSummaryTitle)}
|
|
8549
|
+
|
|
8529
8550
|
<section class="summary" style="display:block;text-align:center">
|
|
8530
8551
|
<div style="font-size:36px;font-weight:700;margin-bottom:12px">
|
|
8531
8552
|
<span style="color:#22c55e">${autoClean}</span> <span style="color:#94a3b8;font-size:18px">${esc(t.noIssues)}</span>
|
|
@@ -8574,6 +8595,14 @@ function safeUrl2(url) {
|
|
|
8574
8595
|
return null;
|
|
8575
8596
|
}
|
|
8576
8597
|
}
|
|
8598
|
+
function aiSummaryBlock2(summary, title) {
|
|
8599
|
+
const text = (summary ?? "").trim();
|
|
8600
|
+
if (!text) return "";
|
|
8601
|
+
return `<div class="ai-summary">
|
|
8602
|
+
<div class="ai-summary-title">\u2728 ${esc2(title)}</div>
|
|
8603
|
+
<div class="ai-summary-body">${esc2(text)}</div>
|
|
8604
|
+
</div>`;
|
|
8605
|
+
}
|
|
8577
8606
|
function escWithLinks2(s) {
|
|
8578
8607
|
const parts = s.split(/(https?:\/\/\S+)/);
|
|
8579
8608
|
return parts.map((part, i) => {
|
|
@@ -8709,7 +8738,13 @@ function hwCss() {
|
|
|
8709
8738
|
details{display:block}
|
|
8710
8739
|
details>summary{display:block}
|
|
8711
8740
|
details>:not(summary){display:block !important}
|
|
8741
|
+
.ai-summary{background:#f5f3ff !important;border-color:#c7d2fe !important}
|
|
8742
|
+
.ai-summary-title{color:#4338ca !important}
|
|
8743
|
+
.ai-summary-body{color:#1e293b !important}
|
|
8712
8744
|
}
|
|
8745
|
+
.ai-summary{background:linear-gradient(135deg,#1e293b,#1e1b4b);border:1px solid #4338ca;border-radius:10px;padding:16px 20px;margin:0 0 28px}
|
|
8746
|
+
.ai-summary-title{font-size:14px;font-weight:700;color:#a5b4fc;margin-bottom:8px}
|
|
8747
|
+
.ai-summary-body{font-size:14px;line-height:1.7;color:#cbd5e1;white-space:pre-wrap}
|
|
8713
8748
|
`;
|
|
8714
8749
|
}
|
|
8715
8750
|
function generateHwDefenseHtmlReport(scanResults, lang) {
|
|
@@ -8910,6 +8945,8 @@ function generateHwDefenseHtmlReport(scanResults, lang) {
|
|
|
8910
8945
|
<div class="meta">${esc2(t.account)}: ${esc2(accountId)} | ${esc2(t.region)}: ${esc2(region)} | ${esc2(t.scanTime)}: ${esc2(scanTime)}</div>
|
|
8911
8946
|
</header>
|
|
8912
8947
|
|
|
8948
|
+
${aiSummaryBlock2(scanResults.aiSummary, t.aiSummaryTitle)}
|
|
8949
|
+
|
|
8913
8950
|
<section class="summary-cards">
|
|
8914
8951
|
<div class="summary-card"><div class="stat-count" style="color:${findingsColor}">${totalFindings}</div><div class="stat-label">${esc2(t.hwTotalFindings)}</div></div>
|
|
8915
8952
|
<div class="summary-card"><div class="stat-count" style="color:#60a5fa">${sectionsChecked}</div><div class="stat-label">${esc2(t.hwSectionsChecked)}</div></div>
|
|
@@ -8929,6 +8966,137 @@ ${sectionsHtml}
|
|
|
8929
8966
|
</html>`;
|
|
8930
8967
|
}
|
|
8931
8968
|
|
|
8969
|
+
// src/tools/ai-summary-prompt.ts
|
|
8970
|
+
function buildFindingsDigest(scan, lang, topN = 12) {
|
|
8971
|
+
const zh = lang === "zh";
|
|
8972
|
+
const all = scan.modules.flatMap(
|
|
8973
|
+
(m) => m.findings.map((f) => ({ ...f, module: f.module ?? m.module }))
|
|
8974
|
+
);
|
|
8975
|
+
const s = scan.summary;
|
|
8976
|
+
const byModule = [...scan.modules].filter((m) => m.findingsCount > 0).sort((a, b) => b.findingsCount - a.findingsCount).slice(0, 19).map((m) => `${m.module}=${m.findingsCount}`).join(", ");
|
|
8977
|
+
const top = [...all].sort((a, b) => b.riskScore - a.riskScore).slice(0, topN);
|
|
8978
|
+
const topLines = top.map(
|
|
8979
|
+
(f, i) => `${i + 1}. [${f.severity}/${f.priority}] ${f.title} \u2014 ${f.resourceType} ${f.resourceId} (${f.region}) risk=${f.riskScore}`
|
|
8980
|
+
).join("\n");
|
|
8981
|
+
const head = zh ? `\u8D26\u53F7: ${scan.accountId} | \u533A\u57DF: ${scan.region}
|
|
8982
|
+
\u98CE\u9669\u603B\u6570: ${s.totalFindings} (CRITICAL ${s.critical} / HIGH ${s.high} / MEDIUM ${s.medium} / LOW ${s.low})
|
|
8983
|
+
\u6A21\u5757\u5206\u5E03: ${byModule || "\u65E0"}
|
|
8984
|
+
|
|
8985
|
+
\u9AD8\u98CE\u9669 Top ${top.length}:
|
|
8986
|
+
${topLines || "\u65E0"}` : `Account: ${scan.accountId} | Region: ${scan.region}
|
|
8987
|
+
Total findings: ${s.totalFindings} (CRITICAL ${s.critical} / HIGH ${s.high} / MEDIUM ${s.medium} / LOW ${s.low})
|
|
8988
|
+
Module breakdown: ${byModule || "none"}
|
|
8989
|
+
|
|
8990
|
+
Top ${top.length} by risk:
|
|
8991
|
+
${topLines || "none"}`;
|
|
8992
|
+
return head;
|
|
8993
|
+
}
|
|
8994
|
+
function getProfile(type, lang) {
|
|
8995
|
+
const zh = lang === "zh";
|
|
8996
|
+
switch (type) {
|
|
8997
|
+
case "dashboard":
|
|
8998
|
+
return zh ? {
|
|
8999
|
+
persona: "\u4F60\u5728\u4E3A\u5B89\u5168\u8FD0\u8425\u4EEA\u8868\u76D8\u5199\u4E00\u6BB5\u9AD8\u7BA1\u901F\u89C8\u3002\u8BFB\u8005\u662F CISO / \u7BA1\u7406\u5C42\uFF0C\u65F6\u95F4\u5F88\u5C11\u3002",
|
|
9000
|
+
focus: "\u6574\u4F53\u5B89\u5168\u6001\u52BF\u4E00\u53E5\u8BDD\u5B9A\u8C03 + \u5B89\u5168\u8BC4\u5206\u89E3\u8BFB + \u6B64\u523B\u6700\u8BE5\u5173\u6CE8\u7684 3 \u4EF6\u4E8B\uFF08\u6309\u4E1A\u52A1\u5F71\u54CD\u6392\u5E8F\uFF09\u3002\u4E0D\u8981\u7F57\u5217\u6240\u6709 finding\u3002",
|
|
9001
|
+
format: "3-5 \u53E5\u8BDD\uFF0C\u5F00\u5934\u4E00\u53E5\u7ED3\u8BBA\u5148\u884C\u3002\u4E2D\u6587\u3002\u4E0D\u7528 Markdown \u6807\u9898\uFF0C\u53EF\u7528\u7B80\u77ED\u5206\u53F7\u6216\u6362\u884C\u3002\u8BED\u6C14\u4E13\u4E1A\u3001\u514B\u5236\u3001\u53EF\u6267\u884C\u3002"
|
|
9002
|
+
} : {
|
|
9003
|
+
persona: "You are writing an executive at-a-glance summary for a security operations dashboard. Readers are CISO/leadership with little time.",
|
|
9004
|
+
focus: "One-line overall posture verdict + interpretation of the security score + the top 3 things to focus on right now (ordered by business impact). Do NOT list every finding.",
|
|
9005
|
+
format: "3-5 sentences, conclusion first. English. No Markdown headings; short line breaks ok. Professional, restrained, actionable tone."
|
|
9006
|
+
};
|
|
9007
|
+
case "html":
|
|
9008
|
+
return zh ? {
|
|
9009
|
+
persona: "\u4F60\u5728\u4E3A\u4E00\u4EFD\u5B8C\u6574\u7684 AWS \u5B89\u5168\u626B\u63CF\u62A5\u544A\u5199\u6267\u884C\u6458\u8981\u3002\u8BFB\u8005\u65E2\u6709\u7BA1\u7406\u5C42\u4E5F\u6709\u6280\u672F\u8D1F\u8D23\u4EBA\u3002",
|
|
9010
|
+
focus: "\u6574\u4F53\u98CE\u9669\u5168\u666F + Top \u98CE\u9669\u7684\u5171\u6027\u6839\u56E0\uFF08\u5982\u516C\u7F51\u66B4\u9732\u9762\u3001IAM \u8FC7\u6743\u3001\u52A0\u5BC6/\u65E5\u5FD7\u7F3A\u5931\u7B49\uFF09+ \u5206\u4F18\u5148\u7EA7(P0\u2192P2)\u7684\u4FEE\u590D\u8DEF\u7EBF\u5EFA\u8BAE\u3002\u70B9\u51FA\u7CFB\u7EDF\u6027\u95EE\u9898\u800C\u975E\u9010\u6761\u590D\u8FF0\u3002",
|
|
9011
|
+
format: "1 \u6BB5\u6982\u8FF0 + 3-5 \u6761\u8981\u70B9\u3002\u4E2D\u6587\u3002\u53EF\u7528\u8981\u70B9\u5217\u8868\u3002\u6280\u672F\u4E0E\u7BA1\u7406\u53CC\u89C6\u89D2\uFF0C\u7ED9\u51FA\u53EF\u843D\u5730\u7684\u4E0B\u4E00\u6B65\u3002"
|
|
9012
|
+
} : {
|
|
9013
|
+
persona: "You are writing the executive summary for a full AWS security scan report. Readers include both management and technical leads.",
|
|
9014
|
+
focus: "Overall risk landscape + common root causes behind the top risks (public exposure, over-privileged IAM, missing encryption/logging, etc.) + a prioritized (P0\u2192P2) remediation roadmap. Surface systemic issues rather than restating each finding.",
|
|
9015
|
+
format: "1 overview paragraph + 3-5 bullet points. English. Bullet list ok. Both technical and management lens, with concrete next steps."
|
|
9016
|
+
};
|
|
9017
|
+
case "hw_defense":
|
|
9018
|
+
return zh ? {
|
|
9019
|
+
persona: "\u4F60\u662F\u62A4\u7F51\u884C\u52A8(\u7F51\u7EDC\u5B89\u5168\u653B\u9632\u6F14\u7EC3)\u7684\u84DD\u961F\u6307\u6325\u3002\u8FD9\u662F\u4E00\u4EFD\u62A4\u7F51\u5907\u6218\u8BC4\u4F30\u62A5\u544A\u3002\u6CE8\u610F\uFF1AHW=\u62A4\u7F51\uFF0C\u4E0E\u534E\u4E3A\u65E0\u5173\u3002",
|
|
9020
|
+
focus: "\u4ECE\u653B\u51FB\u8005\u89C6\u89D2\u4E32\u8054 findings \u6210\u653B\u51FB\u94FE(kill-chain)\uFF1A\u54EA\u4E9B\u662F\u5916\u90E8\u53EF\u8FBE\u7684\u521D\u59CB\u7A81\u7834\u53E3\u3001\u6A2A\u5411\u79FB\u52A8/\u63D0\u6743\u8DEF\u5F84\u3001\u53EF\u80FD\u7684\u5F71\u54CD\u9762\uFF1B\u7136\u540E\u7ED9\u51FA\u5907\u6218\u6536\u655B\u6E05\u5355(\u5148\u5173\u4EC0\u4E48\u3001\u5148\u76EF\u4EC0\u4E48)\u3002\u5F3A\u8C03\u66B4\u9732\u9762\u6536\u655B\u4E0E\u76D1\u63A7\u52A0\u56FA\u3002",
|
|
9021
|
+
format: "\u5148\u4E00\u53E5\u7814\u5224\u7ED3\u8BBA(\u5F53\u524D\u66B4\u9732\u9762/\u88AB\u6253\u7A7F\u98CE\u9669)\uFF0C\u518D\u7ED9\u300E\u653B\u51FB\u94FE\u89C6\u89D2\u300F\u548C\u300E\u5907\u6218\u6574\u6539\u4F18\u5148\u7EA7\u300F\u4E24\u5757\u3002\u4E2D\u6587\u3002\u8BED\u6C14\u8D34\u62A4\u7F51\u5B9E\u6218\u8BED\u5883\uFF0C\u7D27\u8FEB\u4F46\u4E0D\u5938\u5F20\u3002"
|
|
9022
|
+
} : {
|
|
9023
|
+
persona: "You are the blue-team lead for an HW Defense exercise (cybersecurity attack-defense drill). This is a pre-exercise readiness report. Note: HW = HuWang/\u62A4\u7F51, unrelated to Huawei.",
|
|
9024
|
+
focus: "From an attacker's perspective, chain findings into a kill-chain: external initial footholds, lateral movement/privilege-escalation paths, likely blast radius; then a hardening checklist (what to close/watch first). Emphasize attack-surface reduction and monitoring.",
|
|
9025
|
+
format: "Lead with a one-line verdict (current exposure / breach risk), then two blocks: 'Attack-chain view' and 'Readiness remediation priorities'. English. Combat-readiness tone, urgent but not alarmist."
|
|
9026
|
+
};
|
|
9027
|
+
case "mlps3":
|
|
9028
|
+
return zh ? {
|
|
9029
|
+
persona: "\u4F60\u662F\u7B49\u4FDD\u6D4B\u8BC4\u987E\u95EE\u3002\u8FD9\u662F\u4E00\u4EFD\u7B49\u4FDD\u4E09\u7EA7(GB/T 22239-2019)\u5408\u89C4\u9884\u68C0\u62A5\u544A\u3002",
|
|
9030
|
+
focus: "\u4ECE\u5408\u89C4\u89C6\u89D2\u603B\u7ED3\uFF1A\u5F53\u524D\u5BF9\u7167\u7B49\u4FDD\u4E09\u7EA7\u63A7\u5236\u9879\u7684\u603B\u4F53\u8FBE\u6807\u60C5\u51B5\u3001\u54EA\u4E9B\u63A7\u5236\u57DF\u5B58\u5728\u660E\u663E\u4E0D\u8FBE\u6807\u9879(\u5982\u8BBF\u95EE\u63A7\u5236\u3001\u5B89\u5168\u5BA1\u8BA1\u3001\u5165\u4FB5\u9632\u8303\u3001\u6570\u636E\u5B8C\u6574\u6027/\u4FDD\u5BC6\u6027\u7B49)\u3001\u6574\u6539\u7D27\u8FEB\u5EA6\u4E0E\u8FC7\u4FDD\u5EFA\u8BAE\u3002\u628A\u6280\u672F finding \u6620\u5C04\u5230\u5408\u89C4\u8BED\u8A00\u3002",
|
|
9031
|
+
format: "1 \u6BB5\u5408\u89C4\u7ED3\u8BBA + \u6309\u63A7\u5236\u57DF\u5206\u7EC4\u7684\u4E0D\u8FBE\u6807\u8981\u70B9 + \u6574\u6539\u4F18\u5148\u7EA7\u3002\u4E2D\u6587\u3002\u5F15\u7528\u63A7\u5236\u57DF\u540D\u79F0\u3002\u8BED\u6C14\u4E25\u8C28\u3001\u9762\u5411\u6D4B\u8BC4\u3002"
|
|
9032
|
+
} : {
|
|
9033
|
+
persona: "You are an MLPS assessment advisor. This is an MLPS Level 3 (GB/T 22239-2019) compliance pre-check report.",
|
|
9034
|
+
focus: "Summarize from a compliance lens: overall conformance against MLPS L3 controls, which control domains have clear gaps (access control, security audit, intrusion prevention, data integrity/confidentiality, etc.), remediation urgency, and certification-readiness advice. Map technical findings to compliance language.",
|
|
9035
|
+
format: "1 compliance verdict paragraph + non-conformance points grouped by control domain + remediation priority. English. Reference control-domain names. Rigorous, assessment-oriented tone."
|
|
9036
|
+
};
|
|
9037
|
+
}
|
|
9038
|
+
}
|
|
9039
|
+
var TYPE_LABEL = {
|
|
9040
|
+
dashboard: { zh: "\u5B89\u5168\u8FD0\u8425\u4EEA\u8868\u76D8", en: "Security Operations Dashboard" },
|
|
9041
|
+
html: { zh: "AWS \u5B89\u5168\u626B\u63CF\u62A5\u544A", en: "AWS Security Scan Report" },
|
|
9042
|
+
hw_defense: { zh: "\u62A4\u7F51\u884C\u52A8\u8BC4\u4F30\u62A5\u544A", en: "HW Defense (\u62A4\u7F51) Readiness Report" },
|
|
9043
|
+
mlps3: { zh: "\u7B49\u4FDD\u4E09\u7EA7\u5408\u89C4\u9884\u68C0\u62A5\u544A", en: "MLPS Level 3 Compliance Pre-check" }
|
|
9044
|
+
};
|
|
9045
|
+
function buildAiSummaryPrompt(type, scan, lang) {
|
|
9046
|
+
const zh = lang === "zh";
|
|
9047
|
+
const p = getProfile(type, lang);
|
|
9048
|
+
const label = TYPE_LABEL[type][zh ? "zh" : "en"];
|
|
9049
|
+
const digest = buildFindingsDigest(scan, lang);
|
|
9050
|
+
if (zh) {
|
|
9051
|
+
return [
|
|
9052
|
+
`# \u4EFB\u52A1\uFF1A\u4E3A\u300C${label}\u300D\u751F\u6210\u9488\u5BF9\u6027\u7684 AI \u5B89\u5168\u603B\u7ED3`,
|
|
9053
|
+
``,
|
|
9054
|
+
`## \u89D2\u8272`,
|
|
9055
|
+
p.persona,
|
|
9056
|
+
``,
|
|
9057
|
+
`## \u603B\u7ED3\u91CD\u70B9`,
|
|
9058
|
+
p.focus,
|
|
9059
|
+
``,
|
|
9060
|
+
`## \u8F93\u51FA\u683C\u5F0F`,
|
|
9061
|
+
p.format,
|
|
9062
|
+
``,
|
|
9063
|
+
`## \u7EA6\u675F`,
|
|
9064
|
+
`- \u53EA\u4F9D\u636E\u4E0B\u9762\u7684\u626B\u63CF\u6570\u636E\uFF0C\u4E0D\u8981\u7F16\u9020\u4E0D\u5B58\u5728\u7684\u8D44\u6E90\u6216 finding\u3002`,
|
|
9065
|
+
`- \u4E0D\u8981\u9010\u6761\u590D\u8FF0\u6240\u6709 finding\uFF1B\u63D0\u70BC\u6A21\u5F0F\u4E0E\u4F18\u5148\u7EA7\u3002`,
|
|
9066
|
+
`- \u76F4\u63A5\u8F93\u51FA\u603B\u7ED3\u6B63\u6587\u672C\u8EAB\uFF08\u4E0D\u8981\u5E26\u300C\u4EE5\u4E0B\u662F\u603B\u7ED3\u300D\u4E4B\u7C7B\u7684\u524D\u8A00\uFF0C\u4E0D\u8981 code fence\uFF09\u3002`,
|
|
9067
|
+
`- \u8BED\u8A00\uFF1A\u4E2D\u6587\u3002`,
|
|
9068
|
+
``,
|
|
9069
|
+
`## \u626B\u63CF\u6570\u636E\u6458\u8981`,
|
|
9070
|
+
digest,
|
|
9071
|
+
``,
|
|
9072
|
+
`\u8BF7\u73B0\u5728\u8F93\u51FA\u603B\u7ED3\u6B63\u6587\u3002\u751F\u6210\u540E\uFF0C\u628A\u8FD9\u6BB5\u6587\u672C\u901A\u8FC7\u5BF9\u5E94\u62A5\u544A\u5DE5\u5177\u7684 ai_summary \u53C2\u6570\u56DE\u4F20\u5373\u53EF\u3002`
|
|
9073
|
+
].join("\n");
|
|
9074
|
+
}
|
|
9075
|
+
return [
|
|
9076
|
+
`# Task: Produce a tailored AI security summary for the "${label}"`,
|
|
9077
|
+
``,
|
|
9078
|
+
`## Role`,
|
|
9079
|
+
p.persona,
|
|
9080
|
+
``,
|
|
9081
|
+
`## Summary focus`,
|
|
9082
|
+
p.focus,
|
|
9083
|
+
``,
|
|
9084
|
+
`## Output format`,
|
|
9085
|
+
p.format,
|
|
9086
|
+
``,
|
|
9087
|
+
`## Constraints`,
|
|
9088
|
+
`- Base it ONLY on the scan data below; do not invent resources or findings.`,
|
|
9089
|
+
`- Do not restate every finding; distill patterns and priorities.`,
|
|
9090
|
+
`- Output the summary body itself (no preamble like "Here is the summary", no code fences).`,
|
|
9091
|
+
`- Language: English.`,
|
|
9092
|
+
``,
|
|
9093
|
+
`## Scan data digest`,
|
|
9094
|
+
digest,
|
|
9095
|
+
``,
|
|
9096
|
+
`Now output the summary body. After generating it, pass the text back via the ai_summary parameter of the corresponding report tool.`
|
|
9097
|
+
].join("\n");
|
|
9098
|
+
}
|
|
9099
|
+
|
|
8932
9100
|
// src/tools/save-results.ts
|
|
8933
9101
|
import { writeFileSync, readFileSync, mkdirSync, existsSync } from "fs";
|
|
8934
9102
|
import { join } from "path";
|
|
@@ -8985,7 +9153,8 @@ function saveResults(scanResults, outputDir) {
|
|
|
8985
9153
|
})),
|
|
8986
9154
|
findings: scanResults.modules.flatMap(
|
|
8987
9155
|
(m) => m.findings.map((f) => ({ ...f, module: m.module }))
|
|
8988
|
-
)
|
|
9156
|
+
),
|
|
9157
|
+
aiSummary: scanResults.aiSummary
|
|
8989
9158
|
},
|
|
8990
9159
|
history,
|
|
8991
9160
|
meta: {
|
|
@@ -9601,11 +9770,13 @@ function createServer(defaultRegion) {
|
|
|
9601
9770
|
"Generate a Markdown security report from scan results. Read-only. Does not modify any AWS resources.",
|
|
9602
9771
|
{
|
|
9603
9772
|
scan_results: z.string().describe("JSON string of FullScanResult from scan_all"),
|
|
9604
|
-
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
|
|
9773
|
+
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
|
|
9774
|
+
ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
|
|
9605
9775
|
},
|
|
9606
|
-
async ({ scan_results, lang }) => {
|
|
9776
|
+
async ({ scan_results, lang, ai_summary }) => {
|
|
9607
9777
|
try {
|
|
9608
9778
|
const parsed = JSON.parse(scan_results);
|
|
9779
|
+
if (ai_summary) parsed.aiSummary = ai_summary;
|
|
9609
9780
|
const report = generateMarkdownReport(parsed, lang ?? "zh");
|
|
9610
9781
|
return { content: [{ type: "text", text: report }] };
|
|
9611
9782
|
} catch (err) {
|
|
@@ -9618,11 +9789,13 @@ function createServer(defaultRegion) {
|
|
|
9618
9789
|
"Generate a GB/T 22239-2019 \u7B49\u4FDD\u4E09\u7EA7 compliance pre-check report from scan results. Best used with scan_group mlps3_precheck results. Read-only.",
|
|
9619
9790
|
{
|
|
9620
9791
|
scan_results: z.string().describe("JSON string of FullScanResult from scan_group mlps3_precheck or scan_all"),
|
|
9621
|
-
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
|
|
9792
|
+
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
|
|
9793
|
+
ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
|
|
9622
9794
|
},
|
|
9623
|
-
async ({ scan_results, lang }) => {
|
|
9795
|
+
async ({ scan_results, lang, ai_summary }) => {
|
|
9624
9796
|
try {
|
|
9625
9797
|
const parsed = JSON.parse(scan_results);
|
|
9798
|
+
if (ai_summary) parsed.aiSummary = ai_summary;
|
|
9626
9799
|
const report = generateMlps3Report(parsed, lang ?? "zh");
|
|
9627
9800
|
return { content: [{ type: "text", text: report }] };
|
|
9628
9801
|
} catch (err) {
|
|
@@ -9636,11 +9809,13 @@ function createServer(defaultRegion) {
|
|
|
9636
9809
|
{
|
|
9637
9810
|
scan_results: z.string().describe("JSON string of FullScanResult from scan_all"),
|
|
9638
9811
|
history: z.string().optional().describe("JSON string of DashboardHistoryEntry[] from dashboard data.json for 30-day trend charts"),
|
|
9639
|
-
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
|
|
9812
|
+
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
|
|
9813
|
+
ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
|
|
9640
9814
|
},
|
|
9641
|
-
async ({ scan_results, history, lang }) => {
|
|
9815
|
+
async ({ scan_results, history, lang, ai_summary }) => {
|
|
9642
9816
|
try {
|
|
9643
9817
|
const parsed = JSON.parse(scan_results);
|
|
9818
|
+
if (ai_summary) parsed.aiSummary = ai_summary;
|
|
9644
9819
|
const historyData = history ? JSON.parse(history) : void 0;
|
|
9645
9820
|
const report = generateHtmlReport(parsed, historyData, lang ?? "zh");
|
|
9646
9821
|
return { content: [{ type: "text", text: report }] };
|
|
@@ -9655,11 +9830,13 @@ function createServer(defaultRegion) {
|
|
|
9655
9830
|
{
|
|
9656
9831
|
scan_results: z.string().describe("JSON string of FullScanResult from scan_group mlps3_precheck or scan_all"),
|
|
9657
9832
|
history: z.string().optional().describe("JSON string of DashboardHistoryEntry[] from dashboard data.json for 30-day trend charts"),
|
|
9658
|
-
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
|
|
9833
|
+
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
|
|
9834
|
+
ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
|
|
9659
9835
|
},
|
|
9660
|
-
async ({ scan_results, history, lang }) => {
|
|
9836
|
+
async ({ scan_results, history, lang, ai_summary }) => {
|
|
9661
9837
|
try {
|
|
9662
9838
|
const parsed = JSON.parse(scan_results);
|
|
9839
|
+
if (ai_summary) parsed.aiSummary = ai_summary;
|
|
9663
9840
|
const historyData = history ? JSON.parse(history) : void 0;
|
|
9664
9841
|
const report = generateMlps3HtmlReport(parsed, historyData, lang ?? "zh");
|
|
9665
9842
|
return { content: [{ type: "text", text: report }] };
|
|
@@ -9668,16 +9845,36 @@ function createServer(defaultRegion) {
|
|
|
9668
9845
|
}
|
|
9669
9846
|
}
|
|
9670
9847
|
);
|
|
9848
|
+
server.tool(
|
|
9849
|
+
"get_ai_summary_prompt",
|
|
9850
|
+
"Return a report-type-tailored prompt (with a grounded findings digest) that the CALLING AI should run to produce an AI security summary. Then pass the generated text back via the `ai_summary` parameter of the matching report tool (or scan_and_report). The server performs no LLM calls. Use this to make each summary specific to the report type (dashboard / security scan / HW Defense \u62A4\u7F51 / MLPS3 \u7B49\u4FDD).",
|
|
9851
|
+
{
|
|
9852
|
+
report_type: z.enum(["dashboard", "html", "hw_defense", "mlps3"]).describe("Target report type the summary is for: dashboard (overview), html (AWS security scan report), hw_defense (\u62A4\u7F51 attack-defense drill), mlps3 (\u7B49\u4FDD\u4E09\u7EA7 compliance)"),
|
|
9853
|
+
scan_results: z.string().describe("JSON string of FullScanResult from scan_all / scan_group"),
|
|
9854
|
+
lang: z.enum(["zh", "en"]).optional().describe("Summary language (default: zh)")
|
|
9855
|
+
},
|
|
9856
|
+
async ({ report_type, scan_results, lang }) => {
|
|
9857
|
+
try {
|
|
9858
|
+
const parsed = JSON.parse(scan_results);
|
|
9859
|
+
const prompt = buildAiSummaryPrompt(report_type, parsed, lang ?? "zh");
|
|
9860
|
+
return { content: [{ type: "text", text: prompt }] };
|
|
9861
|
+
} catch (err) {
|
|
9862
|
+
return { content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }], isError: true };
|
|
9863
|
+
}
|
|
9864
|
+
}
|
|
9865
|
+
);
|
|
9671
9866
|
server.tool(
|
|
9672
9867
|
"generate_hw_defense_report",
|
|
9673
9868
|
"Generate an HTML report organized by HW Defense (\u62A4\u7F51) SOP checklist categories. Save as .html file.",
|
|
9674
9869
|
{
|
|
9675
9870
|
scan_results: z.string().describe("JSON string of FullScanResult from scan_group hw_defense or scan_all"),
|
|
9676
|
-
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)")
|
|
9871
|
+
lang: z.enum(["zh", "en"]).optional().describe("Report language (default: zh)"),
|
|
9872
|
+
ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered if present; omit to hide.")
|
|
9677
9873
|
},
|
|
9678
|
-
async ({ scan_results, lang }) => {
|
|
9874
|
+
async ({ scan_results, lang, ai_summary }) => {
|
|
9679
9875
|
try {
|
|
9680
9876
|
const parsed = JSON.parse(scan_results);
|
|
9877
|
+
if (ai_summary) parsed.aiSummary = ai_summary;
|
|
9681
9878
|
const report = generateHwDefenseHtmlReport(parsed, lang ?? "zh");
|
|
9682
9879
|
return { content: [{ type: "text", text: report }] };
|
|
9683
9880
|
} catch (err) {
|
|
@@ -9806,11 +10003,13 @@ function createServer(defaultRegion) {
|
|
|
9806
10003
|
"Saves scan results to local disk or S3 for dashboard display. Does not modify any AWS resources.",
|
|
9807
10004
|
{
|
|
9808
10005
|
scan_results: z.string().describe("JSON string of FullScanResult from scan_all"),
|
|
9809
|
-
output_dir: z.string().optional().describe("Output directory (default: ~/.aws-security)")
|
|
10006
|
+
output_dir: z.string().optional().describe("Output directory (default: ~/.aws-security)"),
|
|
10007
|
+
ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (from get_ai_summary_prompt with report_type=dashboard). Persisted into dashboard data and rendered on the Overview; omit to hide.")
|
|
9810
10008
|
},
|
|
9811
|
-
async ({ scan_results, output_dir }) => {
|
|
10009
|
+
async ({ scan_results, output_dir, ai_summary }) => {
|
|
9812
10010
|
try {
|
|
9813
10011
|
const parsed = JSON.parse(scan_results);
|
|
10012
|
+
if (ai_summary) parsed.aiSummary = ai_summary;
|
|
9814
10013
|
const dataPath = saveResults(parsed, output_dir);
|
|
9815
10014
|
return {
|
|
9816
10015
|
content: [
|
|
@@ -9908,9 +10107,10 @@ Deploy this as a StackSet from your Management Account to all member accounts.`
|
|
|
9908
10107
|
role_name: z.string().optional().describe("IAM role name for cross-account scanning"),
|
|
9909
10108
|
account_ids: z.array(z.string()).optional().describe("Filter to specific account IDs"),
|
|
9910
10109
|
reports: z.array(z.enum(["html", "hw_defense", "mlps3", "markdown", "all"])).optional().describe("Report types to generate (default: all)"),
|
|
9911
|
-
lang: z.enum(["zh", "en"]).optional().describe("Language: zh or en (default: zh)")
|
|
10110
|
+
lang: z.enum(["zh", "en"]).optional().describe("Language: zh or en (default: zh)"),
|
|
10111
|
+
ai_summary: z.string().optional().describe("Optional pre-generated AI executive summary (Markdown/plain text). Rendered in reports + dashboard if present; omit to hide.")
|
|
9912
10112
|
},
|
|
9913
|
-
async ({ region, org_mode, role_name, account_ids, reports, lang }) => {
|
|
10113
|
+
async ({ region, org_mode, role_name, account_ids, reports, lang, ai_summary }) => {
|
|
9914
10114
|
try {
|
|
9915
10115
|
const r = region ?? defaultRegion;
|
|
9916
10116
|
const l = lang ?? "zh";
|
|
@@ -9926,6 +10126,7 @@ Deploy this as a StackSet from your Management Account to all member accounts.`
|
|
|
9926
10126
|
} else {
|
|
9927
10127
|
result = await runAllScanners(allScanners, r);
|
|
9928
10128
|
}
|
|
10129
|
+
if (ai_summary) result.aiSummary = ai_summary;
|
|
9929
10130
|
const baseDir = join2(homedir2(), ".aws-security", "reports", (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
9930
10131
|
mkdirSync2(baseDir, { recursive: true });
|
|
9931
10132
|
const savedFiles = [];
|