check
Report Hex package licence metadata and enforce your licence policy. Return a nonzero exit code for violations.
check runs the same audit as the command with no subcommand. It then
enforces your policy. It returns a nonzero exit code when it finds a
violation. Use check in CI.
licence_audit checkDefine a policy
See configuration discovery for how the
command selects the policy file and handles explicit --config files.
Add the policy to [tools.licence_audit] in gleam.toml:
[tools.licence_audit]allow = ["Apache-2.0", "MIT"]deny = ["GPL-3.0-only"]An allow list permits only the specified licences. A deny list rejects
matching licences. To create the policy, use
licence_audit update. The command gets metadata, selects existing entries,
asks you to confirm the selection, and writes the result. It preserves
comments in gleam.toml.
Configuration validation
Unknown keys in [tools.licence_audit] or its notices table are errors with
exit code 2. The policy keys are allow, deny, vuln_severity,
vuln_block_unknown, exceptions, and notices; the notices keys are include
and exclude. The error names the unknown key. An older binary therefore
rejects keys added by a newer release instead of silently ignoring them.
Every allow and deny entry, from config or CLI, must parse as an SPDX
expression. Empty entries and malformed expressions such as MIT/Apache-2.0
or Apache 2.0 cause exit code 2. Validation checks syntax, not membership in
the SPDX License List. Custom identifiers and LicenseRef-/DocumentRef-
forms remain supported. Validation does not change the entry text.
1.0 allow-list requirement
For version 1.0, check requires a non-empty allow list. A deny-only policy
returns exit code 2 and asks you to add allow. This also applies to
check --vulns: it remains a combined licence and vulnerability gate, not a
vulnerability-only check. This requirement replaces deny-only checks supported
by earlier releases.
deny is an exact-match override and wins over allow. Matching does not
normalise deprecated identifiers, a trailing +, -or-later identifiers, or
WITH terms into equivalent licences. List the complete identifiers or terms
that you intend to allow or deny.
SPDX expressions
AND requires both terms to pass. OR needs one passing alternative.
With the policy above, MIT AND GPL-3.0-only fails, but
MIT OR GPL-3.0-only passes through MIT. The same branch must satisfy both
the allow and deny rules.
Operators must be uppercase. WITH binds first, then AND, then OR;
parentheses change grouping. Treat GPL-2.0-only WITH Classpath-exception-2.0
as one term: allowing or denying bare GPL-2.0-only does not match it.
A trailing + is also part of the term. Use the complete term in your policy.
SPDX identifiers match without regard to case; custom LicenseRef-
identifiers remain case-sensitive. The parser checks syntax, not membership
in the SPDX licence list. It does not infer equivalence between identifiers.
Each separate string in a package’s licence list must pass. A full
expression in allow accepts its terms. It does not override a deny rule on
one of its operands. A full expression in deny rejects that declaration.
Expression matching ignores whitespace between tokens and the case of SPDX
identifiers. It keeps the case of custom references and the tokens of the
expression.
Malformed expressions fail licence evaluation. For untrusted metadata, the parser limits each expression to 64 KiB, 1024 tokens, and 64 nested parentheses. Expressions above these limits fail the gate.
Ad-hoc and merged policy
CLI --allow and --deny values form a union with the corresponding
configuration lists; duplicates are removed. --allow adds permitted licences
for this run and can widen the gate. --deny adds denied licences for this run.
Neither option replaces the configured list, and deny still takes precedence
over allow.
For example, add permitted and denied licences to the configured policy:
licence_audit check --allow=Apache-2.0,MIT --deny=GPL-3.0-onlyUse --config=other.toml to read a different file. The file must have a
[tools.licence_audit] section. Use --ignore-config to use only CLI options.
Note:
--allowand--denyalso work on the command with no subcommand. These options show a policy preview. Findings return exit code0when the scan completes. Usecheckto return a failure for a violation.
Exit codes
Completed licence checks exit 0 when the policy passes and 1 for policy
violations. Unavailable or invalid package metadata exits 2, even when a
partial report is available or other packages violate the policy. The command
with no subcommand also exits 2 for these metadata failures.
Production-only gates
Use --prod-only when your gate should consider only production dependencies.
The command then ignores licence violations in development dependencies. This
option prevents tooling-only packages from causing a CI failure.
Production dependencies are the packages reachable from [dependencies] in
the gleam.toml beside the selected manifest. A valid file without that table,
or with an empty table, has no production dependencies. This rule also applies
to check --vulns --prod-only.
A missing gleam.toml uses all lockfile direct dependencies as production
roots. An unreadable file, invalid TOML, or a dependencies value that is not a
table causes exit code 2. --ignore-config skips policy settings, not this
scope validation.
Also fail on vulnerabilities
Add --vulns to run the licence audit and query OSV.dev. The command fails
when an advisory meets or exceeds the severity threshold:
licence_audit check --vulnslicence_audit check --vulns --vuln-severity=mediumlicence_audit check --vulns --vuln-block-unknownThe threshold is low | medium | high (default) | critical.
Advisories with severity none (a valid CVSS score of 0.0) never cause a
failure, even with --vuln-block-unknown. none is not a gate threshold.
The command reports advisories with unknown severity. By default, these
advisories do not cause a failure. Use --vuln-block-unknown to make these
advisories cause a failure. OSV batch or advisory-detail failures exit 2,
because the gate cannot complete. You can set the threshold in the configuration:
[tools.licence_audit]vuln_severity = "high"vuln_block_unknown = trueThe CLI flags --vuln-severity and --vuln-block-unknown require --vulns.
Without it, they cause a usage error (exit 1), including an explicit
--vuln-block-unknown=false. They do not enable a scan. The configuration keys
remain valid without --vulns and apply only when the scan is enabled.
--vuln-severity overrides the configured threshold. --vuln-block-unknown
can only enable blocking: if you omit it, a configured true still applies.
There is no CLI flag to turn this setting off. Use --ignore-config to ignore
both configured vulnerability settings and use CLI-only defaults, which do
not block unknown severity.
Scoped policy exceptions
Record an exception to accept one finding at one locked version. Keep the entry in version control so reviewers can read the reason.
[[tools.licence_audit.exceptions]]purl = "pkg:hex/example@1.2.3"finding = "denied-licence"licence = "GPL-3.0-only"reason = "Approved for this release while we replace the dependency."expires = "2026-12-31"
[[tools.licence_audit.exceptions]]purl = "pkg:hex/example@1.2.3"finding = "advisory"advisory = "CVE-2026-12345"reason = "Reviewed the affected feature; this application does not use it."expires = "2026-12-31"Put global settings such as allow, deny, and vuln_severity in
[tools.licence_audit], before the exception tables. Each exception requires
purl, finding, and a non-empty reason.
finding |
Additional field | What it accepts |
|---|---|---|
denied-licence |
licence = "GPL-3.0-only" |
A matching declared licence rejected by deny. |
unallowed-licence |
licence = "Apache-2.0" |
A matching declared licence absent from a non-empty allow list. |
no-licences-declared |
None | A successful metadata response with an empty licence list. |
advisory |
advisory = "CVE-2026-12345" |
An OSV advisory ID or a direct alias in the fetched record. |
Use the licence term from the finding in the report, rather than the full
declared expression. Licence selectors use the same token matching as allow
and deny: ordinary SPDX identifier case and whitespace between tokens do not
affect the match. For example, gpl-3.0-only matches GPL-3.0-only.
Custom LicenseRef- and DocumentRef- references remain case-sensitive.
Parentheses and licence variants remain distinct.
A denied term takes precedence over an unallowed term.
An exception for one selector cannot accept another selector, a second
required term, or another advisory. For OR, an accepted alternative is
sufficient. The report prefers an alternative that passes global policy over
one that needs an exception. Malformed expressions cannot be excepted.
Exact package scope
Licence exceptions require pkg:hex/<name>@<exact-version>. Advisory exceptions
also accept pkg:github/<owner>/<repo>@<full-commit>, for example:
[[tools.licence_audit.exceptions]]purl = "pkg:github/owner/repo@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"finding = "advisory"advisory = "GHSA-xxxx-yyyy-zzzz"reason = "Reviewed the affected code at this commit."Copy the full locked commit, not a branch, tag, or abbreviated hash. Use lowercase package identities and full hexadecimal Git object IDs (40 or 64 characters). Hex versions support exact prerelease and build suffixes. Wildcards, version ranges, purl qualifiers, subpaths, and other sources are not supported. A version or commit update does not inherit the old exception.
Advisory IDs are case-sensitive. Match only the record’s primary ID or its
explicit aliases; related IDs, text mentions, and alias chains do not
match. The same advisory on another package still uses the normal gate.
Two entries that select the same scoped finding cause a configuration error,
including licence selectors that differ only in ordinary identifier case or
token whitespace, and entries that overlap through advisory aliases. Remove
one entry instead of relying on file order.
Precedence and expiry
The command evaluates global rules first, then applies each matching
exception. An active exception can accept an explicit deny, including a deny
added through the CLI. It does not modify the global lists or declared
metadata. Exceptions alone do not replace the licence policy required by
check. --ignore-config ignores the exceptions along with other settings.
Set expires = "YYYY-MM-DD" for a temporary waiver. The date must be a valid,
quoted calendar date. An exception dated 2026-12-31 remains active through
that UTC date and stops applying at 2027-01-01T00:00:00Z. The command reads
the system clock once per run; reproducible-build timestamps do not affect
expiry. Omit expires for an indefinite review decision.
Review report and stale entries
The report retains each accepted finding and marks it excepted, with the
reason and expiry. A package with both accepted and blocking findings still
fails the gate. Accepted findings remain visible when another dependency tree
fails and when you use --quiet.
The exception summary reports expired entries and stops applying them.
It reports unused when a completed scan finds no matching package or
finding. Remove these stale entries after a dependency update, resolved
advisory, or global policy change. Expired and unused entries do not fail on
their own; matching expired findings follow normal policy and severity rules.
An entry is not evaluated if its scan is disabled, --prod-only excludes
the package, or the command cannot get the evidence. Do not treat these
entries as stale. Licence-only runs do not evaluate advisory exceptions.
The command with no subcommand previews licence exceptions without enforcing them, and
vulns displays advisory exceptions without enforcing a gate.
Exceptions cannot accept failed network requests, malformed metadata, missing
advisory details, or unsupported source coverage. They do not change SBOM
evidence, remove notice content, or remove licence-text and attribution
requirements. update preserves exception entries and their comments.
Flags
Reports Hex package licence metadata and enforces the configured licence policy, exiting non-zero on violations.
Usage:
licence_audit check [--flags]Flags:
| Name | Type | Default | Description |
|---|---|---|---|
--allow |
STRING_LIST |
`` | Allow licences, comma-separated |
--cache-path |
STRING |
Override the licence metadata cache directory | |
--color |
STRING |
auto |
Colorize output: auto|always|never (default auto; alias: –colour) |
--config |
STRING |
Read configuration from PATH | |
--deny |
STRING_LIST |
`` | Deny licences, comma-separated |
--ignore-config |
BOOL |
false |
Ignore configuration files |
--manifest |
STRING |
Read manifest from PATH | |
--no-cache |
BOOL |
false |
Bypass the on-disk caches |
--prod-only |
BOOL |
false |
Only scan production dependencies; exclude dev dependencies |
--quiet |
BOOL |
false |
Suppress progress output (alias: -q) |
--verbose |
BOOL |
false |
Show detailed progress output (alias: -v) |
--vuln-block-unknown |
BOOL |
Fail check --vulns on advisories whose severity is unknown (default false; requires –vulns) |
|
--vuln-severity |
STRING |
Minimum severity that triggers check --vulns failure: low|medium|high|critical (default high; requires –vulns) |
|
--vulns |
BOOL |
false |
When used with check, also query OSV.dev and fail on vulnerabilities at or above –vuln-severity |