LicenseExceptions
Recorded, attributed exceptions to the licence policy: a licence exempted everywhere (blanket) or one package exempted, each with who approved it, why. Fields, YAML, HCL and CLI samples, and how apply treats it.
Recorded, attributed exceptions to the licence policy: a licence exempted everywhere (blanket) or one package exempted, each with who approved it, why, and until when. An exempted finding is kept and badged, never dropped, and an expired exception stops applying and says so; the expiry date is inclusive. Two forms are valid. The repository file .vulnetix/license-exceptions.yaml, read by vulnetix license and scan –evaluate-licenses, keeps blanket and packages at the top level with no metadata. The config form puts them under spec, with metadata. The server does not store exceptions yet: the CLI validates the document and plan notes it, but apply sends nothing.
blanket exceptions are checked first and the first unexpired match wins; packages are checked after them. See Licence policy and Licence evaluation.
apiVersion |
vulnetix.com/v1 |
kind |
LicenseExceptions |
| Group | Scanners and gates |
| Status | Validate only. The server stores nothing for it: validate and plan check a document, and apply sends nothing. |
| Objects per tenant | one (metadata.name: default) |
| Token and role | None. The server stores nothing for this kind; validating needs no credential. |
| Terraform resource | None: the server stores nothing for this kind |
| CLI | vulnetix config validate reads it (CLI v3.165.1 and later); plan and apply note it and send nothing. |
| Pinned schema | v1.15.0/LicenseExceptions.schema.json |
| Newest schema | latest/LicenseExceptions.schema.json |
| First released in | v1.3.0 |
| Print the built-in copy | vulnetix config schema LicenseExceptions |
Minimal
Only the fields the kind requires. From examples/LicenseExceptions/minimal.yaml.
YAML
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/LicenseExceptions.schema.json
apiVersion: vulnetix.com/v1
kind: LicenseExceptions
metadata:
name: default
spec: {}
HCL
There is no Terraform resource. The server stores nothing for this kind, so there is nothing for Terraform to manage. The file stays in the repository; see Which files are Platform IaC documents.
CLI (validates it)
vulnetix config validate -f - <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/LicenseExceptions.schema.json
apiVersion: vulnetix.com/v1
kind: LicenseExceptions
metadata:
name: default
spec: {}
EOF
Advanced
Every field the kind supports, with a when expression where it takes one. From examples/LicenseExceptions/advanced.yaml.
YAML
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/LicenseExceptions.schema.json
apiVersion: vulnetix.com/v1
kind: LicenseExceptions
metadata:
name: default
labels:
team: legal
annotations:
ticket: https://tracker.example.com/LEGAL-102
spec:
blanket:
- license: MPL-2.0
id: LEX-001
reason: File-level copyleft; we ship MPL files unmodified and publish their source.
scope: unmodified
approver: legal@acme.com
approvedDate: "2026-03-02"
expires: "2027-03-01"
projects: ["*"]
packages:
- purl: pkg:golang/github.com/hashicorp/*
license: BUSL-1.1
id: LEX-002
reason: Internal tooling only; not offered as a competing hosted service.
scope: dynamically linked
approver: legal@acme.com
approvedDate: "2026-04-15"
expires: "2026-12-31"
projects: [infra-tools]
- name: ghostscript
license: AGPL-3.0-only
id: LEX-003
reason: Used in the batch PDF renderer, which is never exposed over a network.
scope: vendored
approver: cto@acme.com
approvedDate: "2026-05-20"
projects: [pdf-batch]
---
# The repository file form, .vulnetix/license-exceptions.yaml: blanket and packages at the top level, no metadata.
apiVersion: vulnetix.com/v1
kind: LicenseExceptions
blanket:
- license: EPL-2.0
reason: Eclipse libraries are used unmodified as build-time dependencies.
packages:
- purl: pkg:npm/%40acme/internal-fonts
reason: Proprietary fonts licensed to ACME under contract C-2291.
HCL
There is no Terraform resource. The server stores nothing for this kind, so there is nothing for Terraform to manage. The file stays in the repository; see Which files are Platform IaC documents.
CLI (validates it)
vulnetix config validate -f - <<'EOF'
# yaml-language-server: $schema=https://github.com/Vulnetix/config-schemas/releases/latest/download/LicenseExceptions.schema.json
apiVersion: vulnetix.com/v1
kind: LicenseExceptions
metadata:
name: default
labels:
team: legal
annotations:
ticket: https://tracker.example.com/LEGAL-102
spec:
blanket:
- license: MPL-2.0
id: LEX-001
reason: File-level copyleft; we ship MPL files unmodified and publish their source.
scope: unmodified
approver: legal@acme.com
approvedDate: "2026-03-02"
expires: "2027-03-01"
projects: ["*"]
packages:
- purl: pkg:golang/github.com/hashicorp/*
license: BUSL-1.1
id: LEX-002
reason: Internal tooling only; not offered as a competing hosted service.
scope: dynamically linked
approver: legal@acme.com
approvedDate: "2026-04-15"
expires: "2026-12-31"
projects: [infra-tools]
- name: ghostscript
license: AGPL-3.0-only
id: LEX-003
reason: Used in the batch PDF renderer, which is never exposed over a network.
scope: vendored
approver: cto@acme.com
approvedDate: "2026-05-20"
projects: [pdf-batch]
---
# The repository file form, .vulnetix/license-exceptions.yaml: blanket and packages at the top level, no metadata.
apiVersion: vulnetix.com/v1
kind: LicenseExceptions
blanket:
- license: EPL-2.0
reason: Eclipse libraries are used unmodified as build-time dependencies.
packages:
- purl: pkg:npm/%40acme/internal-fonts
reason: Proprietary fonts licensed to ACME under contract C-2291.
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 LicenseExceptions |
Always LicenseExceptions. | |
metadata |
object | no | no other keys | Metadata for a singleton kind whose documents predate metadata.name. Both metadata and its name may be left out; a name, when given, must be default. | |
metadata.name |
string | no | exactly default |
||
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 | no | no other keys | ||
spec.blanket |
array of object | no | Licences exempted wherever they appear. The first unexpired match wins. | ||
spec.blanket[].license |
string | yes | length 1 to any | The SPDX licence id. Matching is by prefix, so MPL-2.0 also covers MPL-2.0-no-copyleft-exception. | |
spec.blanket[].id |
string | no | length 1 to any | A stable id to refer to the exception by in reports. | |
spec.blanket[].reason |
string | yes | pattern \S |
Why the exception exists. Required: an exception nobody can explain cannot be told apart from a mistake. | |
spec.blanket[].scope |
string | no | What the claim is limited to, such as vendored, unmodified, dynamically linked. | ||
spec.blanket[].approver |
string | no | Who signed the exception off. | ||
spec.blanket[].approvedDate |
string | no | pattern ^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T00:00:00Z)?$ |
When it was approved, as YYYY-MM-DD. | |
spec.blanket[].expires |
string | no | pattern ^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T00:00:00Z)?$ |
The last day the exception applies, as YYYY-MM-DD. Left out, it never expires. | |
spec.blanket[].projects |
array of string | no | each item: length 1 to any | Only these projects, matched without case; * is every project. Left out, every project. | |
spec.packages |
array of object | no | Packages exempted, optionally under one licence. Checked after blanket exceptions. | ||
spec.packages[].purl |
string | no | pattern ^pkg:[a-zA-Z.+-]+/; length 5 to any |
The package, as a purl with * as a wildcard segment, such as pkg:golang/github.com/hashicorp/*. | |
spec.packages[].name |
string | no | length 1 to any | The package name, matched as a substring, for ecosystems where the short name and the full module path are both in use. | |
spec.packages[].license |
string | no | length 1 to any | Exempt the package only under this SPDX licence. Left out, the package is exempt whatever licence it carries, which is the broader claim. | |
spec.packages[].id |
string | no | length 1 to any | A stable id to refer to the exception by in reports. | |
spec.packages[].reason |
string | yes | pattern \S |
Why the exception exists. Required: an exception nobody can explain cannot be told apart from a mistake. | |
spec.packages[].scope |
string | no | What the claim is limited to, such as vendored, unmodified, dynamically linked. | ||
spec.packages[].approver |
string | no | Who signed the exception off. | ||
spec.packages[].approvedDate |
string | no | pattern ^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T00:00:00Z)?$ |
When it was approved, as YYYY-MM-DD. | |
spec.packages[].expires |
string | no | pattern ^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T00:00:00Z)?$ |
The last day the exception applies, as YYYY-MM-DD. Left out, it never expires. | |
spec.packages[].projects |
array of string | no | each item: length 1 to any | Only these projects, matched without case; * is every project. Left out, every project. | |
blanket |
array of object | no | Licences exempted wherever they appear. The first unexpired match wins. | ||
blanket[].license |
string | yes | length 1 to any | The SPDX licence id. Matching is by prefix, so MPL-2.0 also covers MPL-2.0-no-copyleft-exception. | |
blanket[].id |
string | no | length 1 to any | A stable id to refer to the exception by in reports. | |
blanket[].reason |
string | yes | pattern \S |
Why the exception exists. Required: an exception nobody can explain cannot be told apart from a mistake. | |
blanket[].scope |
string | no | What the claim is limited to, such as vendored, unmodified, dynamically linked. | ||
blanket[].approver |
string | no | Who signed the exception off. | ||
blanket[].approvedDate |
string | no | pattern ^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T00:00:00Z)?$ |
When it was approved, as YYYY-MM-DD. | |
blanket[].expires |
string | no | pattern ^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T00:00:00Z)?$ |
The last day the exception applies, as YYYY-MM-DD. Left out, it never expires. | |
blanket[].projects |
array of string | no | each item: length 1 to any | Only these projects, matched without case; * is every project. Left out, every project. | |
packages |
array of object | no | Packages exempted, optionally under one licence. Checked after blanket exceptions. | ||
packages[].purl |
string | no | pattern ^pkg:[a-zA-Z.+-]+/; length 5 to any |
The package, as a purl with * as a wildcard segment, such as pkg:golang/github.com/hashicorp/*. | |
packages[].name |
string | no | length 1 to any | The package name, matched as a substring, for ecosystems where the short name and the full module path are both in use. | |
packages[].license |
string | no | length 1 to any | Exempt the package only under this SPDX licence. Left out, the package is exempt whatever licence it carries, which is the broader claim. | |
packages[].id |
string | no | length 1 to any | A stable id to refer to the exception by in reports. | |
packages[].reason |
string | yes | pattern \S |
Why the exception exists. Required: an exception nobody can explain cannot be told apart from a mistake. | |
packages[].scope |
string | no | What the claim is limited to, such as vendored, unmodified, dynamically linked. | ||
packages[].approver |
string | no | Who signed the exception off. | ||
packages[].approvedDate |
string | no | pattern ^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T00:00:00Z)?$ |
When it was approved, as YYYY-MM-DD. | |
packages[].expires |
string | no | pattern ^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T00:00:00Z)?$ |
The last day the exception applies, as YYYY-MM-DD. Left out, it never expires. | |
packages[].projects |
array of string | no | each item: length 1 to any | Only these projects, matched without case; * is every project. Left out, every project. |
Rules
Conditions the schema enforces beyond each field’s own type. vulnetix config validate and the engine’s plan report a document that breaks one.
| On | Rule |
|---|---|
the document |
Exactly one of these holds: (1) The config form: metadata is required, spec is required, blanket is not allowed and packages is not allowed; (2) The repository file form: spec is not allowed. |
spec.packages[] |
At least one of purl or name is set. |
packages[] |
At least one of purl or name is set. |
Applying this kind
- Not stored. The engine registers the kind so that validate and plan check a document. A plan that includes one shows the warning
not_stored, and apply sends nothing for it.
Two forms
Both are valid, and a document is exactly one of them.
| Form | Where | Shape |
|---|---|---|
| Repository file | .vulnetix/license-exceptions.yaml |
blanket and packages at the top level. metadata is optional. |
| Config | A document under .vulnetix/config |
metadata and spec are required, and blanket and packages sit under spec |
The fields in the table are the same in both. A licence file written before documents carried apiVersion and kind is read as this kind from its well-known path, so an older repository keeps working. vulnetix license and vulnetix scan --evaluate-licenses read the file, or the document under .vulnetix/config, unless --exceptions-file names one. Defining it in both places, or twice, is an error. See Which files are Platform IaC documents. In GitHub Actions the license action reads the same files.
# The repository file form, .vulnetix/license-exceptions.yaml
apiVersion: vulnetix.com/v1
kind: LicenseExceptions
blanket:
- license: EPL-2.0
reason: Eclipse libraries are used unmodified as build-time dependencies.
packages:
- purl: pkg:npm/%40acme/internal-fonts
reason: Proprietary fonts licensed to ACME under contract C-2291.
Where it takes effect
Like LicensePolicy, the server stores nothing for this kind. The engine registers it so that validate and plan check a document, and a plan that includes one shows the warning not_stored. The CLI reads the repository file on the machine running the scan.
Terraform and OpenTofu
There is no Terraform resource. The server stores nothing for this kind, so there is nothing for Terraform to manage. The file stays in the repository; see Which files are Platform IaC documents.
Check a file with vulnetix config validate -f <file>. See Validate documents. In an editor, start the file with the schema comment.