|
| 1 | +--- |
| 2 | +title: "Working with SBOMs" |
| 3 | +description: "Manage software dependencies and SBOMs as Locations" |
| 4 | +audience: pro |
| 5 | +weight: 5 |
| 6 | +--- |
| 7 | + |
| 8 | +DefectDojo Pro models software libraries as **Dependency Locations**. A Dependency is a Location subtype identified by a [Package URL (pURL)](https://github.com/package-url/purl-spec) and intended to represent a single library or package — `org.apache.logging.log4j:log4j-core@2.17.0`, `pypi/django@5.0.2`, `npm/react@18.2.0`, and so on. |
| 9 | + |
| 10 | +Dependencies replace the previous **Components** model, which was attached only to Findings. With Locations, libraries can exist independently of any vulnerability — you can upload an SBOM to an Asset and then let Findings auto-attach to the dependencies they reference as scans come in. |
| 11 | + |
| 12 | +## What a Dependency Holds |
| 13 | + |
| 14 | +Every Dependency is uniquely identified by a pURL, decomposed into atomic fields you can search and filter on: |
| 15 | + |
| 16 | +| Field | Meaning | Example | |
| 17 | +| --- | --- | --- | |
| 18 | +| `purl_type` | Library ecosystem | `npm`, `pypi`, `maven`, `cargo`, `nuget`, `gem` | |
| 19 | +| `namespace` | Vendor or organisation | `org.apache.logging` | |
| 20 | +| `name` | Library name | `log4j-core` | |
| 21 | +| `version` | Specific version | `2.17.0` | |
| 22 | +| `qualifiers` *(optional)* | Implementation details | `arch=amd64` | |
| 23 | +| `subpath` *(optional)* | Path within an archive or monorepo | `src/lib/foo` | |
| 24 | +| `artifact_hashes` *(optional)* | Fingerprints | SHA256 sums | |
| 25 | +| `license_expression` *(optional)* | SPDX license expression | `Apache-2.0`, `MIT` | |
| 26 | +| `file_path` *(optional)* | Where the library was found in the project | `package-lock.json` | |
| 27 | + |
| 28 | +This atomic decomposition is what makes pURL-based search useful: you can ask *"all `pypi` packages in the `django` namespace at version 4.x"* and DefectDojo can answer that without parsing a free-text string. |
| 29 | + |
| 30 | +## Owned-By vs Used-By |
| 31 | + |
| 32 | +When a Dependency is associated with an Asset, the Asset Reference carries an optional **relationship** describing *how* the library belongs to the Asset: |
| 33 | + |
| 34 | +- **`owned_by`** — *"this library is owned by this Asset"*. Use this for first-party libraries an Asset publishes or maintains. |
| 35 | +- **`used_by`** — *"this library is used by this Asset"*. Use this for third-party dependencies an Asset consumes. |
| 36 | + |
| 37 | +The same library can be `owned_by` one Asset and `used_by` several others, which is exactly the relationship you need to answer *"who consumes the package my team publishes?"* during vulnerability triage. |
| 38 | + |
| 39 | +## Uploading an SBOM |
| 40 | + |
| 41 | +To populate Dependencies in bulk, upload an SBOM file against a Product. The endpoint is: |
| 42 | + |
| 43 | +``` |
| 44 | +POST /api/v2/sbom-import/ |
| 45 | +``` |
| 46 | + |
| 47 | +| Field | Description | |
| 48 | +| --- | --- | |
| 49 | +| `product` | The target Product (Asset) ID | |
| 50 | +| `file` | The SBOM file | |
| 51 | +| `scan_type` | The SBOM format — see supported formats below | |
| 52 | +| `replace` *(optional)* | If `true`, stale Product associations not backed by an existing Finding reference are removed. Default: `false` (cumulative) | |
| 53 | + |
| 54 | +The importer parses the file, extracts `Dependency` records, deduplicates them against existing Locations (creating new ones as needed), and creates Asset References linking each Dependency to the Product. The Pro UI exposes the same upload flow — see the **Upload SBOM** action on a Product's Locations tab. |
| 55 | + |
| 56 | +### Supported Formats |
| 57 | + |
| 58 | +The MVP ships parsers for the two dominant SBOM formats: |
| 59 | + |
| 60 | +- **CycloneDX** — JSON and XML |
| 61 | +- **SPDX** — JSON (v2 and v3), XML, and tag-value |
| 62 | + |
| 63 | +SWID Tag format is not yet supported. |
| 64 | + |
| 65 | +### Replace vs Append |
| 66 | + |
| 67 | +By default, repeated uploads are **additive**: dependencies that already exist on the Asset are kept, new ones are added, and nothing is removed. This matches the typical workflow of incremental SBOM updates. |
| 68 | + |
| 69 | +Set `replace=true` to prune. When replace mode is on, after a successful import the importer removes Product associations that were not present in the new SBOM **and** are not currently referenced by an active Finding. References tied to active Findings are preserved even in replace mode, so you do not lose vulnerability context just because a new SBOM omits a package. |
| 70 | + |
| 71 | +## Findings That Reference Libraries |
| 72 | + |
| 73 | +When a parser ingests a vulnerability tied to a library — for example, an SCA tool reporting `CVE-2021-44228` against `log4j-core@2.14.1` — the importer: |
| 74 | + |
| 75 | +1. Looks up an existing Dependency Location by pURL, or creates a new one. |
| 76 | +2. Creates a `LocationFindingReference` linking the Finding to the Dependency with status **Active**. |
| 77 | +3. Creates a `LocationProductReference` so the Dependency also appears on the parent Product, if it isn't already. |
| 78 | + |
| 79 | +Because Findings and SBOM uploads share the same underlying Dependency objects, a Finding ingested *before* an SBOM upload will be retroactively visible in the SBOM view, and vice versa. |
| 80 | + |
| 81 | +## REST API |
| 82 | + |
| 83 | +| Task | Endpoint | |
| 84 | +| --- | --- | |
| 85 | +| Upload an SBOM | `POST /api/v2/sbom-import/` | |
| 86 | +| List Dependencies | `GET /api/v2/dependencies/` | |
| 87 | +| Create a Dependency manually | `POST /api/v2/dependencies/` | |
| 88 | +| List Dependency Locations | `GET /api/v2/location/?location_type=dependency` | |
| 89 | +| Link a Dependency to a Finding | `POST /api/v2/location_findings/` | |
| 90 | +| Link a Dependency to a Product (with `owned_by` / `used_by`) | `POST /api/v2/location_products/` | |
| 91 | + |
| 92 | +Filters on `/api/v2/dependencies/` include the pURL component fields, tags, and ordering on `name`, `version`, and active-finding count. |
| 93 | + |
| 94 | +## In the Pro UI |
| 95 | + |
| 96 | +When Locations is enabled, the navigation exposes: |
| 97 | + |
| 98 | +- **Locations / Dependencies** — Global list of every Dependency across the instance, with pURL filters. |
| 99 | +- **Locations on a Product/Asset** — Per-Asset view that shows both URLs and Dependencies, with the **Upload SBOM** action surfaced on the Dependencies tab. |
| 100 | +- **New Dependency** — Form to create a single library by entering its pURL components manually. |
| 101 | +- **Findings detail** — A Finding that touches a library shows its Dependency Locations alongside any URL Locations, so you can see *"this CVE affects `log4j-core@2.14.1` on Asset 6 and Asset 9"* in one place. |
| 102 | + |
| 103 | +## What's Not in the MVP |
| 104 | + |
| 105 | +- **SWID Tag SBOM format** — Not parsed. CycloneDX or SPDX is required. |
| 106 | +- **License risk scoring** — The `license_expression` field is captured when present in the SBOM, but DefectDojo does not yet flag findings on license incompatibility. License-based reporting is on the roadmap as a follow-up to the Locations MVP. |
| 107 | +- **Container image and cloud resource Locations** — Future Location subtypes. For now, libraries discovered inside a container image are recorded as Dependencies; the container image itself is not yet a first-class Location. |
0 commit comments