How is the set of add-ons in a ZAP distribution or container image actually decided?
answer
- a list in the core repository, not the add-on one
- each entry pinned by hash
- a flag selects the smaller distribution
- images freeze the set at build time
- update moves versions, install adds capability
basics
~20 sA list in ZAP's core repository names every add-on folded into a main release, pinning each by download URL and SHA-256 hash; entries flagged core are the smaller core distribution. Container images then freeze that set at image-build time.
solid answer
~40 sThe core repository carries `main-add-ons.yml`, which names each add-on to include in a main release by id, release download URL and **SHA-256 hash**; the distribution build downloads them. An entry flagged `core: true` belongs to the smaller **core** distribution, and every entry without the flag is excluded from it — which is why a core install has no automation, no scripting, no browser crawler and no API-definition importers. The project's container images take a published release and run `zap.sh -cmd -silent -addonupdate`, copying the resulting archives into the install, so an image's add-on set is fixed when the **image** is built rather than when the container starts. `-addonupdate` upgrades what is already installed and adds nothing; adding requires `-addoninstall <id>` or `-addoninstallall`, and both need the marketplace.
code
yaml · 10 lines# main-add-ons.yml, in ZAP's CORE repository
addOns:
- id: "spider"
url: "<release download url>"
hash: "SHA-256:<digest>"
core: true # folded into the smaller core distribution
- id: "automation"
url: "<release download url>"
hash: "SHA-256:<digest>"
# no core flag -> excluded from the core distributiongo deeper
Know that the add-ons in your install came with the distribution or image you pulled, and that they did not arrive when the container started. Listing them is a one-argument check worth making a habit.
Explain the chain: a list in the core repository pins each add-on by hash, a flag selects the smaller core distribution, and the image build freezes the result. Be able to say why update and install are different arguments.
Use it to close out "works on my machine". Capture the add-on listing with every scan result so that a behavioural difference between two runs can be attributed to the set rather than argued about.
Decide where the set is defined for your organisation, and make that definition reviewable. If every team composes its own image, "we scan with ZAP" is not a statement anyone can compare across teams.
## The list, and which repository it lives in The file that decides a distribution's add-on set is `main-add-ons.yml`, and it lives in the **core** repository, not in the add-on repository. Each entry gives an add-on's id, the release download URL for a specific published build, and a **`SHA-256` hash** of that file. The distribution build fetches each one and folds it into the package, so the set is resolved at build time and pinned by content, not looked up at run time. Each entry may also carry `core: true`. That flag selects the smaller **core distribution**; the file's own comment states that add-ons in the core distribution have the property set and *all other add-ons are excluded*. A main release is the full set; a core release is the flagged subset. ## What the core distribution does and does not have The flagged subset is deliberately small. It carries the active and passive rule packages, the traditional spider, the passive engine, reports, the mandatory networking and call-home add-ons, and a handful of desktop conveniences. It does **not** carry the automation framework, the scripting extension or any script engine, the browser-driven crawlers, the authentication helper, the API-definition importers, the fuzzer or the alert filters. That matters immediately for a pipeline reader, because several of the things people describe as "how you run ZAP in CI" belong to add-ons a core install does not have. The symptoms are indirect: - a documented command-line argument comes back as an unsupported option, because the add-on that registers it is not there; - a plan names a job type that nothing claims, and fails on an unknown job rather than on a missing add-on; - an API component the client library knows about is simply not present in the running install; - a report template you expected is absent, because templates arrive with their add-on. None of those messages says "add-on missing", which is why the first diagnostic move is always to list what the install has. ## How a container image's set is composed The project's images do not assemble the add-on set from the YAML directly. They: 1. download and unpack a published release, which already carries that release's add-on set; 2. run `zap.sh -cmd -silent -addonupdate`, which brings the installed add-ons up to their current marketplace versions; 3. copy the resulting archives from the user home plugin directory into the installation directory. All three steps happen in the **image build**. Nothing re-fetches add-ons when a container starts. So an image tag pins a program version *and* an add-on set, and the two move only when someone rebuilds. ## Update is not install | argument | what it does | needs the marketplace | |---|---|---| | `-addonupdate` | upgrades add-ons already installed; adds none | yes | | `-addoninstall <id>` | installs one named add-on and its dependencies | yes | | `-addoninstallall` | installs everything available | yes | | `-addonlist` | prints name, id, version, status and description | no | The first row is the one that surprises people. Running an update in a container start-up script does not give you a capability the image never had; it only moves versions. Adding a capability means an install argument — with the marketplace egress and the `callhome` add-on that implies — or a new image. ## The pieces that make a set, in order 1. **The release** you started from determines the initial set. 2. **`main-add-ons.yml`** determined that release's set, and the `core: true` flag determined whether you have the full or the reduced one. 3. **Image-build steps** may update or add to it. 4. **Run-time arguments** may add to it, at the cost of an outbound dependency on every run. 5. **Load-time gates** may quietly reduce it again — an archive that fails its run requirements is installed and not running. Any answer that stops at step one is incomplete; any answer that stops at step four misses why a pinned image can still be missing something. ## Why this is the question a pipeline reader is actually asked "Where did these add-ons come from?" is the honest form of "why did the scan behave differently on the runner than on my laptop". The two installs are the same program at different add-on sets, and nothing in a scan's output says so. Recording the add-on listing alongside a scan result costs one argument and makes a run reproducible.
- Does running `-addonupdate` when a container starts give it capabilities the image lacked?No. That argument upgrades add-ons that are already installed and adds none, so a capability the image never carried stays absent. Adding one means an install argument, which needs marketplace egress on every run and makes the set differ between runs. The alternative — and usually the better one — is to bake it into the image.
- Why would the same plan or command work on a laptop and not on a CI runner?Almost always because the two installs carry different add-on sets. Job types, command-line arguments and API components are contributed by add-ons, so a smaller distribution rejects an argument as unsupported or fails a plan on an unknown job. Capture the add-on listing on both sides before assuming the difference is environmental.
- What does pinning by hash in that list actually buy?It makes the distribution build reproducible in its add-on set: the build fetches a specific published archive and verifies its content rather than resolving whatever the marketplace currently offers. It does not pin what happens afterwards — an image build step or a run-time install argument can still change the set.
saying these in an interview costs you the question
- Thinks a container re-fetches its add-ons when it starts.
- Says `-addonupdate` will install an add-on that is not there yet.
- Assumes every distribution of the program carries the same add-ons.
- Looks for the distribution add-on list in the add-on repository.
- Reports a scan result without recording which add-ons produced it.