In a ZAP packaged-scan rule file, how do you pin one noisy rule to never fail a run while another always does?
answer
- two verdict words at opposite ends
- one of the five words is a decoy
- ignoring an active rule also switches it off
- the warning flag does not cover failures
basics
~20 sGive the noisy rule IGNORE and the blocking one FAIL, on their own tab-separated lines. IGNORE keeps the finding visible but out of the gating buckets; FAIL sends the run to exit 1 whenever that rule alerts.
solid answer
~50 sTwo lines in the file passed with `-c`: the noisy rule's id followed by `IGNORE`, the blocking rule's id followed by `FAIL`. `IGNORE` still prints the finding, in its own count, but it never reaches the buckets the exit code is derived from; `FAIL` exits `1` the moment that rule alerts. Three things bite. **`PASS` is not the never-fail verdict** -- the parser accepts the word because the same ordered list of level names also backs the `-l` display option, but no code path sorts findings into a passing bucket from this file. **`IGNORE` means two different things**: on the full and API scans an *active* rule marked `IGNORE` is switched off before the scan starts and never runs, while a *passive* one still runs and is only reclassified. And **`-I` does not protect the failing side** -- it removes the exit-`2` branch only, so the `FAIL` line still exits `1`.
code
bash · 9 linescat > rules.conf <<'EOF'
# columns are TAB separated; the fourth column is your own note
<noisy-rule-id> IGNORE (rule name) assessed and accepted
<blocking-rule-id> FAIL (rule name) must not regress
# accepted by the parser, but there is no passing bucket to land in:
# dropped from every count on one path, re-read as a warning on the other
<some-rule-id> PASS (rule name) do not write this
EOFgo deeper
Recall the two words at the ends of the scale: IGNORE for a rule that must never block, FAIL for one that always must. Both go in the verdict column of a tab-separated line keyed by rule id.
Explain why PASS is accepted and still wrong -- the level names also back the display option -- and that ignoring an active rule on a full scan switches it off rather than merely reclassifying it.
Demonstrate that you verify a FAIL line against a run where the rule actually fired, and that you know which findings are discarded before verdicts apply. Say how the file survives a rule-set upgrade.
Own which rules your organisation is willing to have block a release, and how an accepted finding gets recorded so the reason outlives the person who wrote the line. That is a policy question the file only records.
## The two lines Everything a packaged ZAP scan gates on comes out of one tab-separated file, read with `-c` (from disk) or `-u` (over HTTP). Each line is a rule id, a verdict, and a note. The two verdicts that sit at the ends of the scale are: - **`IGNORE`** -- the findings are collected, printed in their own count, and never reach a bucket the exit code is derived from. - **`FAIL`** -- the findings go in the failing bucket, and a non-empty failing bucket is the first branch the run tests, so it exits `1`. That is the whole answer to the question as asked. What makes this a real interview question is the set of near-misses around it. ## Trap one: PASS looks like the never-fail verdict and is not The parser accepts five level words in that column, and `PASS` is one of them. It is tempting to read that as "this rule is guaranteed to pass", and it is not what happens. The list of level names does double duty. It validates this column, **and** it backs the `-l` option, which sets the lowest level the run will print -- and printing needs a name for the rules that raised nothing. So `PASS` is in the list because of the display option, not because there is a passing bucket you can put a rule into. The consequence is worse than a no-op, because it differs by execution path: | path | what a `PASS` line does | |---|---| | the older daemon-and-API path | the rule matches none of the four bucket tests, so its findings vanish from every count -- not printed, not gated, not visible | | `zap-baseline.py`'s automation-framework path | the summary step recognises only `IGNORE`, `INFO` and `FAIL` and defaults everything else to `WARN`, so the same line can exit `2` | One line, two opposite outcomes, no error either way. When you mean "this must never fail the run", write `IGNORE`. ## Trap two: IGNORE means two different things On the baseline scan, which runs passive rules only, `IGNORE` is purely a reclassification: the rule runs, raises what it raises, and the findings are counted separately. On the full and API scans there is a second effect. Before the scan starts, every **active** rule the file marks `IGNORE` has its threshold turned off in the scan policy, so it never runs at all. Those scripts advertise this as a way to shorten a scan, and their generated file says so in a comment. The consequences worth knowing: - an ignored active rule is reported as skipped rather than ignored, and it is excluded from the passing count as well -- it is neither a pass nor a finding; - an ignored **passive** rule is not switched off by the same line, because the mechanism only reaches active rules; - so the same word costs you scan time on one kind of rule and costs you nothing on the other. If your reason for ignoring a rule is "it is noisy", that is fine either way. If it is "it is expensive", only the active half will actually get faster. ## Trap three: -I does not cover the failing side `-I` is often reached for as the "do not block me" flag. It removes the exit-`2` branch and nothing else: 1. warnings are still raised, printed and counted; 2. a rule marked `FAIL` still exits `1`; 3. with warnings only and `-I` set, the run falls to the next branch -- `0` if at least one rule ran clean, `3` if none did. So `-I` and a `FAIL` line coexist perfectly: that is exactly the shape of "warnings are advisory, this one rule is not". ## Trap four: the failing side has holes of its own A rule pinned to `FAIL` fails the run when it alerts **and the finding survives collection**. Three things happen to findings before the verdicts are consulted: - a small built-in list of example and internal rule ids is dropped; - out-of-scope lines in the same file discard findings by rule and URL; - every finding the scan marked as informational risk is discarded unconditionally, whatever the file says. That last one is the surprise. A rule you pinned to `FAIL` that only ever raises informational-risk findings cannot fail the run, and nothing tells you so. Before relying on a `FAIL` line, confirm the rule has actually fired in a run and landed in the failing count. ## The shape that works 1. Start from a generated file, with every rule at `WARN`. 2. Move the rules you have assessed and accepted to `IGNORE`, with your reason in the fourth column so it reaches the build log. 3. Move the small set you genuinely want blocking to `FAIL`, and verify each one by looking at a run where it fired. 4. Leave the rest at `WARN`, and decide separately -- with `-I` -- whether warnings block. 5. Re-generate after a rule-set upgrade and diff, because new rule ids arrive at the default rather than at your intent. The file is a statement about **rules**, not about a single run. Written that way it survives upgrades; written as a list of things that annoyed someone once, it does not.
- Does -I let you skip the IGNORE line for the noisy rule?Only if you are happy for every unclassified rule to stop blocking too. `-I` removes the exit-`2` branch for the whole run, so it drops the warning bucket wholesale. An `IGNORE` line is per rule, keeps the finding visible in its own count, and leaves the rest of the warning bucket blocking.
- Why might a rule marked FAIL never fail the run?Because the finding may not survive collection. Findings the scan marked as informational risk are discarded before verdicts are consulted, as are those matching an out-of-scope pattern for that rule. Verify a `FAIL` line against a run where the rule actually fired and landed in the failing count.
- What is the difference between IGNORE and INFO for a rule you do not want blocking?Neither gates. `INFO` is the louder of the two: it prints at a higher display level and has its own count, so the finding stays in view. `IGNORE` is the quietest non-gating verdict, and on a full or API scan it additionally switches an active rule off before the scan runs.
saying these in an interview costs you the question
- Uses PASS as the verdict for a rule that must not block
- Thinks -I also stops a FAIL-marked rule failing the run
- Assumes IGNORE behaves identically for passive and active rules
- Believes a FAIL line guarantees the rule can fail the run
- Treats the file as per-run tuning rather than a durable statement