List every place third party code enters your data stack: dbt packages, Airflow providers and images, notebook environments and extensions, cluster libraries, Python model packages, and warehouse connectors. Record each with a version and an owner, in one inventory. You cannot patch what you have not listed.
Why data stacks are easy to miss
A typical web service has one or two manifests. A data platform has many, owned by different teams, in different formats. Analysts add a notebook package. Engineers add an Airflow provider. Analytics engineers add a dbt package. Nobody sees all of it.
The sources to list
| Layer | Where the list lives | Source of truth |
|---|---|---|
| dbt packages | package file and package-lock.yml | See pinning dbt packages |
| dbt Python models | packages in model config | Python models |
| Airflow | image requirements, constraints, installed providers | Providers |
| Notebooks | environment files, extensions | JupyterLab extensions |
| Compute libraries | compute configuration, volumes | Databricks scopes |
| Connectors | requirements of every job | Warehouse connectors |
Steps
- Pick the unit. One row per package, version and where it runs.
- Collect from files first. Lock files, requirements files and the dbt lock file are the cheapest, most reliable inputs.
- Add what files miss. Ask the platform for installed packages: a package list from a running image, a notebook environment, a cluster.
- Name an owner for each environment.
- Mark exposure. Production job, shared notebook server, personal sandbox.
- Store it as an SBOM or a table you can query, and refresh it on a schedule.
- Check it against advisories continuously, not once.
- Review drift. Compare what is declared with what is installed.
Common gaps
Notebook sessions that install packages at run time never show in a manifest. Compiled and system libraries in the base image come from the OS, not pip. Packages used only by a Python model are declared in a model config, not a requirements file. A manifest only view misses all three, as our post on what manifest only scanning misses explains.
Try it yourself
Open the demo and see how an inventory lists direct and transitive packages with versions. Think about which of your layers would need its own feed.
Click through it at your own pace, or open it full screen.
Quick check
What is the cheapest first step?
Collect lock files and requirements files from every repository. Then add runtime package lists for what files miss.
How often should the inventory refresh?
Often enough that a new advisory can be matched to a fresh list. For production, tie it to every build.
Safeguard builds SBOMs, scans dependencies, uses reachability analysis to prioritize, and offers asset discovery. You can try a free scan at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.