Skip to content

feat(report): modernize HTML report UI and add exports#1338

Open
Santoshverma77 wants to merge 5 commits intoOWASP:masterfrom
Santoshverma77:feat/report-ui-exports-only
Open

feat(report): modernize HTML report UI and add exports#1338
Santoshverma77 wants to merge 5 commits intoOWASP:masterfrom
Santoshverma77:feat/report-ui-exports-only

Conversation

@Santoshverma77
Copy link

@Santoshverma77 Santoshverma77 commented Mar 2, 2026

Improve the generated HTML report with a professional layout and styling. Add client-side export actions (JSON/CSV/Text) plus print-to-PDF support while preserving existing data rendering.

Proposed change

Your PR description goes here.

Type of change

  • New core framework functionality
  • Bugfix (non-breaking change which fixes an issue)
  • Code refactoring without any functionality changes
  • New or existing module/payload change
  • Documentation/localization improvement
  • Test coverage improvement
  • Dependency upgrade
  • Other improvement (best practice, cleanup, optimization, etc)

Checklist

  • I've followed the contributing guidelines
  • I've run make pre-commit, it didn't generate any changes
  • I've run make test, all tests passed locally

Improve the generated HTML report with a professional layout and styling.
Add client-side export actions (JSON/CSV/Text) plus print-to-PDF support while preserving existing data rendering.

Made-with: Cursor
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 931556d and 7312988.

📒 Files selected for processing (1)
  • pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml

Summary by CodeRabbit

  • New Features

    • Added export options: JSON, CSV, Text, and PDF (print-based).
    • Interactive report summary showing aggregated Targets, Modules, and findings count.
    • Enhanced JSON viewing with safer parsing and conditional rendering.
  • Improvements

    • Revamped report layout with semantic sections and improved JSON action controls.
    • Clarified table header labels (title-cased) and better accessibility.
  • Chores

    • Broadened Python version support to include 3.11 and 3.12.

Walkthrough

Reworks the web report HTML scaffold and table markup, replaces client JSON parsing with a feature-rich, defensive implementation (including exports), tweaks core table header labels, and relaxes the Python version constraint in pyproject.toml.

Changes

Cohort / File(s) Summary
Core header change
nettacker/core/graph.py
Updated HTML report table header labels from lowercase keys to title-cased/descriptive labels (e.g., dateDate, module_nameModule, json_eventDetails (JSON)).
Report templates
nettacker/web/static/report/table_title.html, nettacker/web/static/report/table_items.html, nettacker/web/static/report/table_end.html
Replaced simple table header with a full report scaffold (header, meta, report-summary, export toolbar); introduced semantic row/cell classes, separated JSON container from the action button, enhanced button attributes/ARIA and SVG sizing, and adjusted table closing wrappers/containers.
Client JSON parsing & UI
nettacker/web/static/report/json_parse.js
Rewrote parsing/initialization to an IIFE with safe length handling, in-memory rawEvents/events arrays, guarded renderjson and Clipboard usage, aggregated non-fatal summary population (targets/modules/findings), and added export handlers/utilities for JSON, CSV, Text, and PDF.
Project metadata
pyproject.toml
Relaxed Python version specifier to a permissive range: changed the python constraint string to >=3.10,<3.13.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • arkid15r
  • securestep9
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(report): modernize HTML report UI and add exports' accurately summarizes the main changes: modernizing the HTML report UI with professional layout and adding export functionality (JSON/CSV/Text/PDF).
Description check ✅ Passed The description directly relates to the changeset, explaining the goal of improving the HTML report with professional layout and adding client-side export actions while preserving existing data rendering.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@nettacker/web/static/report/json_parse.js`:
- Around line 22-26: The current loop incorrectly skips rendering when the
clipboard button is missing; update the check so you only skip when the
container is absent (keep the lookup for button using "json_clipboard_"+i but do
not continue if button is null), render/parse into the container regardless, and
only attach clipboard functionality if button exists; apply the same change to
the second block that uses "json_event_"+i and "json_clipboard_"+i so missing
clipboard elements no longer prevent JSON from being parsed, rendered, included
in summaries, or exported.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 79d436f and 1ebc6bd.

📒 Files selected for processing (6)
  • nettacker/core/graph.py
  • nettacker/web/static/report/html_table.css
  • nettacker/web/static/report/json_parse.js
  • nettacker/web/static/report/table_end.html
  • nettacker/web/static/report/table_items.html
  • nettacker/web/static/report/table_title.html

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@nettacker/web/static/report/json_parse.js`:
- Around line 112-139: The toCSV function derives headers from only the first
row which can drop fields present in later rows; update the headers logic in
toCSV to collect the union of keys across all objects in data (e.g., iterate
over data and add Object.keys(row) to a Set), then convert that set to an array
(optionally sorted for deterministic output) and use that array in the existing
headers/rows/escapeCell flow so all columns from every event are exported.
- Around line 142-166: The toText function currently ignores entries that only
have the fallback ev.raw (created when JSON parsing failed), resulting in empty
lines; update toText (in function toText) to detect ev.raw and include it in the
parts array (e.g., push ev.raw when present or when no other fields were added)
so non-JSON events render their raw content in the text export while preserving
existing fields like ev.date, ev.target, ev.module_name, ev.port, and ev.event.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ebc6bd and 11888f3.

📒 Files selected for processing (1)
  • nettacker/web/static/report/json_parse.js

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
nettacker/web/static/report/json_parse.js (2)

141-165: ⚠️ Potential issue | 🟡 Minor

Text export still omits fallback raw content for non-JSON entries.

When parsing fails (Line 34), events become { raw: value }, but toText never includes ev.raw, producing near-empty lines at Line 163.

🔧 Proposed fix
       if (ev.event) {
         parts.push("- " + ev.event);
       }
+      if (!parts.length && ev.raw) {
+        parts.push(ev.raw);
+      }
       lines.push((index + 1) + ". " + parts.join(" "));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/web/static/report/json_parse.js` around lines 141 - 165, toText
currently ignores the parsed fallback payload stored as ev.raw for non-JSON
events, producing near-empty lines; update the toText function to check for
ev.raw and include it in the parts array (e.g., push ev.raw when present,
perhaps after ev.event or if parts is empty) so the rendered line contains the
raw content for events that failed JSON parsing; ensure you reference the toText
function and the ev.raw property when making the change so empty entries are
replaced with the raw payload.

111-139: ⚠️ Potential issue | 🟠 Major

CSV export still drops columns that appear after the first event.

Line 115 derives headers from only data[0], so fields present only in later rows are omitted from export.

🔧 Proposed fix
 function toCSV(data) {
   if (!data.length) {
     return "";
   }
-  const headers = Object.keys(data[0]);
+  const headerSet = new Set();
+  data.forEach(function (row) {
+    Object.keys(row || {}).forEach(function (key) {
+      headerSet.add(key);
+    });
+  });
+  const headers = Array.from(headerSet);

   const escapeCell = function (cell) {
@@
   data.forEach(function (row) {
     rows.push(
       headers
         .map(function (key) {
-          return escapeCell(row[key]);
+          return escapeCell(row ? row[key] : "");
         })
         .join(","),
     );
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/web/static/report/json_parse.js` around lines 111 - 139, The CSV
export in toCSV() builds headers from only data[0], dropping keys that appear
later; update toCSV to compute headers as the union of all object keys across
every row (preserving first-seen order) instead of Object.keys(data[0]). Locate
function toCSV (and escapeCell helper) and replace the headers assignment with
logic that iterates over data, collects unique keys into an array in encounter
order, then use that headers array for the header row and subsequent row mapping
so all fields from any event are included in the CSV.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pyproject.toml`:
- Line 47: Update the Python version constraint in pyproject.toml from
">=3.10,<3.14" to ">=3.10,<3.13" so the package metadata matches the documented
supported range (Python 3.10–3.12); locate the python = "...” entry in
pyproject.toml and modify the version specifier accordingly.

---

Duplicate comments:
In `@nettacker/web/static/report/json_parse.js`:
- Around line 141-165: toText currently ignores the parsed fallback payload
stored as ev.raw for non-JSON events, producing near-empty lines; update the
toText function to check for ev.raw and include it in the parts array (e.g.,
push ev.raw when present, perhaps after ev.event or if parts is empty) so the
rendered line contains the raw content for events that failed JSON parsing;
ensure you reference the toText function and the ev.raw property when making the
change so empty entries are replaced with the raw payload.
- Around line 111-139: The CSV export in toCSV() builds headers from only
data[0], dropping keys that appear later; update toCSV to compute headers as the
union of all object keys across every row (preserving first-seen order) instead
of Object.keys(data[0]). Locate function toCSV (and escapeCell helper) and
replace the headers assignment with logic that iterates over data, collects
unique keys into an array in encounter order, then use that headers array for
the header row and subsequent row mapping so all fields from any event are
included in the CSV.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11888f3 and 942c8e8.

📒 Files selected for processing (3)
  • nettacker/web/static/report/html_table.css
  • nettacker/web/static/report/json_parse.js
  • pyproject.toml

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
nettacker/web/static/report/json_parse.js (1)

139-146: ⚠️ Potential issue | 🟡 Minor

Add defensive null-check for row in mapping.

The header collection loop defensively checks if (row && typeof row === "object") (line 118), but the row mapping at line 143 doesn't. If data ever contains a null/undefined entry, row[key] throws.

🛡️ Proposed fix
       data.forEach(function (row) {
         rows.push(
           headers
             .map(function (key) {
-              return escapeCell(row[key]);
+              return escapeCell(row ? row[key] : undefined);
             })
             .join(","),
         );
       });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/web/static/report/json_parse.js` around lines 139 - 146, The
mapping over data rows can throw if an entry is null/undefined; update the
data.forEach mapping (the block that calls headers.map and escapeCell) to first
check that row is an object (e.g., row && typeof row === "object") and skip or
substitute an empty object/empty cells when it isn't; ensure the same defensive
check used earlier is applied before calling row[key] so headers.map never
accesses properties on null/undefined.
🧹 Nitpick comments (2)
nettacker/web/static/report/json_parse.js (2)

18-18: Remove unused rawEvents array.

rawEvents is populated at line 28 but never read. If there's no planned use, remove it to avoid confusion.

🧹 Proposed fix
-    const rawEvents = [];
     const events = [];

And remove from the loop:

       const value = container.innerText;
-      rawEvents.push(value);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/web/static/report/json_parse.js` at line 18, Remove the unused
array declaration and its population: delete the declaration "const rawEvents =
[];" and remove any "rawEvents.push(...)" calls inside the loop (where events
are parsed/populated) so no dead variable remains; ensure there are no other
references to rawEvents after removal and keep the rest of the parsing logic
(e.g., the parsed events variable used elsewhere) intact.

91-93: Consider logging caught errors for debugging.

Silent catch blocks can obscure issues during development. Since summary is non-critical, log rather than throw.

🔧 Proposed fix
     } catch (e) {
-      // Non-fatal, summary is optional
+      // Non-fatal, summary is optional
+      console.warn("Summary population failed", e);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@nettacker/web/static/report/json_parse.js` around lines 91 - 93, The catch
block that swallows errors for the summary parse (the catch (e) after attempting
to parse "summary") should log the exception instead of remaining silent; update
the catch handling in nettacker/web/static/report/json_parse.js (the catch (e)
block that comments "Non-fatal, summary is optional") to call the project's
logging mechanism or at minimum console.warn/console.debug with a clear message
and the error object (include context like "Failed to parse summary" and the
error) so developers can diagnose malformed summary data without throwing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@nettacker/web/static/report/json_parse.js`:
- Around line 139-146: The mapping over data rows can throw if an entry is
null/undefined; update the data.forEach mapping (the block that calls
headers.map and escapeCell) to first check that row is an object (e.g., row &&
typeof row === "object") and skip or substitute an empty object/empty cells when
it isn't; ensure the same defensive check used earlier is applied before calling
row[key] so headers.map never accesses properties on null/undefined.

---

Nitpick comments:
In `@nettacker/web/static/report/json_parse.js`:
- Line 18: Remove the unused array declaration and its population: delete the
declaration "const rawEvents = [];" and remove any "rawEvents.push(...)" calls
inside the loop (where events are parsed/populated) so no dead variable remains;
ensure there are no other references to rawEvents after removal and keep the
rest of the parsing logic (e.g., the parsed events variable used elsewhere)
intact.
- Around line 91-93: The catch block that swallows errors for the summary parse
(the catch (e) after attempting to parse "summary") should log the exception
instead of remaining silent; update the catch handling in
nettacker/web/static/report/json_parse.js (the catch (e) block that comments
"Non-fatal, summary is optional") to call the project's logging mechanism or at
minimum console.warn/console.debug with a clear message and the error object
(include context like "Failed to parse summary" and the error) so developers can
diagnose malformed summary data without throwing.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 942c8e8 and 931556d.

📒 Files selected for processing (1)
  • nettacker/web/static/report/json_parse.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant