skip to content

In ZAP's automation framework, what does a plan file contain and what decides the order the work runs in?

level: middleimportance: must knowfreq 60%

answer

  1. two top-level keys, one file
  2. environment first, then work
  3. the list is the sequence
  4. env plus jobs, top to bottom

basics

~20 s

A ZAP automation plan is a YAML file with two parts: env, which names the environment the run acts on, and jobs, an ordered list of units of work. Jobs run top to bottom, in the order written.

solid answer

~40 s

The `automation` add-on reads a YAML plan with two top-level keys. `env` is mandatory and describes what the run acts on: contexts, plus `vars`, `configs` and `parameters` that govern the run as a whole. `jobs` is an ordered list; each entry carries a `type` naming what to do, optional `name`, `enabled`, `alwaysRun`, a `parameters` block and a `tests` block. There is no dependency graph and no job categories at run time: the list is executed top to bottom exactly as written, so putting a job that waits for passive scanning before anything has been crawled simply wastes the wait. `-autorun` runs the file, and the sequence performed is the sequence written there.

code

yaml · 14 lines
yaml
env:
  contexts:
    - name: target
      urls:
        - https://example.com/
  parameters:
    failOnError: true

jobs:
  - type: spider
    parameters:
      context: target
  - type: passiveScan-wait
  - type: report

go deeper

for a junior

Recall the two halves of the file: env describes what is being tested, jobs lists what to do. Be able to point at where the target URL goes and where a job's type goes.

for a middle

Explain that job order is file order, that env is mandatory while jobs is not, and what each of type, name, enabled and alwaysRun does on a job entry.

for a senior

Show that you treat the plan as reviewable configuration: you would catch an empty job list, an ordering that wastes a wait, and a disabled job still shaping the run's outcome, before any of them reached a pipeline.

for a principal

Own the argument for declaring a run in a file at all — one reviewable artefact per pipeline, diffable and portable — and say what has to sit outside it, such as credentials and the decision about which environment may be attacked.

## The shape of the file A ZAP automation plan is one YAML document read by the **`automation` add-on**. It has two top-level keys and the add-on reads only those two: - **`env`** — the environment. It is **mandatory**: if the key is absent, the plan records `Missing environment.` as an error. - **`jobs`** — an ordered list of the units of work to perform. Anything else you write at the top level is **silently ignored** — the loader reaches for `env` and `jobs` by name and never enumerates the rest of the document. That is worth knowing because the rule is the opposite one level down: an element inside `env` that the framework does not recognise is reported as an **error**, not ignored. ## What `env` carries `env` describes what the jobs act on and how the plan as a whole behaves: - **`contexts`** — the named targets the jobs refer to by name. At least one context, with at least one URL, is required; an empty environment is an error. - **`vars`** — plan-level variables, substituted into URLs and many parameters. - **`configs`** — generic configuration keys applied to the running program before the first job, the same keys the `-config` command-line option takes. - **`parameters`** — the run-wide switches: `failOnError`, `failOnWarning`, `continueOnFailure`, `progressToStdout` and `maxDuration`. ## What a job entry carries Each element of `jobs` is a map. Only `type` is required: | key | what it does | |---|---| | `type` | names the job; looked up in a registry the installed add-ons populate | | `name` | a label used in output and in job tests; defaults to the type | | `enabled` | when `false`, the job is skipped at run time (but still verified at load) | | `alwaysRun` | when `true`, the job still runs after the plan has decided to stop early | | `parameters` | the job's own settings; unrecognised names are reported | | `tests` | job outcome tests — `alert`, `stats`, `url` or `monitor` | ## Order is the order you wrote The single most common misreading is that the framework sorts the work for you. It does not. The list is executed **top to bottom exactly as it appears in the file**. The add-on does maintain a notion of job category — exploration before attack before reporting — but that ordering is used to lay out the templates the `-autogen*` options write and to place jobs added through the desktop, **not** to reorder a plan you hand it. So: 1. A job that waits for passive scanning to drain, placed before anything has crawled the site, waits for nothing. 2. A job that configures how findings are filtered, placed after the scanning jobs, does not reach the findings those jobs already raised. 3. A job that sets the exit value, placed anywhere but last, reports on a run that has not finished. The reader's job is to write the sequence, not to trust one. ## The two silences that cost pipelines Two plan shapes load cleanly, run, and tell you nothing is wrong: - **`jobs` absent or empty.** The loader takes a missing job list as "nothing to do" and records no error at all. The environment is created, no work happens, and the run ends clean. A plan that lost its job list in a bad merge is a **green pipeline that scanned nothing**. - **A disabled job.** `enabled: false` skips the work but not the load-time verification of that job, so a disabled job can still contribute a warning to the run's outcome. Because of the first, a plan is worth asserting on rather than trusting: either a job outcome test that requires evidence of work, or a pipeline step that reads the run's own output. ## Running it The plan is handed to the program with **`-autorun <source>`**, where the source is a file path or an `http`/`https` URL. **`-autocheck <source>`** loads and validates the same file without running any of it. The `-autogenmin` and `-autogenmax` options write a starting template — composed from the job types the running build actually has — and `-autogenconf` writes one reflecting the current configuration. ## Why the shape matters The plan is the whole interface. There is no hidden default sequence and no implicit target: the run is the ordered list the file names, against the environment the file names. What the file cannot settle is what the build under it makes available, which is a separate problem. That makes a plan reviewable in a pull request the way a build file is — and it makes every silence in it, including an empty job list, your responsibility rather than the tool's.

  • Does the framework reorder the jobs it is given?
    No. The job list is executed in file order. The add-on's notion of job category is used when it writes a template for you and when a job is added through the desktop, but a plan you author is run exactly as written — including an order that makes no sense.
  • What happens if the `jobs` key is missing entirely?
    Nothing is recorded as wrong. The loader treats an absent job list as nothing to do, the environment is still created, and the run ends with a clean exit value. A plan that lost its jobs still reports success, which is why a plan deserves an assertion that work actually happened.
  • Where do relative file paths inside a plan resolve from?
    Against the directory holding the plan file, which keeps a plan portable between a workstation and a container. A plan fetched from a URL has no file on disk, so its relative paths fall back to the process working directory instead.

saying these in an interview costs you the question

  • Thinks the framework sorts jobs into a sensible order
  • Assumes an empty job list is reported as an error
  • Calls env optional because jobs name their own targets
  • Reads the job list as a set of options rather than a sequence
  • Expects an unknown top-level key to be rejected