Rules and selectors
Field-level reference for firewall rules, selectors, selector functions, effects, and exceptions.
A firewall's policy consists of rules and exceptions inside its configuration. This page documents every field. For the mental model, see Rule evaluation.
Rule
{
"id": "delay-new-versions",
"disabled": false,
"executionPhase": "versions",
"selector": { "maxAgeHours": 168 },
"ruleEffect": { "block": true, "log": true },
"description": "Block versions younger than 7 days"
}| Field | Type | Description |
|---|---|---|
id | string | Unique within the firewall. Referenced by exceptions and log entries |
disabled | boolean | Skip the rule without deleting it. Default false |
executionPhase | string | versions, download, or upload. A versions rule filters metadata responses and is also enforced when a client fetches a matching version directly. The dashboard rule form labels versions as filter versions |
selector | object | Which packages the rule applies to. See below |
ruleEffect | object | What happens on match. See below |
description | string | Free text, shown in the dashboard and useful in logs |
Evaluation order
Rules are not evaluated in configuration order. A request is evaluated against the cheaper rules first, so it pays for an expensive check only once every cheaper rule has allowed it. Rules of equal cost keep their configuration order, inherited rules before the firewall's own.
The first matching rule with block: true ends evaluation. Two things follow. The block a client sees, and the rule recorded in the log entry, is not necessarily the first rule you configured. And rules after it are never evaluated, never log, and cost the request nothing: a package stopped by a maxAgeHours rule is never scanned for malware.
Treat the order as an implementation detail that can change. If you need a rule to be evaluated regardless of what else matches, do not rely on ordering; give it a selector that cannot overlap with the others.
Selector
All set fields must match (AND). Empty fields match everything.
| Field | Type | Description |
|---|---|---|
upstreamId | string | Match packages served from this upstream |
internal | string | "internal", "external", or empty for any. Refers to whether the package resolves from an upstream marked internal |
packageName | string | Exact name, or one wildcard: prefix*, *suffix, or * |
version | string | Exact version, same wildcard support. Compared as text, never parsed |
versionRange | string | Version range in the ecosystem's own notation, compared by version semantics. See Version ranges |
maxAgeHours | number | Whole hours. Matches versions published more recently than this. 168 is 7 days |
function | object | Named selector function with options. See Selector functions |
Wildcards
packageName and version accept at most one *, at the start or the end:
| Pattern | Matches |
|---|---|
@acme/* | Everything in the @acme scope |
*-beta | Names ending in -beta |
* | Everything |
lodash | Exactly lodash |
Package name matching
packageName is matched in the naming form the ecosystem itself considers canonical, so a selector written the way the package appears on the registry works:
| Ecosystem | Matching |
|---|---|
| NuGet | Case-insensitive. Newtonsoft.Json and newtonsoft.json are the same package |
| PyPI | Case-insensitive, and -, _, . are interchangeable (PEP 503). zope.interface, zope_interface, and Zope.Interface all select zope-interface |
| npm, Maven, Go, conda | Exact, case-sensitive. React does not select react, and a Maven coordinate or Go module path must be written exactly |
NuGet and PyPI have their own naming rules, and the firewall follows them. Everywhere else the name is matched as written, so a rule selects only the package it names.
Write the name the way the registry shows it. Most npm names are lowercase, but older ones such as JSONStream are not, and a rule written jsonstream does not match.
Wildcards are normalized the same way, so a NuGet selector Microsoft.* matches microsoft.extensions.logging. version is always compared exactly and is never normalized.
Exceptions use the same matching, which matters most there: an exception meant to unblock a package has to select it to take effect.
Version ranges
version and versionRange answer different questions. version compares text, so 1.* selects anything whose version string starts with 1.. versionRange parses both sides and compares them as versions, so >=1.2.0 <2.0.0 knows that 1.10.0 is newer than 1.9.0. Use version to match a naming shape, versionRange to match a real interval.
The two are independent fields. Set both and a version has to satisfy both.
Each ecosystem keeps its own range notation:
| Ecosystem | Notation | Examples |
|---|---|---|
| npm | semver ranges | ^1.2.0, ~1.2.3, >=1.2.0 <2.0.0, 1.x, 0.0.1 - 0.0.3 || >2.0.1 |
| Go | semver ranges. A leading v on the package version is accepted, so v1.5.0 matches >=1.2.0 <2.0.0 | >=1.2.0 <2.0.0 |
| NuGet | semver ranges, not NuGet interval notation | >=1.0.0 <2.0.0 |
| Maven | interval notation | [1.0,2.0), [1.0,2.0] |
| PyPI | PEP 440 specifiers | >=1.0,<2.0, ~=1.4.2 |
| conda | not supported. The dashboard hides the field, and the API rejects a range on a conda firewall |
Semver ranges support || for alternatives, X - Y for an inclusive span, x, X, or * as a wildcard component, and the operators =, !=, >, <, >=, <=, ~, ^. As in npm itself, a prerelease only matches a range that mentions a prerelease: 1.2.0-beta.1 does not satisfy ^1.2.0.
NuGet ranges go through the semver parser, deliberately, so that range syntax is the same across ecosystems that can share it. NuGet's own bracket intervals are therefore not accepted, and [1.0.0,2.0.0) is rejected when you save the rule. NuGet versions keep their own rules, so a four-part version such as 1.5.0.3 still parses and compares correctly.
Saving a rule whose range the ecosystem cannot parse fails with an error. At request time, a package version the ecosystem cannot parse does not match the range.
Selector functions
| Function | Phases | Ecosystems | Options |
|---|---|---|---|
vulnerabilities | download | all except Conda | maxCvssScore (0 to 10), maxEpssScore (0 to 1) |
malware | download, upload | all | minimumConfidence (known_malware/suspicious/weak_indicator)effort (known/deep) |
install-scripts | download, upload | npm, PyPI | none |
deprecated | versions, download | npm, PyPI, NuGet | none |
unlisted | versions, download | NuGet | none |
secrets | upload | all | ignoredFiles, excludeTestFiles |
license | download | all; Conda supports unknown only | licenseSet, mode (deny/allow), unknown |
trust-downgrade | versions | npm | none |
Full semantics, options, and dashboard availability per function: Selector functions.
The API rejects rules and exceptions whose function does not support the firewall's ecosystem. Full config imports and rollbacks apply the same validation.
Effect
| Field | Type | Description |
|---|---|---|
block | boolean | Stop the request |
log | boolean | Write a firewall log entry on every match |
{ "block": false, "log": true } is a dry-run rule, the standard way to trial a policy.
Exceptions
An exception waives one rule for requests matching its own selector, with an expiry and a reason. Field-level reference: Exceptions.
Related
- Concept: Rule evaluation
- Reference: Selector functions, Exceptions, Firewall config
- How-to: Delay new versions, Block vulnerable packages, Manage exceptions
Permissions
The full permission catalog, the built-in team permission sets, and the defaults applied to new firewalls.
Selector functions
Reference for the named selector functions, vulnerabilities, malware, install-scripts, deprecated, unlisted, secrets, license, trust-downgrade, with their phases, ecosystems, and options.