CLI · commit 8458277

depaudit

Dependency inventory, license policy & SBOM generator

Download depaudit.zip
Quickstart
unzip depaudit.zip && cd depaudit
uv venv .venv && uv pip install -p .venv/bin/python -e '.[dev]'
.venv/bin/python -m pytest -q

depaudit

Know exactly what third-party code ships in your projects. depaudit parses lockfiles across Python, JavaScript, Go and Rust, builds the dependency graph, enforces a license policy, checks an offline OSV advisory snapshot with ecosystem-correct version semantics, flags hygiene problems (duplicates, loose pins, typosquats) and emits CycloneDX 1.5 and SPDX 2.3 SBOMs - as a single CLI that is easy to run in CI and has no runtime network requirement.

Features

Install

Python 3.12+.

cd depaudit
uv venv .venv && uv pip install -p .venv/bin/python -e '.[dev]'
.venv/bin/depaudit --help

Quickstart

The repository ships a realistic polyglot monorepo in examples/monorepo (11 lockfiles, one of each supported kind), an OSV snapshot and an offline metadata snapshot.

cd depaudit
M=examples/monorepo
O="--metadata examples/metadata.json --site-packages $M/site-packages"

.venv/bin/depaudit scan   $M $O                       # inventory
.venv/bin/depaudit audit  $M $O --osv examples/osv    # policy + vulnerabilities + hygiene (exit 1 on violations)
.venv/bin/depaudit why    semver $M                   # why is this here?
.venv/bin/depaudit sbom   $M $O --format cyclonedx -o sbom.cdx.json
.venv/bin/depaudit sbom   $M $O --format spdx      -o sbom.spdx.json
.venv/bin/depaudit diff   examples/pr-diff/base.json examples/pr-diff/head.json

On your own project: depaudit audit . --osv path/to/osv-export.zip (the policy is read from ./depaudit.toml if present).

Usage

All commands take an optional PATH (a directory, scanned recursively, or a single lockfile; default .). The commands that read packages share these options:

Option Purpose
--policy FILE policy file (default: depaudit.toml next to PATH)
--metadata FILE offline metadata snapshot (license, latest version and release date per package); repeatable
--site-packages DIR extra site-packages directory to read license metadata from; repeatable. node_modules and .venv/lib/python*/site-packages next to a lockfile are found automatically
--online fill missing license / latest-release data from PyPI and the npm registry
--cache-dir, --cache-ttl cache for --online (default .depaudit-cache, 24 h)

scan and licenses

$ depaudit scan examples/monorepo --metadata examples/metadata.json --site-packages examples/monorepo/site-packages
monorepo: 91 packages (41 direct, 50 transitive, 18 dev) from 13 lockfile(s)                        

  Ecosystem   Package                Version                Scope             License               
 ────────────────────────────────────────────────────────────────────────────────────────────────── 
  cargo       aho-corasick           0.7.18                 transitive prod   Unlicense OR MIT      
  cargo       autocfg                1.1.0                  transitive prod   Apache-2.0 OR MIT     
  cargo       chrono                 0.4.19                 direct prod       MIT OR Apache-2.0     
  cargo       diff                   0.1.13                 transitive dev    MIT OR Apache-2.0     
  cargo       libc                   0.2.147                transitive prod   MIT OR Apache-2.0     
  cargo       memchr                 2.5.0                  transitive prod   Unlicense OR MIT      
  cargo       num-integer            0.1.45                 transitive prod   MIT OR Apache-2.0     
  cargo       num-traits             0.2.15                 transitive prod   MIT OR Apache-2.0     
  cargo       pretty_assertions      1.4.0                  direct dev        MIT OR Apache-2.0     
  cargo       regex                  1.5.4                  direct prod       MIT OR Apache-2.0     
  cargo       regex-syntax           0.6.25                 transitive prod   MIT OR Apache-2.0     
  cargo       time                   0.1.45                 transitive prod   MIT OR Apache-2.0     
  cargo       yansi                  0.5.1                  transitive dev    MIT OR Apache-2.0     
  golang      github.com/gin-gonic   v1.9.0                 direct prod       MIT                   
              /gin                                                                                  
  golang      github.com/pkg/error   v0.9.1                 direct prod       BSD-2-Clause          
              s                                                                                     
  golang      github.com/stretchr/   v1.8.4                 direct prod       MIT                   
  ...
$ depaudit licenses examples/monorepo --metadata examples/metadata.json --site-packages examples/monorepo/site-packages

  License                                Packages   Examples                                        
 ────────────────────────────────────────────────────────────────────────────────────────────────── 
  MIT                                          46   github.com/gin-gonic/gin,                       
                                                    github.com/stretchr/testify, @babel/runtime,    
                                                    @types/node, ansi-styles ...                    
  BSD-3-Clause                                 11   golang.org/x/crypto, golang.org/x/net,          
                                                    highlight.js, click, colorama ...               
  MIT OR Apache-2.0                            10   chrono, diff, libc, num-integer, num-traits     
                                                    ...                                             
  Apache-2.0                                    4   typescript, requests, requests, tzdata          
  ISC                                           4   lru-cache, semver, semver, yallist              
  BSD-2-Clause                                  2   github.com/pkg/errors, pygments                 
  MPL-2.0                                       2   certifi, pathspec                               
  Unlicense OR MIT                              2   aho-corasick, memchr                            
  (unknown)                                     1   reqests                                         
  Apache Software License; BSD License          1   packaging                                       
  Apache-2.0 OR MIT                             1   autocfg                                         
  BSD-3-Clause OR Apache-2.0                    1   python-dateutil                                 
  BSD-like                                      1   idna                                            
  GPL-3.0-only                                  1   chalkk                                          
  HPND                                          1   pillow                                          
  LGPL-2.0-or-later                             1   chardet                                         
  LGPL-2.1-only                                 1   chardet                                         
  WTFPL                                         1   left-pad                                        

scan --format json prints the same data as JSON. Note how idna shows the raw string BSD-like (not an SPDX id), and python-dateutil shows a dual-license pair read from trove classifiers.

audit

$ depaudit audit examples/monorepo --metadata examples/metadata.json \
      --site-packages examples/monorepo/site-packages --osv examples/osv --as-of 2024-06-01
monorepo: 91 packages (41 direct, 50 transitive) from 13 lockfile(s), as of 2024-06-01
Findings                                                                                            

  Severity   Rule              Detail                                                               
 ────────────────────────────────────────────────────────────────────────────────────────────────── 
  error      banned-version    lodash 4.17.15 matches banned range <4.17.21: prototype pollution    
                               and command injection (fixed in 4.17.21)                             
  error      banned-version    pyyaml 5.3 matches banned range <5.4: arbitrary code execution via   
                               full_load                                                            
  error      license-policy    chalkk 4.0.0: GPL-3.0-only is strong copyleft; policy for            
                               distributed distribution: deny                                       
  error      package-denied    left-pad is on the package deny list (npm:left-pad)                  
  error      typosquat         chalkk is one edit away from popular package chalk                   
  error      typosquat         reqests is one edit away from popular package requests               
  ...

  Advisory              Package               Severity   Fixed in              Upgrade to           
 ────────────────────────────────────────────────────────────────────────────────────────────────── 
  GHSA-m5pq-gvj9-9vr8   regex 1.5.4           high       1.5.5                 1.5.5                
  GHSA-wcg3-cvx6-7396   time 0.1.45           medium     0.2.23                0.2.23               
  GHSA-3vp4-m3rf-835h   github.com/gin-goni   medium     v1.9.1                v1.9.1               
                        c/gin v1.9.0                                                                
  GHSA-ffhg-7mh4-33c4   golang.org/x/crypto   high       v0.0.0-202002201836   v0.0.0-202002201836  
                        v0.0.0-201903082217              23-bac4c82f6975       23-bac4c82f6975      
                        18-c2843e01d9a2                                                             
  GHSA-vvpx-j8f3-3w6h   golang.org/x/net      high       v0.17.0               v0.17.0              
                        v0.7.0                                                                      
  GHSA-grv7-fg5c-xmjg   braces 3.0.2          high       3.0.3                 3.0.3                
  GHSA-35jh-r3h4-6jhm   lodash 4.17.15        high       4.17.21               4.17.21              
  GHSA-p6mc-m468-83gw   lodash 4.17.15        high       4.17.19               4.17.21              
  GHSA-952p-6rrq-rcjv   micromatch 4.0.5      medium     4.0.8                 4.0.8                
  GHSA-xvch-5gv4-984h   minimist 1.2.5        critical   1.2.6                 1.2.6                
  GHSA-c2qf-rxjj-qqgw   semver 6.3.0          medium     6.3.1                 6.3.1                
  GHSA-c2qf-rxjj-qqgw   semver 7.3.5          medium     7.5.2                 7.5.2                
  GHSA-3h5v-q93c-6h6q   ws 8.13.0             high       8.17.1                8.17.1               
  GHSA-h5c8-rqwp-cp95   jinja2 2.11.2         medium     3.1.3                 3.1.3 (major)        
  GHSA-8ghj-p4vj-mr35   pillow 9.5.0          medium     -                     10.0.1 (major)       
  GHSA-j7hp-h8jx-5ppr   pillow 9.5.0          high       10.0.1                10.0.1 (major)       
  GHSA-8q59-q68h-6hv4   pyyaml 5.3            critical   5.4                   5.4                  
  GHSA-j8r2-6x86-q33q   requests 2.19.1       medium     2.31.0                2.31.0               
  PYSEC-2018-28         requests 2.19.1       high       2.20.0                2.31.0               
  GHSA-v845-jxx5-vc9f   urllib3 1.24.1        medium     1.26.17               1.26.17              
  GHSA-v845-jxx5-vc9f   urllib3 1.26.16       medium     1.26.17               1.26.17              

FAIL: 17 error(s), 31 warning(s), 21 vulnerability match(es)

(exit code 1). Options: --format table|json|markdown, -o FILE, --checks license,packages,vuln,hygiene,age,outdated, --as-of YYYY-MM-DD (reproducible age checks), --strict (warnings fail too), -v (also list informational findings such as outdated packages).

The JSON report (--format json) is the input of diff; the Markdown report is meant for PR comments and CI summaries. Exit codes: 0 clean, 1 violations, 2 bad input or usage.

Vulnerability rows show the fixed version of the matching advisory range and the minimal upgrade that clears every advisory in the snapshot for that package ((major) marks a major-version change). pillow 9.5.0 illustrates why: the first advisory has no fixed version (last_affected: 9.5.0), the second is fixed in 10.0.1, and 10.0.1 is the smallest version affected by neither.

why

$ depaudit why braces examples/monorepo
npm:braces 3.0.2 (transitive prod)
  docs-site -> micromatch 4.0.5 -> braces 3.0.2

$ depaudit why semver examples/monorepo
npm:semver 6.3.0 (transitive prod)
  storefront-web -> make-dir 3.1.0 -> semver 6.3.0
npm:semver 7.3.5 (direct prod)
  storefront-web -> semver 7.3.5

$ depaudit why time examples/monorepo
cargo:time 0.1.45 (transitive prod)
  fx-cli -> chrono 0.4.19 -> time 0.1.45

$ depaudit why golang.org/x/net examples/monorepo
golang:golang.org/x/net v0.7.0 (transitive prod)
  no dependency path recorded (the lockfile does not store the dependency graph)

PACKAGE can be name, name@version or ecosystem:name. Go lockfiles do not store a graph, so indirect modules have no path.

sbom

depaudit sbom examples/monorepo --format cyclonedx -o sbom.cdx.json   # CycloneDX 1.5
depaudit sbom examples/monorepo --format spdx -o sbom.spdx.json       # SPDX 2.3

Documents are validated against the official schemas before they are written (--no-validate to skip). An excerpt (one component, first two dependency entries):

{
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
  "bomFormat": "CycloneDX",
  "specVersion": "1.5",
  "serialNumber": "urn:uuid:536683b4-c6d9-5baa-a10a-d92c2586ed6d",
  "version": 1,
  "metadata": {
    "timestamp": "2026-10-16T15:18:25Z",
    "tools": {
      "components": [
        {
          "type": "application",
          "name": "depaudit",
          "version": "0.1.0"
        }
      ]
    },
    "component": {
      "type": "application",
      "bom-ref": "root:monorepo",
      "name": "monorepo"
    }
  },
  "components": [
    {
      "type": "library",
      "bom-ref": "pkg:npm/minimist@1.2.5",
      "name": "minimist",
      "version": "1.2.5",
      "purl": "pkg:npm/minimist@1.2.5",
      "hashes": [
        {
          "alg": "SHA-512",
          "content": "9229c3253193c4387e12c15ef05719aec4b022d4015c41b18e6ff5f5c8193b4d21bd25446367fd1c3751092cda1cc01bbc9c0b227f18664c90d1012b7e57f9b1"
        }
      ],
  ...

diff

$ P="--policy examples/monorepo/depaudit.toml --osv examples/osv --format json"
$ depaudit audit examples/pr-diff/base $P -o base.json   # on the base branch
$ depaudit audit examples/pr-diff/head $P -o head.json   # on the PR branch
$ depaudit diff base.json head.json
New dependencies                                    

  Package         Versions   License        Direct  
 ────────────────────────────────────────────────── 
  npm:csv-tools   2.3.0      GPL-3.0-only   yes     
  npm:minimist    1.2.5      MIT            no      

New licenses in the tree: GPL-3.0-only
New vulnerabilities                                             

  Advisory              Package          Severity   Upgrade to  
 ────────────────────────────────────────────────────────────── 
  GHSA-xvch-5gv4-984h   minimist 1.2.5   critical   1.2.6       

New findings                                                                                        

  Severity   Rule             Detail                                                                
 ────────────────────────────────────────────────────────────────────────────────────────────────── 
  error      license-policy   csv-tools 2.3.0: GPL-3.0-only is strong copyleft; policy for          
                              distributed distribution: deny                                        

REGRESSION: change introduces new vulnerabilities or policy errors

Exit code 1 means the change introduces a vulnerability or a new policy error. --format markdown produces a PR comment (see examples/pr-diff).

Configuration

A minimal depaudit.toml:

distribution = "distributed"     # or "saas"

[licenses]
allowed = ["MIT", "Apache-2.0", "BSD-3-Clause", "ISC"]
denied  = ["AGPL-3.0-only"]
review  = ["MPL-2.0"]

[[banned_versions]]
package  = "npm:lodash"
versions = "<4.17.21"

[age]
max_days = 730

[vulnerabilities]
fail_on = "high"

The full reference (decision order, copyleft categories, expressions, every key) is in docs/policy.md.

Architecture

src/depaudit/
  cli.py            click commands, option wiring, exit codes
  parsers/          one module per ecosystem: python.py, js.py, golang.py, rust.py, common.py; __init__ = discovery
  model.py          Package, Inventory (graph, roots, scopes), purls
  graph.py          why-paths
  versions.py       dispatch; pep440.py and semver.py implement the version semantics
  spdx_expr.py      SPDX expression parser / evaluator
  licdata.py        phrase fingerprints (no license texts);  licenses.py  classifier + normalisation
  localmeta.py      license detection from site-packages / node_modules
  metadata.py       offline snapshots + PyPI / npm lookup with disk cache;  enrich.py  merges all sources
  policy.py         depaudit.toml, license verdicts, package / banned-version / age checks
  osv.py, cvss.py   OSV snapshot loading, range matching, upgrade suggestion, CVSS v3 scoring
  hygiene.py        duplicates, loose specifiers, typosquats (data/popular.json)
  audit.py          runs the checks, builds the Report
  report.py, diff.py  table / Markdown rendering, report diff
  sbom.py           CycloneDX / SPDX generation and schema validation (schemas/)

Deeper write-ups: docs/design.md (graph, license detection, classifier worked example, SBOM mapping), docs/version-semantics.md (PEP 440, semver, Go, OSV ranges), docs/policy.md.

Tests

.venv/bin/pytest -q

The suite covers every lockfile parser, the graph and why paths, PEP 440 / semver / Cargo / Go version ordering and range matching (table-driven, including pre-releases, epochs and local versions), SPDX parsing and evaluation, the license classifier, policy outcomes, the OSV matcher and upgrade suggestions, typosquats, schema validity of both SBOM formats (including negative cases), diff, the registry client (with an injected fetcher, never the network) and the CLI end to end.

Limitations

License

MIT, see LICENSE.