Execution phases
The three things a package manager asks a registry for, the firewall phase that acts on each, and how to pick the phase when you write a rule.
A package manager asks a registry for three things: which versions of a package exist, the file for one of those versions, and to accept a file it is publishing. A firewall answers all three, so all three are points where your rules can act.
Every rule runs in exactly one of them. The three execution phases are versions, download, and upload, which is the lowercase spelling the config, API, and CLI use, and what this page uses. The dashboard's Applies when (Execution Phase) picker spells them out instead, as "Resolving package versions", "Downloading a package", and "Uploading a package".
Each phase gives something up: a versions rule can still steer an install but only sees the registry's metadata, a download rule sees the actual package but can only allow or fail it. That tradeoff decides what happens to the developer's install when a rule matches, which is the choice worth settling before you write the rest of the rule.
A policy is not a rule. A policy is what your organization requires: no dependency younger than a week, no copyleft license in a shipped product, nothing carrying a known critical vulnerability. A rule is how one phase enforces part of that. One policy is usually several rules, sometimes across different phases, plus the exceptions you decide to grant. This page is about the phase a rule runs in; who sets the policy behind it is covered in Prevention model.
What the package manager asks for
| What the package manager needs | The request it makes | Phase | What a rule can do |
|---|---|---|---|
| To find out which versions exist | The package's version list | versions | Leave versions out of the answer |
| To get the file for one version | The package file | download | Serve it, or fail the request |
| To publish a file | The upload | upload | Accept the publish, or reject it |
The firewall answers each of these in the ecosystem's own protocol, so the package manager talks to what looks like a registry and gets answers shaped by your rules (see Client operations).
Which of the three you get depends on what the project already carries, not on the command someone typed. A project that declares ranges has versions to work out; a project with a lockfile, or with exact versions written down, has none, so installing it is downloads and nothing else. The phase follows the request, not the command.
The three execution phases
Versions phase
This phase is version resolution. A project depending on lodash ^4.17.0 has not named a version: the caret means any 4.x release from 4.17.0 upward, so the package manager has to find out what exists before it can choose. That question is what this phase answers, for the whole dependency tree, and a build installing from a lockfile never asks it. The rules still apply to those installs, enforced at download time instead; the callout below explains the difference.
A blocking rule here removes the matching versions from the metadata response before the package manager sees it, along with any tags pointing at them. The package manager then picks the newest version that is left and still satisfies the dependency range, so resolution lands on something that complies with your rules.
block versions younger than 7 days
A maturity rule like the one above, blocking versions younger than some age, can be declared in either phase, and the phase changes what happens when a dependency range would otherwise resolve to a young version.
Declared in download, it fails the install outright. In the example above, an install allowed to pick 4.17.23 would be rejected two days after that release went out, including for transitive dependencies nobody chose directly, and keep failing until the version ages past the window or someone grants an exception.
Declared in versions, the same install steers around it instead, the way the illustration shows: the package manager never sees 4.17.23 in the version list it gets back, so it resolves straight to 4.17.21 without ever asking for the younger one.
Either phase still stops a request that names the young version directly instead of resolving a range, such as a lockfile pinned to 4.17.23. There is no older version to fall back to there, so it fails the same way a download block would, enforced at download time (see the callout below).
It is also how you control which copy of a package wins when upstreams overlap, say a patched internal build alongside the public release. The package manager picks from the combined list, and a versions rule decides what goes into it.
Two limits are worth knowing:
- There has to be another version to pick. An exact pin of a removed version, or a tag pointing at one, has nothing to fall back to and fails.
- It only sees what the registry knows. A
versionsrule can use the package name, the upstream, registry status such as deprecation, and the publish date (maxAgeHours). Anything that needs the package file itself is out of reach.
Do exact pins or lockfiles bypass the filter?
No, but they fail differently. An exact pin (react@18.2.0) is checked against the filtered list, so the package manager reports that version as not found. A request that skips the list entirely and goes straight for the package file, such as a tarball URL taken from a lockfile, is checked against the versions rules at download time instead. That one fails with the same explicit error a download block gives: the package, the version, and a request ID, recorded in the firewall log as a download entry.
Either way, a version a versions rule removed cannot get in. What differs is the error the developer sees. "This version does not exist" when the package manager used the version list, an explicit block when it went straight for the file. Rules that should always fail loudly still belong in download, alone or in addition.
Download phase
This phase is downloading a package. Every package that reaches a build is fetched one file at a time, whether its version was resolved a moment earlier or written into a lockfile months ago. The firewall has that file in hand when it decides.
A blocking rule here fails the request. The package manager has already committed to a version, so there is nothing for it to fall back to. download rules run once per package fetched, with the package file available to read, which is what makes content checks possible.
What this phase gives you is coverage that resolution cannot provide. Every package file entering a build passes through it, including the dependencies several levels down that no developer picked. Nothing gets in by being requested a different way, which is what makes a download rule the one you can state as a guarantee, to an auditor or to a customer.
Use it when a different version of the same package would not make the problem acceptable: a malware verdict, a vulnerability threshold, a package that must never be fetched from outside your organization.
A block answers the request with the firewall's error instead of the package file. How much of that error a developer sees depends on the package manager, so each ecosystem page shows what its clients print. The reason lives in the firewall log either way: the block carries a request ID, and the entry it points at names the rule that fired, the package, and the version. See Investigate a blocked install.
Upload phase
This phase is publishing. When a developer or a pipeline pushes a package to your publish target, it goes through the firewall on the way. It is the only phase that looks at packages leaving your organization.
upload rules evaluate publishes before they reach the publish target. A blocked publish is never forwarded, and the rejection names the package, the version, and a request ID. Because this is where you can still stop something before it leaves, secrets scanning runs here. Malware and install-time code execution checks also run here for ecosystems with publish support, so what you publish is held to the standard you apply to what you consume.
Comparing versions and download
The two phases that act on packages coming in are the pair you choose between when you write a rule.
versions | download | |
|---|---|---|
| Runs when | The package manager asks which versions exist | The package manager fetches one package file |
| Can use | Name, version, upstream, publish date, registry status such as deprecation | All of that, and the package contents |
| On a match | The version is left out of the answer | The request fails |
| The developer sees | A successful install, possibly on an older version | A failed install, with a block from the firewall behind it |
Which checks run in which phase
The phase also decides which selector functions a rule can use, and that often decides the phase for you. Check the selector function matrix before writing a rule. The dashboard only offers compatible combinations, and the API rejects a rule when its selector function cannot evaluate in the selected phase.
Two consequences come up often. Vulnerability and license checks are offered in download, so rules built on them fail the install rather than steering it. Package age, deprecation, unlisted status, publishing trust, and Composer plugin metadata can be checked in versions and steer resolution instead.
What each phase records
- A
versionsrule withlog: truerecords the versions it removed, so filtering stays visible in the firewall log even though the install succeeded. - Webhook events come from
downloadanduploaddecisions. Metadata filtering never produces events, however many versions it removes. Aversionsrule that blocks an artifact request is adownloaddecision, so that block does produce one.
Choosing a phase for a rule
Start from what you want to enforce rather than from the phase. Two questions settle it.
- Would another version of this package be acceptable? If yes,
versionsenforces it and lets the install continue on a version that complies. If no version of it may enter,downloadis the phase that says so. - Does the check need to read the package file? If it does, the phase is decided for you:
downloadfor what comes in,uploadfor what you publish. The selector function matrix is the list.
Many requirements want both phases, and the two rule sets are separate gates, so a version that survives filtering is still evaluated on download. A common baseline is a maxAgeHours window in versions to delay fresh releases without breaking installs, plus malware and vulnerabilities rules in download as hard stops. Pairing the same selector across both phases works too, when you want resolution steered away from something and a hard stop if a lockfile asks for it anyway.
| What you want to enforce | Phase | What the developer sees |
|---|---|---|
| An acceptable version exists, so send installs to it instead (age windows, deprecated packages) | versions | The install succeeds on an older version. Nothing fails |
| Installs must only ever choose from versions you control (overlapping upstreams, internal builds) | versions | The package manager only ever sees the versions you allow |
| No matching version may enter, whatever that breaks (malware, vulnerabilities) | download | The install fails, including when the package is a dependency of a dependency |
| Control what gets published (secrets) | upload | The publish is rejected before it reaches the upstream |
Starting points in the dashboard
You do not have to pick a phase cold. Add Rule opens with a short list of common goals, each one a policy people usually want, and choosing one starts the rule in the phase that policy needs.
| The goal you pick | Where it starts the rule |
|---|---|
| Let new releases mature | versions, with a 7-day window already filled in |
| Hide packages or versions | versions |
| Block packages from being downloaded | download |
| Check packages you publish | upload, offered for ecosystems that have a publish path |
| Start from a blank rule | Nothing preselected |
What you get is a starting point, not a finished rule. The next screen is the normal rule form, where you add the selector that says which packages to match and the selector function that says what to check, and where every seeded value stays editable, phase included.
The how-to guides each work one policy through end to end and state the phase they use and why.
Related
- Concept: Rule evaluation, Exception model
- How-to: Delay new versions (
versions), Block malware (download), Scan for secrets on publish (upload), Investigate a blocked install - Reference: Client operations, Rules and selectors, Selector functions