mirror of
https://github.com/CyberSecurityUP/NeuroSploit.git
synced 2026-09-29 20:41:51 +02:00
feat(report): rebuild reports on demand, from the CLI and the web
A PDF was only ever produced while a run was finishing. If `typst` was missing at that moment — or the template improved afterwards — the operator had no way to get one without re-running the whole engagement against the target. report::rebuild() regenerates every artifact (md · json · html · pdf) from the findings already on disk, exposed as `neurosploit rebuild <run-id|dir>` and as POST /api/runs/:id/report with a "Generate report" button in the run view. The endpoint shells out to the harness rather than reimplementing report generation in JavaScript, so there is one implementation instead of two that drift, and it says plainly when the PDF was skipped for want of `typst` instead of handing back a link to a file that was never produced. Also fixes write_all() to pass the run's pocs/ listing into the HTML report, so a rebuilt report links the scripts each finding cites — the run-time path already did this and the rebuild path silently did not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
481a4eb1b9
commit
61ae3bc74d
@@ -784,6 +784,28 @@ function leaveLiveJob() {
|
||||
termSyncTargets();
|
||||
}
|
||||
$('#btnBackToBoard').addEventListener('click', () => { leaveLiveJob(); show($('#liveView'), false); show($('#dashView'), false); show($('#wizardView'), true); });
|
||||
// Regenerating from the evidence already on disk, rather than re-running the
|
||||
// engagement: a run whose PDF was never produced (no `typst` at the time, or a
|
||||
// since-improved template) would otherwise be unreportable.
|
||||
$('#btnBuildReport').addEventListener('click', async () => {
|
||||
const id = state.currentDetailId;
|
||||
if (!id) return;
|
||||
const btn = $('#btnBuildReport');
|
||||
const label = btn.textContent;
|
||||
btn.disabled = true;
|
||||
btn.textContent = 'Generating…';
|
||||
try {
|
||||
const r = await api(`/api/runs/${encodeURIComponent(id)}/report`, { method: 'POST' });
|
||||
toast(r.pdf ? 'Report rebuilt — PDF ready.' : (r.note || 'Report rebuilt.'), r.pdf ? 'ok' : 'warn', 7000);
|
||||
await loadDetail(id);
|
||||
} catch (e) {
|
||||
toast(`Couldn't generate the report: ${e.message}`, 'error', 9000);
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.textContent = label;
|
||||
}
|
||||
});
|
||||
|
||||
$('#btnDetailBack').addEventListener('click', () => { clearInterval(state.detailPoll); show($('#detailView'), false); show($('#dashView'), false); show($('#wizardView'), true); });
|
||||
$('#btnNewEngagement').addEventListener('click', () => { leaveLiveJob(); clearInterval(state.detailPoll); show($('#detailView'), false); show($('#liveView'), false); show($('#dashView'), false); show($('#wizardView'), true); });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user