mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-09-29 12:31:43 +02:00
Audited at 390×844, 844×390 (phone landscape), 768×1024, 1024×768, 1440×900
and ≥1600px. What was actually broken:
- **The run header collapsed.** `justify-content: space-between` let the two
action buttons take the whole row, so at 390px the title wrapped one
character per line ("Test AspNe / t") and the facts line wrapped one word per
line. It now stacks below 680px, with the title block sized to its content
instead of stretching (the desktop `flex: 1` was what left a 180px void above
the buttons in the stacked layout).
- **The terminal header overflowed** its dock at 390px (557px of content in a
390px box) — it wraps now, and the status text drops out on narrow screens
where the coloured dot already carries it.
- **`100vh` is wrong on mobile.** It measures the viewport without the
collapsing address bar, so the wizard footer and its CTA sit underneath it.
Switched to `dvh` with the `vh` line kept as the fallback.
- **The dock took 82% of a phone in landscape** at its fixed 320px. It now
tracks the viewport (`clamp(180px, 42dvh, 340px)`, tighter still under
500px of height).
- **The off-canvas drawer had no way out but the button that opened it.**
Added a scrim that closes it, Esc, and auto-close when a run is picked —
and it closes itself if the window grows past the breakpoint, which
otherwise left a scrim over a sidebar that was no longer a drawer.
- **The stepper scrolls horizontally on a phone**, so advancing to an
off-screen step looked like nothing happened; the active step is scrolled
into view.
Device-type rules rather than width alone: `pointer: coarse` gets 38-44px hit
targets and 16px inputs (under 16px, iOS zooms the page on focus and breaks the
layout the user is typing into); `prefers-reduced-motion` drops the drawer
slide and the progress animation, which are decoration.
Scrolling stays where it belongs — one scroller per pane (`.wizard-body`,
`.run-body`, `.dash-body`, `.sb-groups`, `.modal-body`, `.term-host`), wide
tables scroll inside `.table-wrap`, and the page itself never scrolls
horizontally at any tested size.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
459 lines
23 KiB
HTML
459 lines
23 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>NeuroSploit v4.0.0 — Console</title>
|
||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🧠</text></svg>">
|
||
<link rel="stylesheet" href="/vendor/xterm.css" />
|
||
<link rel="stylesheet" href="/style.css" />
|
||
</head>
|
||
<body>
|
||
|
||
<button class="sidebar-toggle" id="btnSidebarToggle" title="Show / hide run history" aria-label="Show or hide run history" aria-expanded="false" aria-controls="sidebar">☰</button>
|
||
<div class="sidebar-scrim" id="sidebarScrim" hidden></div>
|
||
|
||
<div class="app">
|
||
|
||
<!-- ============ SIDEBAR ============ -->
|
||
<aside class="sidebar" id="sidebar">
|
||
<div class="sb-top">
|
||
<div class="brand"><span class="mark">NS</span> NeuroSploit</div>
|
||
<button class="icon-btn" id="btnThemeToggle" title="Toggle light / dark theme">☾</button>
|
||
</div>
|
||
|
||
<button class="sb-new" id="btnNewEngagement">+ New engagement</button>
|
||
<button class="sb-link" id="btnDashboard">▤ Dashboard</button>
|
||
|
||
<div class="sb-search">
|
||
<span class="search-icon" aria-hidden="true">⌕</span>
|
||
<input id="runFilter" type="text" autocomplete="off" placeholder="Filter runs" aria-label="Filter runs" />
|
||
</div>
|
||
|
||
<div class="sb-groups" id="sbGroups"><!-- populated by app.js --></div>
|
||
|
||
<div class="sb-bottom">
|
||
<span class="sb-version" id="sbVersion">v4.0.0</span>
|
||
<div class="sb-bottom-actions">
|
||
<button class="icon-btn" id="btnOpenAuth" title="Auth & API keys">🔑</button>
|
||
<button class="icon-btn" id="btnOpenRepl" title="Open terminal (Ctrl+`)">❭_</button>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- ============ MAIN ============ -->
|
||
<main class="main">
|
||
|
||
<!-- ============ DASHBOARD ============ -->
|
||
<section class="dashboard" id="dashView" hidden>
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">Dashboard</div>
|
||
<div class="topbar-sub">Coverage, findings and FAIR loss exposure across every run</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<select id="dashRange" class="dash-range" title="Time range">
|
||
<option value="0">all time</option>
|
||
<option value="7">last 7 days</option>
|
||
<option value="30">last 30 days</option>
|
||
<option value="90">last 90 days</option>
|
||
</select>
|
||
<button class="btn" id="btnDashRefresh">Refresh</button>
|
||
</header>
|
||
<div class="dash-body" id="dashBody">
|
||
<div class="empty-state">Loading…</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ WIZARD (new engagement) ============ -->
|
||
<section class="wizard" id="wizardView">
|
||
<header class="topbar">
|
||
<div>
|
||
<div class="topbar-title">New engagement</div>
|
||
<div class="topbar-sub">Asset → Scope & Auth → Leads → Model & Run → Review</div>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="btn" id="btnOpenTerm2">❭_ Terminal</button>
|
||
<button class="btn" id="btnOpenAuth2">🔑 Auth & Keys</button>
|
||
</header>
|
||
|
||
<nav class="stepper" id="stepper">
|
||
<button class="step-tab active" data-step="0"><span class="n">1</span> Asset</button>
|
||
<button class="step-tab" data-step="1"><span class="n">2</span> Scope & Auth</button>
|
||
<button class="step-tab" data-step="2"><span class="n">3</span> Leads</button>
|
||
<button class="step-tab" data-step="3"><span class="n">4</span> Model & Run</button>
|
||
<button class="step-tab" data-step="4"><span class="n">5</span> Review</button>
|
||
</nav>
|
||
|
||
<div class="wizard-body">
|
||
|
||
<!-- Step 1 — Asset -->
|
||
<div class="wizard-panel" data-panel="0">
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldName">Engagement name</label>
|
||
<input id="fieldName" type="text" placeholder="e.g. Keystone – Digital Banking" aria-describedby="errName" />
|
||
<div class="field-error" id="errName" hidden></div>
|
||
<div class="field-help">Identifies this engagement in the sidebar and run history — required.</div>
|
||
</div>
|
||
<div>
|
||
<div class="section-title">What are you testing?</div>
|
||
<div class="section-desc">Pick the engagement type — this decides which CLI subcommand runs underneath.</div>
|
||
</div>
|
||
<div class="mode-tiles" id="modeTiles">
|
||
<button class="mode-tile" data-mode="run"><span class="t">Black-box</span><span class="d">URL only — recon-driven</span></button>
|
||
<button class="mode-tile" data-mode="whitebox"><span class="t">White-box</span><span class="d">Source repo — SAST agents</span></button>
|
||
<button class="mode-tile" data-mode="greybox"><span class="t">Grey-box</span><span class="d">URL + source together</span></button>
|
||
<button class="mode-tile" data-mode="host"><span class="t">Host / Infra</span><span class="d">IP — Linux/Windows/AD</span></button>
|
||
<button class="mode-tile" data-mode="aitest"><span class="t">AI / LLM</span><span class="d">Live AI agent or MCP endpoint</span></button>
|
||
</div>
|
||
|
||
<div class="field-group" id="fieldTargetGroup">
|
||
<label class="field-label" id="targetLabel" for="fieldTarget">Target URL</label>
|
||
<input id="fieldTarget" type="text" placeholder="https://target.example.com" aria-describedby="errTarget" />
|
||
<div class="field-error" id="errTarget" hidden></div>
|
||
<div class="field-help" id="targetHelp">The application, host, or endpoint to test.</div>
|
||
</div>
|
||
<div class="field-group" id="fieldRepoGroup" hidden>
|
||
<label class="field-label" for="fieldRepo">Source repo</label>
|
||
<input id="fieldRepo" type="text" placeholder="owner/repo, a GitHub URL, or a local path" aria-describedby="errRepo" />
|
||
<div class="field-error" id="errRepo" hidden></div>
|
||
<div class="field-help">Cloned automatically if it's a GitHub URL or owner/repo shorthand.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 2 — Scope & Auth -->
|
||
<div class="wizard-panel" data-panel="1" hidden>
|
||
<div>
|
||
<div class="section-title">Objective & focus</div>
|
||
<div class="section-desc">Steers what the agents prioritise and what counts as impact.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldObjective">Objective</label>
|
||
<textarea id="fieldObjective" placeholder="e.g. Pre-launch review of the checkout flow — prove any path to unauthorized order access."></textarea>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldFocus">Focus</label>
|
||
<textarea id="fieldFocus" placeholder="e.g. Prioritize the paths most likely to cause data leakage."></textarea>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldOutOfScope">Out of scope</label>
|
||
<textarea id="fieldOutOfScope" placeholder="Hosts, paths, or techniques the agents must not touch."></textarea>
|
||
</div>
|
||
<div>
|
||
<div class="section-title">Authentication</div>
|
||
<div class="section-desc">Test as a logged-in user. Configured in the <button class="btn btn-sm" id="btnOpenAuth3">🔑 Auth & Keys</button> menu.</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 3 — Leads -->
|
||
<div class="wizard-panel wizard-panel-wide" data-panel="2" hidden>
|
||
<div>
|
||
<div class="section-title">Set the action plan</div>
|
||
<div class="section-desc">Toggle specific leads to test, or leave everything off to let recon-driven auto-selection choose.</div>
|
||
</div>
|
||
<div class="lead-toolbar">
|
||
<div class="search-wrap">
|
||
<span class="search-icon" aria-hidden="true">⌕</span>
|
||
<input id="leadSearch" type="text" placeholder="Search leads by name or CWE" />
|
||
</div>
|
||
<div class="chips">
|
||
<button class="chip chip-active" data-filter="all">All <span id="chipAll">0</span></button>
|
||
<button class="chip" data-filter="selected">Pinned <span id="chipSelected">0</span></button>
|
||
<button class="chip" data-filter="excluded">Not pinned <span id="chipExcluded">0</span></button>
|
||
</div>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="btn btn-sm" id="btnExpandAll">Expand all</button>
|
||
<button class="btn btn-sm" id="btnSelectAll">Select all</button>
|
||
<button class="btn btn-sm" id="btnClearAll">Clear all</button>
|
||
<button class="btn btn-sm" id="btnCustomLead">+ Custom lead</button>
|
||
</div>
|
||
<div class="field-help lead-tip">Categories start collapsed — click one to open it, or click its switch to pin every lead inside at once.</div>
|
||
<div class="custom-leads" id="customLeadsList" hidden></div>
|
||
<div class="categories" id="categories"><!-- populated --></div>
|
||
<div class="empty-state" id="leadsEmpty" hidden>No lead matches that search.</div>
|
||
</div>
|
||
|
||
<!-- Step 4 — Model & Run -->
|
||
<div class="wizard-panel" data-panel="3" hidden>
|
||
<div>
|
||
<div class="section-title">Model</div>
|
||
<div class="section-desc">Pick a provider and model from the harness's live catalog.</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldProvider">Provider</label>
|
||
<select id="fieldProvider"></select>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label" for="fieldModelSelect">Model</label>
|
||
<select id="fieldModelSelect"></select>
|
||
</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label">Auth mode</label>
|
||
<div class="auth-mode-toggle" id="authModeToggle">
|
||
<button data-mode="api" class="selected">API key</button>
|
||
<button data-mode="subscription">Subscription (local CLI login)</button>
|
||
</div>
|
||
<div class="field-help" id="authModeHelp">Uses the API key set in Auth & Keys for this provider.</div>
|
||
</div>
|
||
<div class="check-row"><input type="checkbox" id="fieldMcp" /> <label for="fieldMcp">Playwright MCP (browser tool access, subscription backends only)</label></div>
|
||
|
||
<div>
|
||
<div class="section-title">Run settings</div>
|
||
</div>
|
||
<div class="field-row">
|
||
<div class="field-group"><label class="field-label" for="fieldVotes">Votes</label><input class="narrow" id="fieldVotes" type="number" min="1" max="9" value="3" /><div class="field-help">Models that must agree before a finding is kept.</div></div>
|
||
<div class="field-group"><label class="field-label" for="fieldChain">Chain depth</label><input class="narrow" id="fieldChain" type="number" min="0" max="5" value="2" /><div class="field-help">How far findings get chained into attack paths.</div></div>
|
||
<div class="field-group"><label class="field-label" for="fieldRecon">Recon intensity</label>
|
||
<select class="narrow" id="fieldRecon">
|
||
<option value="1">1 · quick</option>
|
||
<option value="2">2 · standard</option>
|
||
<option value="3" selected>3 · deep</option>
|
||
<option value="4">4 · exhaustive</option>
|
||
</select>
|
||
<div class="field-help">Deeper recon finds more surface but costs more tokens.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 5 — Review -->
|
||
<div class="wizard-panel" data-panel="4" hidden>
|
||
<div>
|
||
<div class="section-title">Review</div>
|
||
<div class="section-desc">Confirm before launching — this spawns the real CLI harness.</div>
|
||
</div>
|
||
<div class="review-grid" id="reviewGrid"></div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<footer class="wizard-footer">
|
||
<div class="summary-line" id="wizardSummary"></div>
|
||
<div class="footer-actions">
|
||
<button class="btn" id="btnStepBack">← Back</button>
|
||
<button class="btn btn-primary" id="btnStepNext">Next →</button>
|
||
<button class="btn btn-primary" id="btnLaunch" hidden>Start Exploitation →</button>
|
||
</div>
|
||
</footer>
|
||
</section>
|
||
|
||
<!-- ============ LIVE RUN ============ -->
|
||
<section class="runpage" id="liveView" hidden>
|
||
<header class="run-head">
|
||
<div class="run-head-main">
|
||
<div class="run-target" id="liveTarget">—</div>
|
||
<div class="run-meta" id="liveTargetSub"></div>
|
||
<div class="run-meta"><span class="phase-dot" id="phaseDot"></span><span id="livePhase">starting</span></div>
|
||
<div class="run-meta" id="livePinned"></div>
|
||
</div>
|
||
<div class="run-actions">
|
||
<button class="btn" id="btnOpenTerm3">❭_ Terminal</button>
|
||
<a class="btn" id="btnOpenReport" target="_blank" hidden>Open report</a>
|
||
<button class="btn btn-danger" id="btnStopRun">Stop</button>
|
||
<button class="btn" id="btnBackToBoard">← New engagement</button>
|
||
</div>
|
||
</header>
|
||
<div class="progress-wrap">
|
||
<div class="progress-bar" id="progressBar"><div class="progress-fill" id="progressFill"></div></div>
|
||
<div class="progress-label" id="progressLabel">0 / 0 agents</div>
|
||
</div>
|
||
<nav class="run-tabs">
|
||
<button class="run-tab active" data-tab="findings">Findings <span id="liveFindingsCount">0</span></button>
|
||
<button class="run-tab" data-tab="attackpath">Generative Attack Path Chaining</button>
|
||
<button class="run-tab" data-tab="log">Activity log</button>
|
||
</nav>
|
||
<div class="run-body">
|
||
<div class="run-tab-panel" data-tabpanel="findings">
|
||
<div class="findings-toolbar">
|
||
<div class="sev-summary" id="liveSevSummary"></div>
|
||
<div class="topbar-spacer"></div>
|
||
<div class="search-wrap">
|
||
<span class="search-icon" aria-hidden="true">⌕</span>
|
||
<input id="liveFindingSearch" type="text" placeholder="Filter findings" />
|
||
</div>
|
||
</div>
|
||
<div class="table-wrap">
|
||
<table class="data-table" id="liveFindingsTable">
|
||
<thead><tr><th data-sort="severity">Severity</th><th data-sort="title">Title</th><th data-sort="endpoint">Endpoint</th><th data-sort="cwe">CWE</th><th data-sort="agent">Agent</th><th data-sort="confidence" class="col-conf">Conf.</th></tr></thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
<div class="empty-state" id="liveFindingsEmpty">No validated findings yet.</div>
|
||
</div>
|
||
<div class="run-tab-panel" data-tabpanel="attackpath" hidden><div id="liveAttackPath"></div></div>
|
||
<div class="run-tab-panel log-tab-panel" data-tabpanel="log" hidden>
|
||
<div class="log-panel" id="logList"></div>
|
||
<div class="send-prompt-row" id="sendPromptRow" hidden>
|
||
<span class="repl-prompt">❭</span>
|
||
<input id="sendPromptInput" type="text" autocomplete="off" spellcheck="false" placeholder="/status · /stop · /continue · or describe it in plain language" />
|
||
<button class="btn btn-sm" id="btnSendPromptTerm" title="Open this session in the full terminal">Open in terminal</button>
|
||
</div>
|
||
<div class="field-help" id="sendPromptHelp" hidden>This session stays interactive while the engagement runs — type a command or plain instruction and press Enter.</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ RUN DETAIL (past run) ============ -->
|
||
<section class="runpage" id="detailView" hidden>
|
||
<header class="run-head">
|
||
<div class="run-head-main">
|
||
<div class="run-target" id="detailTarget">—</div>
|
||
<div class="run-meta" id="detailTargetSub"></div>
|
||
<div class="run-meta"><span class="phase-dot static" id="detailDot"></span><span id="detailState">—</span></div>
|
||
<div class="run-meta run-facts" id="detailFacts"></div>
|
||
</div>
|
||
<div class="run-actions">
|
||
<a class="btn" id="detailOpenReport" target="_blank" hidden>Open report</a>
|
||
<button class="btn" id="btnDetailBack">← New engagement</button>
|
||
</div>
|
||
</header>
|
||
<nav class="run-tabs">
|
||
<button class="run-tab active" data-tab="findings">Findings <span id="detailFindingsCount">0</span></button>
|
||
<button class="run-tab" data-tab="attackpath">Generative Attack Path Chaining</button>
|
||
</nav>
|
||
<div class="run-body">
|
||
<div class="run-tab-panel" data-tabpanel="findings">
|
||
<div class="findings-toolbar">
|
||
<div class="sev-summary" id="detailSevSummary"></div>
|
||
<div class="topbar-spacer"></div>
|
||
<div class="search-wrap">
|
||
<span class="search-icon" aria-hidden="true">⌕</span>
|
||
<input id="detailFindingSearch" type="text" placeholder="Filter findings" />
|
||
</div>
|
||
</div>
|
||
<div class="table-wrap">
|
||
<table class="data-table" id="detailFindingsTable">
|
||
<thead><tr><th data-sort="severity">Severity</th><th data-sort="title">Title</th><th data-sort="endpoint">Endpoint</th><th data-sort="cwe">CWE</th><th data-sort="agent">Agent</th><th data-sort="confidence" class="col-conf">Conf.</th></tr></thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
<div class="empty-state" id="detailFindingsEmpty">No validated findings.</div>
|
||
</div>
|
||
<div class="run-tab-panel" data-tabpanel="attackpath" hidden><div id="detailAttackPath"></div></div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ TERMINAL DOCK (real CLI harness session) ============ -->
|
||
<section class="term-dock" id="termDock" hidden>
|
||
<div class="term-resize" id="termResize" title="Drag to resize"></div>
|
||
<div class="term-head">
|
||
<span class="term-dot" id="termDot" data-state="off"></span>
|
||
<span class="term-title">NeuroSploit harness</span>
|
||
<select class="term-target" id="termTarget" title="Where this terminal's input goes">
|
||
<option value="session">standalone REPL session</option>
|
||
</select>
|
||
<span class="term-status" id="termStatus">disconnected</span>
|
||
<div class="topbar-spacer"></div>
|
||
<button class="term-btn" id="btnTermClear" title="Clear screen (Ctrl+L)">clear</button>
|
||
<button class="term-btn" id="btnTermRestart" title="Start a fresh harness session">restart</button>
|
||
<button class="term-btn" id="btnTermExpand" title="Expand / collapse the dock">expand</button>
|
||
<button class="icon-btn" id="btnTermClose" title="Close (Esc)">✕</button>
|
||
</div>
|
||
<div class="term-alert" id="termAlert" hidden></div>
|
||
<div class="term-host" id="termHost"></div>
|
||
<div class="term-hints" id="termHints">
|
||
<span class="k">Enter</span> send · <span class="k">↑↓</span> history · <span class="k">Tab</span> complete · <span class="k">Ctrl+C</span> interrupt · <span class="k">Ctrl+L</span> clear
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
</div>
|
||
|
||
<!-- ============ AUTH & KEYS MODAL ============ -->
|
||
<div class="modal-overlay" id="authModal" hidden>
|
||
<div class="modal">
|
||
<div class="modal-head">
|
||
<div class="title">Auth & Keys</div>
|
||
<button class="icon-btn" id="btnCloseAuth">✕</button>
|
||
</div>
|
||
<div class="modal-tabs">
|
||
<button class="modal-tab active" data-mtab="target">Target auth</button>
|
||
<button class="modal-tab" data-mtab="keys">API keys</button>
|
||
<button class="modal-tab" data-mtab="creds">Creds file</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="modal-panel" data-mpanel="target">
|
||
<div class="field-group">
|
||
<label class="field-label" for="authHeader">Auth header</label>
|
||
<input id="authHeader" type="text" placeholder="Authorization: Bearer <token> or Cookie: session=..." />
|
||
<div class="field-help">Used so agents test as a logged-in user. Kept only for this session, sent to the CLI as an ephemeral creds file.</div>
|
||
</div>
|
||
<div class="field-group">
|
||
<label class="field-label">Named roles (multi-identity access-control testing)</label>
|
||
<div class="role-list" id="roleList"></div>
|
||
<button class="btn btn-sm" id="btnAddRole" style="align-self:flex-start;">+ Add role</button>
|
||
<div class="field-help">Two or more roles enable IDOR/BOLA/BFLA cross-role testing.</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-panel" data-mpanel="keys" hidden>
|
||
<div class="field-help" style="margin-bottom:12px;">Keys are kept in this server process's memory only — never written to disk. Cleared on restart.</div>
|
||
<div id="providerKeyList"></div>
|
||
</div>
|
||
<div class="modal-panel" data-mpanel="creds" hidden>
|
||
<div class="field-group">
|
||
<label class="field-label" for="credsPath">creds.yaml path (overrides target auth above)</label>
|
||
<input id="credsPath" type="text" placeholder="creds.yaml" />
|
||
<div class="field-help">An explicit file on disk — see neurosploit-rs/creds.example.yaml for the schema (jwt/header/cookie/login/roles/ssh/windows/cloud).</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ CUSTOM LEAD MODAL ============ -->
|
||
<div class="modal-overlay" id="leadModal" hidden>
|
||
<div class="modal modal-sm">
|
||
<div class="modal-head">
|
||
<div class="title">Custom lead</div>
|
||
<button class="icon-btn" id="btnCloseLead">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="field-group">
|
||
<label class="field-label" for="leadDesc">What should this lead test?</label>
|
||
<textarea id="leadDesc" placeholder="e.g. Abuse the invoice PDF export to read internal files via the template engine."></textarea>
|
||
<div class="field-help">Claude (Opus, subscription) generates a real specialist agent file for it and pins it. If generation is unavailable, the text is folded into <code>--focus</code> instead.</div>
|
||
</div>
|
||
<div class="field-error" id="errLead" hidden></div>
|
||
</div>
|
||
<div class="modal-foot">
|
||
<button class="btn" id="btnLeadCancel">Cancel</button>
|
||
<button class="btn btn-primary" id="btnLeadGenerate">Generate lead</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ============ FINDING DETAIL MODAL ============ -->
|
||
<div class="modal-overlay" id="findingModal" hidden>
|
||
<div class="modal modal-lg">
|
||
<div class="modal-head">
|
||
<div>
|
||
<span class="sev" id="fmSev">—</span>
|
||
<span class="title" id="fmTitle" style="margin-left:8px;">—</span>
|
||
</div>
|
||
<button class="icon-btn" id="btnCloseFinding">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="review-grid" id="fmMeta" style="margin-bottom: var(--sp-5);"></div>
|
||
|
||
<div id="fmSection-evidence"></div>
|
||
<div id="fmSection-impact"></div>
|
||
<div id="fmSection-remediation"></div>
|
||
<div id="fmSection-chains"></div>
|
||
|
||
<div class="field-group">
|
||
<label class="field-label">Proof of concept</label>
|
||
<div id="fmPocList" class="field-help">—</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toasts" id="toasts"></div>
|
||
|
||
<script src="/vendor/xterm.js"></script>
|
||
<script src="/vendor/xterm-addon-fit.js"></script>
|
||
<script src="/app.js"></script>
|
||
</body>
|
||
</html>
|