Policy reference (depaudit.toml)
depaudit audit looks for depaudit.toml next to the scanned path (or use --policy FILE). Every key is optional;
without a policy file the defaults below apply. Unknown keys are rejected with the name of the offending key, so typos
do not silently disable a rule.
A complete, commented policy lives in examples/monorepo/depaudit.toml.
Outcome model
Every check produces findings with a severity:
| Severity | Meaning | Exit code effect |
|---|---|---|
error |
a violation (license deny, banned, ...) |
audit exits 1 |
warning |
needs a human decision (license review) |
exits 1 only with --strict |
info |
informational (e.g. outdated) | never |
Exit codes: 0 clean, 1 violations found, 2 usage or input error (bad lockfile, bad policy, unreadable file).
Top level
distribution = "saas" # "saas" (default) or "distributed"
include_dev = false # evaluate dev-only packages too (default false)
distribution selects the copyleft rule set (see below). With include_dev = false, packages reachable only from dev
roots are skipped by the license, package and age checks, and their vulnerabilities are warnings instead of errors.
Hygiene checks (typosquats) always look at everything.
[licenses]
[licenses]
allowed = ["MIT", "Apache-2.0", "BSD-3-Clause"]
denied = ["AGPL-3.0-only"]
review = ["MPL-2.0"]
unknown = "review" # allow | review | deny - no license found / unparseable / unrecognised id
unlisted = "review" # allow | review | deny - known license in none of the lists
- Entries are SPDX ids and are normalised, so
GPL-3.0,GPL-3.0-onlyandGPL-3.0+/-or-latermean what you expect. unlisteddefaults toreviewwhenallowedis non-empty, otherwiseallow.- Entries may include an exception:
"GPL-2.0-only WITH Classpath-exception-2.0".
Decision order for one license id
- Exact string match (including any
WITHexception) indenied, thenallowed, thenreview. - The same lookup using only the base id (so listing
GPL-2.0-onlyalso covers itsWITHvariants unless the exact variant is listed). - Copyleft category rule for the current
distribution(below). unlisteddefault.
An id that is not a recognised SPDX id (or an expression that does not parse) gets the unknown action.
SPDX expressions
A OR B: the package satisfies the policy if any alternative does, so the best (most permissive) verdict wins.
A AND B: all terms apply, so the worst verdict wins. WITH binds tighter than AND, AND tighter than OR.
The explanation says which branch decided: MIT OR GPL-3.0-only resolved via: MIT is in the allowed list.
[copyleft.<distribution>]
License families are classified as:
| Category | Licenses |
|---|---|
strong |
GPL-1.0/2.0/3.0, EUPL, OSL-3.0 |
weak |
LGPL, MPL, EPL, CDDL, CPL, MS-RL, ... and GPL WITH a linking/classpath exception |
network |
AGPL, SSPL, RPL, CPAL |
Everything else is treated as permissive. Defaults:
| Distribution | strong | weak | network |
|---|---|---|---|
saas |
review |
allow |
deny |
distributed |
deny |
review |
deny |
Override any cell:
[copyleft.distributed]
strong = "review"
[packages]
[packages]
allow = ["npm:internal-*", "pypi:legacy-tool"] # exempt from the license check
deny = ["npm:event-stream", "@evil/*"] # always an error
[packages.licenses] # override missing/wrong license metadata
"pypi:some-pkg" = "MIT"
Patterns are shell-style globs matched against ecosystem:name (npm, pypi, golang, cargo) or the bare name.
[[banned_versions]]
[[banned_versions]]
package = "npm:lodash"
versions = "<4.17.21"
reason = "prototype pollution"
versions uses the ecosystem's own range syntax (PEP 440 specifiers for PyPI, npm ranges for npm and Go, Cargo
requirements for crates). Pre-releases are included in the match, so <2.0.0 bans 2.0.0-rc.1 as well. See
version-semantics.md.
[age]
[age]
max_days = 730
level = "warn" # off | warn | error
A package is stale when its latest release is older than max_days relative to --as-of (default: today). Release
dates come from a --metadata snapshot or --online; packages without date information are skipped.
[vulnerabilities]
[vulnerabilities]
fail_on = "high" # none | low | medium | high | critical
Matches at or above the threshold are errors, lower ones warnings. Severity comes from CVSS v3 vectors (computed
base score) or the advisory's database_specific.severity; advisories with no severity count as medium. none turns
every vulnerability into a warning.
[hygiene]
[hygiene]
duplicates = "warn" # off | warn | error - same package at several versions in one lockfile (npm, cargo)
unpinned = "warn" # loose specifiers: requirements without ==, `*`/`latest`/open-ended npm ranges, URL/git refs
typosquat = "error" # one edit away from a top-1000 PyPI/npm name
Checks
depaudit audit --checks license,packages,vuln,hygiene,age,outdated runs a subset (default: all). vuln needs --osv.