In ZAP's packaged scans, what is the tab-separated file passed with -c, and what is on each line?
answer
- tabs, not spaces, and three tokens minimum
- column one is the rule id
- the generator writes everything at WARN
- anything unlisted defaults to warning
basics
~10 sIt is a per-rule verdict file: each tab-separated line pins one numeric scan-rule id to IGNORE, INFO, WARN or FAIL, with an optional note. Any rule the file omits defaults to WARN.
solid answer
~50 sThe packaged scan scripts take a plain tab-separated file -- `-c` reads it from disk, `-u` fetches it over HTTP, and `-g` writes a starting copy with every rule already at `WARN`. Lines beginning with `#` are comments; every other line must carry at least three tab-separated tokens or the parser rejects the file. Column one is the numeric scan-rule id, column two is the verdict, column three a free-text note, and an optional fourth field your own message, printed beside that rule's findings. Column two takes one of five level words -- `PASS`, `IGNORE`, `INFO`, `WARN`, `FAIL` -- or the special word `OUTOFSCOPE`, which turns the line into a URL filter instead; anything else raises. A rule the file never mentions defaults to `WARN`, which `-i` flips to `INFO`. The verdict decides which bucket that rule's findings land in, and the buckets are what the exit code is derived from.
code
bash · 9 lines# -g writes a starting file: every rule the run knows, all at WARN
zap-baseline.py -t https://example.com -g rules.conf
# each line is TAB separated: <rule id> <verdict> <note> [<your message>]
# <noisy-rule-id>\tIGNORE\t(rule name)\taccepted, tracked elsewhere
# <blocking-rule-id>\tFAIL\t(rule name)\tmust not regress
# feed the edited copy back in; -u would fetch the same format over HTTP
zap-baseline.py -t https://example.com -c rules.confgo deeper
Recall that the file is tab-separated, that column one is the numeric rule id and column two the verdict, and that anything you leave out is treated as a warning. Generating a starting copy is what -g is for.
Explain the mechanics: the minimum-three-tokens parse, the WARN default and how -i inverts it, and the fact that an active rule marked IGNORE is switched off rather than merely reclassified. Name the five accepted words.
Talk about keeping the file honest over time -- regenerating it after a rule-set upgrade, diffing for new ids, and using the fourth column so the reason travels into the build log with the finding.
Own the question of where this file lives and who may edit it: one shared copy behind a URL, or one per service. Each answer trades consistency against a team's ability to accept a finding it understands.
## What the file is for ZAP's packaged scan scripts do not decide on their own which findings should stop a build. They sort every finding into a bucket by **rule**, and this file is where you say which bucket each rule gets. It is where an unattended run records a human judgment about a specific rule. Three options reference it: - **`-c <file>`** -- read the file from disk (inside the container, from the mounted working directory). - **`-u <url>`** -- fetch exactly the same format over HTTP, so several pipelines can share one governed copy. - **`-g <file>`** -- *write* a starting file instead of reading one, listing every rule the run knows about with the verdict `WARN`. ## The line format, exactly The parser is deliberately blunt. It skips blank lines and lines starting with `#`, and it counts tabs: a line with fewer than two tabs is rejected with an error naming the line, so a file edited in a tool that helpfully converts tabs to spaces fails loudly rather than quietly. | column | contents | notes | |---|---|---| | 1 | the numeric scan-rule id | on a verdict line, one id -- not a list and not a wildcard | | 2 | the verdict | one of `PASS`, `IGNORE`, `INFO`, `WARN`, `FAIL` -- or `OUTOFSCOPE`, which changes what the line means | | 3 | a free-text note | the generator writes the rule's name here in brackets; it is decoration | | 4 | your own message | optional; printed beside that rule's findings in the run output | Two things about column one are worth pinning down, because the file has a second kind of line (an out-of-scope line) where the rules differ: - On a **verdict** line, column one is a single id. The comma-separated list and the `*` wildcard are parsed only on the out-of-scope branch, so a verdict line that uses either matches no rule at all and quietly does nothing. - Worse, on `zap-baseline.py`'s automation-framework path the plan builder converts each verdict line's id with an integer conversion, so a `*` or a comma list there is not a wildcard -- it is an error. ## The verdicts and what each one buys you - **`FAIL`** -- this rule's findings go in the failing bucket, and the run exits `1` when it alerts. - **`WARN`** -- the warning bucket; the run exits `2` unless `-I` was supplied. - **`INFO`** -- printed, counted separately, never gates. - **`IGNORE`** -- the quietest non-gating verdict. On the full and API scans it does more than reclassify: an **active** rule marked `IGNORE` is turned off in the policy before the scan starts and never runs, which is why those scripts advertise it as a way to shorten a scan. A **passive** rule marked `IGNORE` still runs and still alerts; only its findings are re-bucketed. - **`PASS`** -- accepted by the parser but not a bucket. The same ordered list of level names serves two jobs: it validates this column *and* it backs the `-l` display-threshold option. There is no code path that sorts findings into a passing bucket from this file, so a rule marked `PASS` is not "guaranteed to pass"; use `IGNORE` when you mean that. ## The default is WARN, and that matters Everything the file omits is treated as `WARN`. Combined with `-g` writing every rule at `WARN`, this makes the out-of-the-box behaviour "any finding at all fails the stage with code `2`". That is a sensible default for a tool you have just adopted and a bad one for a pipeline nobody is watching, which is the whole reason the file exists. The `-i` flag inverts the default so unmentioned rules land in the informational bucket instead. That makes a run gate only on what you explicitly wrote down -- a deliberate, and reversible, narrowing. ## A working shape 1. Run once with `-g` to get the full list of rules at `WARN`. 2. Commit that file and edit it: move the rules you genuinely want blocking to `FAIL`, move the ones you have assessed and accepted to `IGNORE`, and leave the rest at `WARN` so new findings still surface. 3. Add a fourth column on the lines you changed, saying **why** -- it is printed next to the finding, so the next person reading the build log sees the reasoning without opening the file. 4. Re-run `-g` after a rule-set upgrade and diff it against your copy: rules that appear in the new file and not in yours are the ones that just started defaulting to `WARN`. That last step is the one teams skip. The file is keyed on rule ids, and a rule set that grows adds ids your file has never seen, all of which arrive at the default.
- What happens to a rule that is not mentioned in the file?It defaults to `WARN`, so it lands in the warning bucket and the run exits `2` if it alerts. The `-i` flag changes that default to `INFO`, which makes the run gate only on rules you wrote down explicitly. Either way, nothing is silently dropped.
- Why does the parser reject a file that looks correct?It counts tab characters and needs at least two per line. An editor that converts tabs to spaces, or a copy-paste through a web page, produces a file that looks right and fails to load -- the script reports the offending line and the run ends on `3`.
- Can one file be shared across several pipelines?Yes -- `-u` takes a URL and parses the identical format, so a governed copy can live in one place and be fetched by every run. The trade-off is that the scan now depends on that endpoint being reachable, and a fetch failure ends the run.
saying these in an interview costs you the question
- Thinks the file is space-separated or comma-separated
- Believes an unlisted rule is ignored by default
- Says column one accepts a rule name rather than its id
- Assumes PASS is the verdict for never blocking
- Thinks -g writes the file with sensible verdicts already chosen