From 12f863495f191d826c5a994dc110f2d333268360 Mon Sep 17 00:00:00 2001 From: blakeaowens Date: Tue, 22 Sep 2026 02:29:08 -0500 Subject: [PATCH] docs(reporting): document the Report Builder CSV, Excel and JSON formats A Generated Report can now be produced as CSV, Excel or JSON alongside PDF and HTML. The data formats carry the rows a report is built from rather than the document built around them, which is what makes a report automatable: a script, a spreadsheet or a downstream system can consume one directly. Documents what a reader needs to know before choosing one: - The five formats, split into the Document and Data groups. - That a data format includes only Tabular and Detail blocks, because a cover page, a chart or a widget has nothing to put in a cell, and that the generate dialog names the included and left-out blocks before you generate. - The per-format shape: CSV sections for a multi-block template, one Excel worksheet per block, and the JSON envelope (with a worked example), including why JSON rows are keyed by field path rather than by label. - How truncation is reported in each format. - The `file_format` values on the API, and the Triage Engine report node's Format setting. English only; translated pages are regenerated on the quarterly refresh. Co-Authored-By: Claude Opus 5 --- .../triage_engine/node_reference.md | 2 +- .../reports/PRO__report_builder.md | 30 ++++++++++++++-- .../reports/PRO__report_builder_api.md | 34 +++++++++++++++++-- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/docs/content/automation/triage_engine/node_reference.md b/docs/content/automation/triage_engine/node_reference.md index 40698eb5c6b..36923f5efab 100644 --- a/docs/content/automation/triage_engine/node_reference.md +++ b/docs/content/automation/triage_engine/node_reference.md @@ -675,7 +675,7 @@ Generates a report from a template, scoped to the Findings that reached this nod | Setting | Default | Notes | |---------|---------|-------| | **Report Template** | none | Which template to generate from. Required. | -| **Format** | `pdf` | `pdf` or `html`. | +| **Format** | `pdf` | `pdf`, `html`, `csv`, `xlsx` (Excel) or `json`. The data formats (`csv`, `xlsx`, `json`) carry only the template's Tabular and Detail blocks: a cover page, a chart or a widget has nothing to put in a cell and is left out. They are what a scheduled rule hands to a downstream system rather than to a reader. See [the Report Builder](/metrics_reports/reports/report-builder/). | | **Findings Included** | `batch_findings` | `batch_findings` limits the report to the Findings that reached this node. `template_default` lets the template use its own filters. `trigger_tests` (Findings of the Triggering Imports) is for rules that start from **When a Scan Has Landed** or **When a Group of Scans Has Landed**: every Finding of the tests those imports wrote. | | **Announce Over** | none | A [Messaging Connector](/issue_tracking/pro_integration/messaging_connectors/) to post the download link over once the report is generated. Leave empty to not announce. | | **Announce To** | empty | Shown once a connection is chosen. Where that connection sends: a Slack channel ID, email addresses, and so on. | diff --git a/docs/content/metrics_reports/reports/PRO__report_builder.md b/docs/content/metrics_reports/reports/PRO__report_builder.md index c84a3a70cbc..ccf197437c2 100644 --- a/docs/content/metrics_reports/reports/PRO__report_builder.md +++ b/docs/content/metrics_reports/reports/PRO__report_builder.md @@ -114,7 +114,7 @@ A Chart also has a **Date Range** setting. Leave it on **All time** (the default | Severity of Findings Past SLA by Asset | Past-SLA findings per asset, broken out by severity | | Assets Tested Over Time | Count of distinct assets tested in each period | -Charts appear in Block and Template previews and in the reports you generate, in both HTML and PDF output. Reports created through the [API](../report-builder-api/), and reports delivered automatically by a rule, include their charts as well. +Charts appear in Block and Template previews and in the reports you generate, in both HTML and PDF output. Reports created through the [API](../report-builder-api/), and reports delivered automatically by a rule, include their charts as well. The CSV, Excel and JSON formats carry rows rather than a document, so a Chart Block is left out of those. > **💡 Tip:** A Chart block carries its filters like any other Block, so the same chart filtered two ways is two Blocks. Duplicate the Block and adjust the copy rather than editing one shared Block. @@ -171,7 +171,31 @@ You can build this in the UI (below) or automate it with the [API](../report-bui ### Generated Reports -Running a Template produces a **Generated Report**: a persisted PDF or HTML file that you can download and re-run on demand. Each Generated Report is **frozen in time** — it captures your DefectDojo data at the moment it was generated and does **not** update automatically when the underlying data later changes. To get a fresh snapshot, re-run the Template. +Running a Template produces a **Generated Report**: a persisted file that you can download and re-run on demand. Each Generated Report is **frozen in time**: it captures your DefectDojo data at the moment it was generated and does **not** update automatically when the underlying data later changes. To get a fresh snapshot, re-run the Template. + +A Generated Report comes in one of five formats, in two groups: + +| Format | Group | What it contains | +|--------|-------|------------------| +| HTML | Document | The whole Template, laid out: every Block, in order | +| PDF | Document | The same, paginated for print and distribution | +| CSV | Data | The rows of the Template's Tabular and Detail Blocks | +| Excel | Data | The same rows, one worksheet per Block | +| JSON | Data | The same rows, with each Block's columns and labels | + +The documents are what you send to a reader. The data formats are what you hand to a script, a spreadsheet, or a downstream system: they carry the rows a report is built from rather than the document built around them. + +**A data format includes only the Blocks that have rows:** Tabular and Detail Blocks. A Cover Page, a Chart, a Widget and the other Stock Blocks have nothing to put in a cell, so they are left out. The generate dialog names exactly which of your Template's Blocks will be included and which will be left out before you generate, and a Template with no Tabular or Detail Block at all cannot be generated as a data format. + +Within a data format, the shape follows the Template: + +- **CSV.** A Template with one data Block produces a plain CSV: a header row of your chosen column labels, then the rows. A Template with several data Blocks writes them one after another, each preceded by a `# ` comment line and separated by a blank line. +- **Excel.** Each data Block becomes its own worksheet, named after the Block's header. +- **JSON.** One object carrying the report's name and generation time, then a `blocks` array. Each Block lists its `columns` (the field path and the label you see in the UI) and its `rows`, keyed by field path so a consumer is not broken by a label being renamed. + +If a Block hits the row limit, the export says so: CSV and Excel add a trailing "rows omitted" line, and JSON carries an `omitted_rows` count per Block. + +> **💡 Tip:** Rules can generate a report too. A rule's **Generate a Report** action offers the same five formats, which is how a scheduled rule delivers a spreadsheet to a downstream system rather than a document somebody has to read. See the Triage Engine's [Node Reference](/automation/triage_engine/node_reference/). A Generated Report moves through these statuses as it is built: @@ -228,7 +252,7 @@ In the Template editor, you select a Theme and arrange the Blocks in the order t ### Step 4: Generate and download -When the Template is ready, generate the report. The generate dialog confirms the Template and lets you choose the output format — **HTML** or **PDF**. +When the Template is ready, generate the report. The generate dialog confirms the Template and lets you choose the output format: **HTML**, **PDF**, **CSV**, **Excel**, or **JSON**. Pick one of the data formats and the dialog tells you which of the Template's Blocks it will include and which it will leave out, so you know before you generate rather than after you open the file. ![Generate report dialog](images/pro_generate_report_dialog.png) diff --git a/docs/content/metrics_reports/reports/PRO__report_builder_api.md b/docs/content/metrics_reports/reports/PRO__report_builder_api.md index 854bcb42723..82b5b3fc7e1 100644 --- a/docs/content/metrics_reports/reports/PRO__report_builder_api.md +++ b/docs/content/metrics_reports/reports/PRO__report_builder_api.md @@ -314,7 +314,37 @@ Replace `theme_id` and each `block_id` with the IDs returned in the previous ste Generating a report is asynchronous: you create a run, poll its status, then download the file once it completes. -**Start a run.** POST a `template_id` and a `file_format` of `pdf` or `html`: +**Start a run.** POST a `template_id` and a `file_format`. Five are available: + +| `file_format` | What you get | +|---------------|--------------| +| `pdf` | The whole template, paginated | +| `html` | The whole template, as a web page | +| `csv` | The rows of the template's Tabular and Detail blocks | +| `xlsx` | The same rows, one worksheet per block | +| `json` | The same rows, with each block's columns and labels | + +`csv`, `xlsx` and `json` are the formats to automate against: they carry the rows a report is built from rather than the document built around them. They include **only** the template's Tabular and Detail blocks, since a cover page, a chart or a widget has nothing to put in a cell. A template with no Tabular or Detail block fails with that explanation in `error_message`. + +The `json` body is one object carrying the report's name and generation time, then a `blocks` array. Each block lists its `columns` (the field path plus the label) and its `rows`, keyed by field path: + +```json +{ + "report": {"template": "Quarterly Critical Report", "template_id": 5, "generated_at": "2026-09-22T06:43:52.465Z"}, + "blocks": [ + { + "name": "Critical Findings", + "header": "Critical Findings", + "model": "finding", + "columns": [{"path": "id", "label": "ID"}, {"path": "title", "label": "Title"}], + "rows": [{"id": 1, "title": "SQL injection in the login form"}], + "omitted_rows": 0 + } + ] +} +``` + +Keying rows by field path rather than by label is deliberate: a label can be renamed in the UI, a field path cannot. ```bash curl -s -X POST \ @@ -376,7 +406,7 @@ BASE_URL = os.environ.get( "https://[YOUR-INSTANCE].cloud.defectdojo.com/api/v2", ).rstrip("/") TOKEN = os.environ["DD_IMPORTER_DOJO_API_TOKEN"] # fail loudly if unset -FILE_FORMAT = "pdf" # "pdf" or "html" +FILE_FORMAT = "pdf" # "pdf", "html", "csv", "xlsx", or "json" def api_request(method, path, body=None, accept_json=True):