Skip to content

PackageList

Entries for the tenant's package firewall allow list or deny list. Fields, YAML, HCL and CLI samples, and how apply treats it.

Checked against config-schemas@v1.15.0, terraform-provider-resolve@82cb23c, cli@v4.9.1

Entries for the tenant’s package firewall allow list or deny list. The tenant has one of each; every PackageList contributes its entries to one of them, and owns only the entries it declares. A deny entry always blocks, in every mode, ahead of every other check. An allow entry waives every policy block (thresholds, KEV, exploits, bad actors, end of life, cooldown, version lag) but never an exact-version malware match, a known-bad artifact hash or a malware scan verdict.

apiVersion vulnetix.com/v1
kind PackageList
Group Package firewall
Status Served. The config engine plans and applies it.
Objects per tenant many, keyed by metadata.name
Token and role An owner or admin session, or a vmt_ config management token with the owner or admin role that lists PackageList in its kinds. See Management tokens.
Applied after PackageFirewallPolicy (deleted before them)
CEL fields spec.entries[].when (package): see CEL rule expressions
Terraform resource vulnetix_package_list, imported by name (see Terraform and OpenTofu)
CLI vulnetix config apply, CLI v3.157.0 and later.
Pinned schema v1.15.0/PackageList.schema.json
Newest schema latest/PackageList.schema.json
First released in v1.1.0
Print the built-in copy vulnetix config schema PackageList

Minimal

Only the fields the kind requires. From examples/PackageList/minimal.yaml.

YAML

# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/PackageList.schema.json
apiVersion: vulnetix.com/v1
kind: PackageList
metadata:
  name: banned
spec:
  list: deny
  entries:
    - purl: pkg:npm/event-stream@3.3.6

HCL (resource vulnetix_package_list)

# Only the arguments the kind requires. From config-schemas examples/PackageList/minimal.yaml.

resource "vulnetix_package_list" "banned" {
  name = "banned"
  entries = [
    {
      purl = "pkg:npm/event-stream@3.3.6"
    },
  ]
  list = "deny"
}

CLI (applies it)

export VULNETIX_CONFIG_TOKEN=vmt_...   # a config management token
vulnetix config apply -f - --manager gitops:acme/platform --auto-approve <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/PackageList.schema.json
apiVersion: vulnetix.com/v1
kind: PackageList
metadata:
  name: banned
spec:
  list: deny
  entries:
    - purl: pkg:npm/event-stream@3.3.6
EOF

Advanced

Every field the kind supports, with a when expression where it takes one. From examples/PackageList/advanced.yaml.

YAML

# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/PackageList.schema.json
apiVersion: vulnetix.com/v1
kind: PackageList
metadata:
  name: first-party
  labels:
    team: platform-security
  annotations:
    ticket: https://jira.example.com/browse/SEC-2211
spec:
  list: allow
  entries:
    - purl: pkg:npm/@acme/*
      reason: Our own npm scope; releases must not wait out the cooldown.
      scope: full
      when: "!malware && !badActor"
    - purl: pkg:golang/github.com/acme/*
      reason: Our own Go modules.
    - purl: pkg:pypi/requests@2.32.3
      reason: CVSS on this release is a false positive for our use.
      when: cvss < 9.0 && !kev
    - purl: pkg:npm/left-pad
      scope: bad_actor
      reason: Maintainer attribution reviewed and judged a false positive.
---
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/PackageList.schema.json
apiVersion: vulnetix.com/v1
kind: PackageList
metadata:
  name: banned
spec:
  list: deny
  entries:
    - purl: pkg:npm/event-stream@3.3.6
      reason: Compromised release.
      scope: full
    - purl: pkg:npm/ua-parser-js
      reason: Hold back fresh releases after the 2021 hijack.
      when: ageDays < 3 || versionLag > 5

HCL (resource vulnetix_package_list)

# Every argument the kind supports. From config-schemas examples/PackageList/advanced.yaml.

resource "vulnetix_package_list" "first_party" {
  name = "first-party"
  entries = [
    {
      purl   = "pkg:npm/@acme/*"
      reason = "Our own npm scope; releases must not wait out the cooldown."
      scope  = "full"
      when   = "!malware && !badActor"
    },
    {
      purl   = "pkg:golang/github.com/acme/*"
      reason = "Our own Go modules."
    },
    {
      purl   = "pkg:pypi/requests@2.32.3"
      reason = "CVSS on this release is a false positive for our use."
      when   = "cvss < 9.0 && !kev"
    },
    {
      purl   = "pkg:npm/left-pad"
      reason = "Maintainer attribution reviewed and judged a false positive."
      scope  = "bad_actor"
    },
  ]
  list = "allow"
  labels = {
    team = "platform-security"
  }
  annotations = {
    ticket = "https://jira.example.com/browse/SEC-2211"
  }
}

resource "vulnetix_package_list" "banned" {
  name = "banned"
  entries = [
    {
      purl   = "pkg:npm/event-stream@3.3.6"
      reason = "Compromised release."
      scope  = "full"
    },
    {
      purl   = "pkg:npm/ua-parser-js"
      reason = "Hold back fresh releases after the 2021 hijack."
      when   = "ageDays < 3 || versionLag > 5"
    },
  ]
  list = "deny"
}

CLI (applies it)

export VULNETIX_CONFIG_TOKEN=vmt_...   # a config management token
vulnetix config apply -f - --manager gitops:acme/platform --auto-approve <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/PackageList.schema.json
apiVersion: vulnetix.com/v1
kind: PackageList
metadata:
  name: first-party
  labels:
    team: platform-security
  annotations:
    ticket: https://jira.example.com/browse/SEC-2211
spec:
  list: allow
  entries:
    - purl: pkg:npm/@acme/*
      reason: Our own npm scope; releases must not wait out the cooldown.
      scope: full
      when: "!malware && !badActor"
    - purl: pkg:golang/github.com/acme/*
      reason: Our own Go modules.
    - purl: pkg:pypi/requests@2.32.3
      reason: CVSS on this release is a false positive for our use.
      when: cvss < 9.0 && !kev
    - purl: pkg:npm/left-pad
      scope: bad_actor
      reason: Maintainer attribution reviewed and judged a false positive.
---
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/PackageList.schema.json
apiVersion: vulnetix.com/v1
kind: PackageList
metadata:
  name: banned
spec:
  list: deny
  entries:
    - purl: pkg:npm/event-stream@3.3.6
      reason: Compromised release.
      scope: full
    - purl: pkg:npm/ua-parser-js
      reason: Hold back fresh releases after the 2021 hijack.
      when: ageDays < 3 || versionLag > 5
EOF

Fields

Paths use dots for nesting and [] for the items of a list. Required means required whenever the parent object is present. A default is what the server uses when the field is left out.

Field Type Required Default Allowed values Description
apiVersion string yes exactly vulnetix.com/v1 The document format version. Every kind in this release is vulnetix.com/v1.
kind string yes exactly PackageList Always PackageList.
metadata object yes no other keys
metadata.name string yes pattern ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ The object’s name, unique per kind within a tenant. It is the natural key: plan, apply, export and the Terraform provider all address an object by kind and name.
metadata.org string no format uuid The tenant (organization UUID) the document belongs to. When set, plan and apply refuse to run against any other tenant.
metadata.labels object no map of string to string (length 0 to 256); keys match ^[a-z0-9]([a-z0-9._/-]{0,61}[a-z0-9])?$ Free key/value labels. Stored with the object, never interpreted by the server.
metadata.annotations object no map of string to string (length 0 to 4096) Free key/value notes for people and tools, such as a ticket link.
spec object yes no other keys
spec.list string yes allow, deny Which list the entries go on.
spec.entries array of object yes
spec.entries[].purl string yes pattern ^pkg:(golang|npm|pypi|cargo|gem|hex|pub|maven|nuget|composer|conan|conda|cran|julia|oci|deb|rpm|apk)/[^?#*\s]+$, or pattern ^pkg:golang/[^/@?#*\s]+/[^@?#*\s]+/\*$, or pattern ^pkg:(npm|pypi|cargo|gem|hex|pub|maven|nuget|composer|conan|conda|cran|julia|oci|deb|rpm|apk)/@?[^@?#*\s]+/\*$ The package, as a purl without qualifiers or subpath. With a version (pkg:npm/lodash@4.17.21) the entry covers that version, and wins over a whole-package entry for it; without one it covers every version. On an allow list a purl whose name is * covers every package in a namespace, matched at a separator, so @acme/* never covers @acme-evil/x: pkg:npm/@acme/* (npm @acme/), pkg:golang/github.com/acme/ (Go github.com/acme/, which needs a host and an owner), pkg:maven/com.acme/ (Maven com.acme:*). A namespace entry has no version. The purl type maps to the firewall ecosystem: golang to go, gem to gem, deb to debian, apk to alpine, the rest to the same name.
spec.entries[].reason string no Why the decision was made, for the people who review the list.
spec.entries[].scope string no full full, bad_actor What an allow entry waives. full: every policy block. bad_actor: only a bad-actor attribution, for an operator who judged that attribution a false positive. A deny entry is always full.
spec.entries[].when string no length 1 to 4096 A CEL condition over the package variables (purl, ecosystem, name, version, published, ageDays, versionLag, malware, cvss, epss, cess, kev, eol, exploitMaturity, badActor, now). The entry applies only to versions for which it is true: a deny entry blocks only those versions, an allow entry waives only for them. Left out, the entry applies to every version it names. An entry whose condition fails to evaluate is skipped and logged: a deny entry does not block and an allow entry does not waive.

CEL variables

spec.entries[].when is a CEL expression in the package context, returning bool. It is evaluated by the package firewall proxy, for each requested version, in evaluate(). The entry is skipped and the proxy logs it. See where each expression is evaluated. The functions, limits and error codes are on CEL rule expressions.

Variable Type Bound Description
purl string 2048 chars Package URL of the requested version.
ecosystem string 64 chars Package ecosystem, such as npm, pypi, golang, maven.
name string 512 chars Package name as the ecosystem writes it: @acme/tool, github.com/acme/tool, com.acme:tool.
version string 256 chars Requested version.
published timestamp When the version was published. The zero timestamp when unknown.
ageDays int Derived. Whole days from published to now. -1 when the publish time is unknown, so a cooldown rule never reads an unknown age as new.
versionLag int How many releases are newer than this version. 0 for the newest, or when the lag is unknown.
malware bool The version is known malware.
cvss double Highest CVSS base score across the version’s advisories.
epss double Highest EPSS probability across the version’s advisories.
cess double Highest Coalition ESS score across the version’s advisories.
kev bool An advisory for the version is in a known-exploited catalogue.
eol bool The version is end of life.
exploitMaturity string 64 chars poc, active, weaponized, or empty when no exploit is known.
badActor bool The publisher is a known bad actor.
now timestamp The time of evaluation. Callers may fix it; otherwise it is the clock when Eval runs.

Applying this kind

  • Command. vulnetix config apply -f <file>; the CLI line above says from which release. Plan first with vulnetix config plan: it shows each object as create, update, delete or no change, with a planHash that apply then holds to. Apply writes in one transaction.
  • Manager. Each object records the manager that applied it (terraform, console or gitops:<repo>). --prune deletes only objects its own manager owns. See The manager and the config engine.
  • Order. Applied after PackageFirewallPolicy, so a document that refers to one by metadata.name can be in the same apply. Deleted before them.
  • Status. Applied, Unchanged or Deleted, with no other status fields. The phases the engine reports are explained under status phases.

How apply treats it

  • A PackageList owns only the entries it declares. Entries made in the console, and entries another PackageList declares, are never changed or pruned by it.
  • Entries are compared one by one, keyed by ecosystem, package name and version as the purl maps to them.
  • Every write appends a package firewall list audit row in the same transaction, with the same actions the console records (create, update, move, activate, delete). The actor is the applying principal and the manager.
  • Applied after the PackageFirewallPolicy.

Terraform and OpenTofu

The resource is vulnetix_package_list in the vulnetix/resolve provider. Its arguments are the spec in snake case, beside name, labels and annotations from metadata. The Minimal and Advanced HCL are above. The provider’s own reference is vulnetix_package_list.

Import an object that already exists by its name:

# Import an existing PackageList by its name (metadata.name).
terraform import vulnetix_package_list.banned banned

Install, authentication and how state is read: Terraform and OpenTofu.

More examples

examples/PackageList/allow-first-party.yaml from Vulnetix/config-schemas:

# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/PackageList.schema.json
apiVersion: vulnetix.com/v1
kind: PackageList
metadata:
  name: first-party
spec:
  list: allow
  entries:
    - purl: pkg:npm/@acme/*
      reason: Our own npm scope; releases must not wait out the cooldown.
    - purl: pkg:golang/github.com/acme/*
      reason: Our own Go modules.
    - purl: pkg:maven/com.acme/*
      reason: Our own Maven group.
    - purl: pkg:pypi/requests@2.32.3
      reason: CVSS on this release is a false positive for our use.
    - purl: pkg:npm/left-pad
      scope: bad_actor
      reason: Maintainer attribution reviewed and judged a false positive.

examples/PackageList/deny.yaml from Vulnetix/config-schemas:

# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/PackageList.schema.json
apiVersion: vulnetix.com/v1
kind: PackageList
metadata:
  name: banned
spec:
  list: deny
  entries:
    - purl: pkg:npm/event-stream@3.3.6
      reason: Compromised release.
    - purl: pkg:pypi/colourama
      reason: Typosquat of colorama.

Check a file with vulnetix config validate -f <file>. See Validate documents. In an editor, start the file with the schema comment.

Edit this pageSources: config-schemas/schemas/PackageList.schema.json, config-schemas/schemas/common.schema.json, config-schemas/examples/PackageList/minimal.yaml, config-schemas/examples/PackageList/advanced.yaml, config-schemas/examples/PackageList/allow-first-party.yaml, config-schemas/examples/PackageList/deny.yaml, config-schemas/cel/variables.go, terraform-provider-resolve/examples/resources/vulnetix_package_list/minimal.tf, terraform-provider-resolve/examples/resources/vulnetix_package_list/advanced.tf, vdb-site/docs/platform-iac-engine.md, vdb-site/api/internal/handler/config_engine_kinds.go, vdb-site/api/internal/config/packagelist.go, vdb-site/api/internal/config/purl.go
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.