When is forking a shipped ZAP report template the right call rather than configuring one?
answer
- configuration reaches further than people expect
- sections can only subtract
- a fork is markup you own
- the plan travels, the template does not
basics
~20 sFork only when the document itself is wrong: a shape or an output format nothing ships. Anything reachable by choosing a template and setting its theme, sections and filters should stay configuration, because a fork is markup you own.
solid answer
~40 sConfiguration already reaches a surprising amount: which template, which theme, which of that template's declared `sections` appear, and which alerts survive the `risks`, `confidences` and `sites` filters, plus the title and description. Fork when none of that can produce the document you need - a shape nothing ships, or an output format with no template at all. What you take on is real: a Thymeleaf body written against the add-on's context variables, a `Messages.properties` whose keys must line up with the section names in your `template.yaml`, and the fact that improvements to the shipped template you copied will never reach yours. There is also a distribution cost - a plan references a template by id, so the directory has to exist on every machine that runs the plan.
go deeper
Before reaching for a custom template, check whether another shipped one, a theme, or the sections list already gets you there - most requests are met without new markup.
Be able to say what a fork consists of: a template.yaml, a Thymeleaf body written against the add-on's context variables, and message keys matching every section name you declare.
Weigh the upkeep honestly. A forked template is markup with no upstream, and it has to be provisioned onto every runner because the job resolves it by directory name, not by path.
Treat the fork as a second artefact with its own lifecycle and owner, decide how it is distributed and versioned alongside the plans that name it, and be willing to say no when configuration would do.
## What configuration already reaches Before anyone forks anything, it is worth being precise about how far the supported levers go, because teams routinely fork to get something they could have configured: - **Which document.** The shipped set spans themed HTML, plain HTML, HTML with requests and responses, Markdown, XML, JSON and SARIF JSON, plus a PDF path. - **Which parts of it.** The `sections` list selects from whatever the chosen template declares. - **How it looks.** The `theme` parameter, where the template declares themes. - **What is in it.** The `risks`, `confidences` and `sites` lists, plus the plan's contexts, decide which alerts reach the template at all. - **What it says it is.** `reportTitle` and `reportDescription`. The cut-offs themselves are already disclosed by any template carrying a `reportParameters` section, so these two fields are for the context a machine cannot supply. If the gap between that and what you need is presentational, the answer is almost always a different shipped template rather than a new one. ## What only a fork reaches 1. **A structure nothing ships** - a document ordered around something other than alerts, or one that pulls in data the shipped templates do not surface. 2. **An output format with no template** - a feed shaped for a specific downstream consumer. 3. **Removing content the template has no section for.** Sections can only subtract from what a template declares; if the template never made that block optional, configuration cannot drop it. ## What a fork actually costs | you now own | why it is not free | |---|---| | a Thymeleaf body | written against context variables the add-on supplies - the filtered `alertTree`, `reportData`, a `helper`, pre-computed alert counts, statistics, the `resources` folder name - and those evolve with the add-on | | a `Messages.properties` | every section and theme name in your `template.yaml` needs its key, prefixed automatically with `report.template.section.` or `report.template.theme.` | | a `resources` folder, if you keep one | copied beside every generated report, so your output is a file plus a directory, forever | | the diff you no longer get | the template you copied keeps being improved upstream; your copy does not move | None of these is heavy on the day you fork. They are heavy in the second year, when the person who wrote the markup has moved on and a plan quietly stops rendering a block because a variable was renamed. ## The distribution problem, which is the real design decision A `report` job names a template by **id**, and that id is the name of a directory under the templates folder in ZAP's home directory. There is no way to point a job at a template path, and the plan file does not carry the template with it. The only lever is the add-on's own template-directory setting, which is ZAP configuration rather than plan data. So the moment you fork, you have created a second artefact with a different lifecycle from the plan: - the plan is text in the repository, reviewed with the change that motivated it; - the template is machine state that must be present on every runner before the plan will work. That has to be decided deliberately - baked into a container image, mounted at run time, or fetched during setup - and it has to be versioned, because a plan and a template that drift apart fail in the least helpful way available: an unknown-template error, on the runner, at the end of a scan that has already finished. ## How to decide 1. **Write down the document you want**, then check it against the shipped templates section by section. Most gaps close here. 2. **If a gap remains, ask whether it is content or shape.** Content gaps are usually filter or template choices. Shape gaps are the honest case for a fork. 3. **Fork shallowly.** Copy the closest shipped directory, keep its variable usage and its section keys, and change as little markup as you can - a shallow fork can absorb an upstream change by hand, a rewritten one cannot. 4. **Decide the distribution before you write the markup.** If nobody owns getting the directory onto every runner, the fork is not finished even when it renders perfectly on a laptop. 5. **Put the decision somewhere.** "We use a custom template" is a standing commitment, and it should be as visible as the plan that depends on it. The honest default for most teams is: choose a shipped template, narrow it with filters, say what you narrowed in the description, and spend the maintenance budget somewhere it buys more.
- Your fork renders on a laptop but a plan naming it errors on the CI runner. Why?The job resolves a template by directory name under the templates folder in that machine's ZAP home, and your directory is not there. The plan file does not carry the template with it and a job cannot be pointed at a path, so the directory has to be provisioned onto the runner - baked into the image, mounted, or copied during setup.
- What is the cheapest fork if you only need to drop one block from a shipped report?Check first whether that block is already a declared section - if it is, the `sections` list drops it with no fork at all. If it is not, copy the template directory, wrap the block in the same conditional the other sections use, add the name to `template.yaml` and a matching key to `Messages.properties`. That keeps the fork shallow enough to re-apply upstream changes by hand.
saying these in an interview costs you the question
- Forks a template to change colours that a theme already changes
- Assumes the plan file carries a custom template to the runner
- Thinks a section list can hide a block the template never made optional
- Treats a forked template as a one-off with no owner afterwards
- Expects upstream fixes to reach a copied template directory