(interfaceName, enable, button)
| 8726 | if (cc.EXPOSURE) bits.push(cc.EXPOSURE + ' exposure'); |
| 8727 | if (cc.ATTACK) bits.push(cc.ATTACK + ' attack'); |
| 8728 | if (bits.length) html += ' · ' + bits.join(', '); |
| 8729 | html += '</p>'; |
| 8730 | if ((d.cves || []).length) { |
| 8731 | html += '<p class="text-xs text-gray-400 mb-2">CVEs in scope: <span class="font-mono text-amber-300">' + d.cves.map(escapeHtml).join(', ') + '</span></p>'; |
| 8732 | } |
| 8733 | const fs = d.findings || []; |
| 8734 | if (fs.length) { |
| 8735 | html += '<table class="min-w-full text-xs text-gray-300 whitespace-nowrap"><thead>' + |
| 8736 | '<tr class="text-left text-gray-500"><th class="px-2 py-1">Sev</th><th class="px-2 py-1">Code</th><th class="px-2 py-1">Finding</th><th class="px-2 py-1">Class</th><th class="px-2 py-1">Source</th><th class="px-2 py-1">CVEs</th><th class="px-2 py-1">Detail</th></tr>' + |
| 8737 | '</thead><tbody>' + |
| 8738 | fs.map(f => { |
| 8739 | const sev = _GUARD_SEV_STYLE[f.severity] || 'bg-slate-800 text-slate-400'; |
| 8740 | const kl = _GUARD_KLASS_STYLE[f.klass] || 'text-gray-400'; |
| 8741 | return '<tr class="border-t border-slate-800">' + |
| 8742 | `<td class="px-2 py-1"><span class="px-1.5 py-0.5 rounded ${sev} text-[10px] font-semibold">${escapeHtml(f.severity)}</span></td>` + |
| 8743 | `<td class="px-2 py-1 font-mono text-gray-400">${escapeHtml(f.code)}</td>` + |
| 8744 | `<td class="px-2 py-1">${escapeHtml(f.name)}</td>` + |
| 8745 | `<td class="px-2 py-1 ${kl}">${escapeHtml(f.klass)}</td>` + |
| 8746 | `<td class="px-2 py-1 font-mono">${escapeHtml(f.src || '—')}</td>` + |
| 8747 | `<td class="px-2 py-1 font-mono text-amber-300/80">${escapeHtml((f.cves || []).join(', ') || '—')}</td>` + |
| 8748 | `<td class="px-2 py-1 text-gray-500">${escapeHtml(_guardDetailStr(f.detail))}</td>` + |
| 8749 | '</tr>'; |
| 8750 | }).join('') + |
| 8751 | '</tbody></table>'; |
| 8752 | } else if (d.verdict === 'clean') { |
| 8753 | html += '<p class="text-xs text-gray-500">Segment quiet — no vendor management or attack traffic seen in the window.</p>'; |
| 8754 | } |
| 8755 | return html; |
| 8756 | } |
| 8757 | async function _runGuard(module, label, btn) { |
| 8758 | const out = document.getElementById(module + '-guard-results'); |
| 8759 | if (!out) return; |
| 8760 | const ifaceSel = document.getElementById(module + '-guard-iface'); |
| 8761 | const iface = ifaceSel && ifaceSel.value ? ifaceSel.value : ''; |
| 8762 | const secsEl = document.getElementById(module + '-guard-secs'); |
| 8763 | const secs = secsEl && secsEl.value ? secsEl.value : '20'; |
| 8764 | _ndBusy(btn, true, 'Capturing…'); |
| 8765 | out.classList.remove('hidden'); |
| 8766 | out.innerHTML = `<p class="text-sm text-gray-400">Passively capturing the ${escapeHtml(label)} attack surface…</p>`; |
| 8767 | try { |
| 8768 | _guardFillIfaces(module + '-guard-iface'); |
| 8769 | const roleEl = document.getElementById(module + '-guard-role'); |
no test coverage detected