A Go-based CLI tool to automate the upload and lifecycle management of Software Bill of Materials (SBOM) in OWASP Dependency-Track.
This tool bridges the gap between simple API uploads and full CI/CD lifecycle management by handling version sprawl, active states, and latest version tagging in a single execution.
You can identify a project either by PROJECT_NAME + VERSION or by its stable UUID (via -project). Because the
UUID is stable, it keeps working across project renames: -upload targets the project directly, and
-list/-clean/-latest re-resolve the project's current name from the UUID on each run. Note that the lifecycle
operations (-clean/-latest) then act on every version sharing that resolved name, exactly like name-based mode, the
UUID selects the project, not a narrower scope.
If you simply use curl to upload an SBOM to Dependency-Track, you encounter two major problems over time. These are
well-documented pain points in the community:
Every CI build creates a new version. If you have 100 builds, you have 100 "Active" versions. Dependency-Track monitors all active versions for vulnerabilities, meaning you will receive alerts for vulnerabilities in old, undeployed versions.
- Community Validation: Users have explicitly requested an
isActiveExclusivelyflag to solve this, noting that " Over time there will be hundreds of 'active' versions, even though they are actually not 'active'". - Current Workaround: Teams currently resort to manual housekeeping or complex scripts to set "dirty tags to inactive" to avoid polluting their risk score.
- Our Solution: The
-cleanflag automatically iterates through project versions and sets old ones toactive: false.
Dependency-Track attempts to guess the "latest" version, but it is not always accurate (e.g., when patching older release branches or dealing with pre-releases).
- Community Validation: Users have reported issues where Dependency-Track incorrectly identifies pre-release versions as "latest," skewing "Outdated Component" analysis metrics.
- Our Solution: The
-latestflag explicitly forces the version you are currently uploading to be markedisLatest=true, ensuring your "Outdated Component" metrics are calculated against the correct baseline.
There is no built-in native feature to "keep only the last X versions" or "purge old versions" during upload.
- Community Validation: Feature requests for "automatic purging of projects" have been raised by users who find it " hard to do this manually" for projects with many releases.
- Our Solution: While we don't delete data (auditors hate that!), our tool effectively "archives" old versions by deactivating them, solving the noise issue without destroying history.
Understanding these flags is critical for a clean dashboard:
| Flag | Dependency-Track Meaning | Impact on Pipeline |
|---|---|---|
| Active | Indicates this version is currently deployed/supported. | Critical. Only "Active" versions contribute to Portfolio Metrics and trigger Vulnerability Alerts. |
| Latest | Indicates this is the most current version of the project. | Visual & Analytical. Used as the baseline for "Outdated Component" analysis and marked with a badge in the UI. |
Since this is a single-file Go program, you can run it directly or build a binary.
Run the following command to get the latest release binary:
wget https://raw.githubusercontent.com/MedUnes/dtrack-cli/master/latest.sh && \
chmod +x latest.sh && \
./latest.sh && \
rm ./latest.shgo run main.go -helpgo build -o dtrack-cli main.go
./dtrack-cli -help
Goal: Upload a new SBOM, mark it as the only active version, and tag it as latest.
Use the -ci shortcut flag, which enables -upload, -latest, and -clean simultaneously.
# Syntax: go run main.go [flags] <API_KEY> <PROJECT_NAME> <VERSION>
dtrack-cli -ci -file ./build/bom.json $DT_API_KEY "My-Web-App" "v1.2.0"
What happens:
- Uploads
build/bom.jsonto project "My-Web-App" version "v1.2.0". - Sets
v1.2.0toActive=TrueandIsLatest=True. - Iterates through all other versions (e.g., v1.1.0, v1.0.0) and sets them to
Active=False/IsLatest=False.
Goal: Check what versions exist and when they were uploaded without making changes.
dtrack-cli -list $DT_API_KEY "My-Web-App"
Output:
--- Current Versions ---
VERSION ACTIVE LATEST LAST UPLOAD UUID
v1.2.0 true true 2023-10-25 14:30 abc-123...
v1.1.0 false false 2023-10-20 10:00 def-456...
------------------------
Goal: You uploaded a hotfix for an older version (v1.0.1) and want to mark it as Active, but you do not want
it to become the "Latest" version (because v2.0 already exists).
Use specific flags instead of -ci.
# Upload and Clean (deactivate others), but do NOT touch the 'Latest' flag
dtrack-cli -upload -clean $DT_API_KEY "My-Web-App" "v1.0.1"
Goal: Your dashboard is cluttered with 50 old versions. You want to keep v2.0 as the only active one, but you
don't have the SBOM file handy to re-upload.
# Just clean up the metadata
dtrack-cli -clean -latest $DT_API_KEY "My-Web-App" "v2.0"
Goal: An upload or lookup is failing in a way that isn't obvious, perhaps the base URL is wrong, an upstream proxy
is rewriting requests, or the server is responding with HTML instead of JSON. Reach for -verbose to surface the actual
request URL, response status, and a body preview (first 512 bytes).
dtrack-cli -verbose -list $DT_API_KEY "My-Web-App"
Example output:
[verbose] → GET https://dtrack.example.com/api/v1/project?excludeInactive=false&name=My-Web-App&pageNumber=1&pageSize=50
[verbose] ← 200 OK
[verbose] Body (preview): [{"uuid":"abc-123","name":"My-Web-App","version":"v1.2.0",...}]
Goal: Identify the project by its UUID instead of PROJECT_NAME + VERSION. This is handy when a project may be
renamed, or when your pipeline already stores the UUID. The UUID identifies one specific version, so only the API_KEY
positional argument is needed.
# Upload by UUID (no name/version needed), sends the BOM with project=<uuid>
dtrack-cli -upload -project abc-123-def -file ./build/bom.json $DT_API_KEY
# Full CI mode by UUID (upload + latest + clean)
dtrack-cli -ci -project abc-123-def -file ./build/bom.json $DT_API_KEY
# List sibling versions (resolves UUID -> project name, then lists all versions)
dtrack-cli -list -project abc-123-def $DT_API_KEY
# Clean + latest by UUID
dtrack-cli -clean -latest -project abc-123-def $DT_API_KEYFor -list / -latest / -clean, the tool first calls GET /api/v1/project/<uuid> to resolve the UUID into the
project's name and version, then runs the usual name-based list/patch flow, so these lifecycle operations still act on
all versions sharing that name (see the note in the intro). If you also pass positional PROJECT_NAME/VERSION
alongside -project, they are ignored (with a warning).
| Flag | Description | Requirement |
|---|---|---|
-upload |
Uploads the file specified by -file. |
Requires VERSION argument. |
-list |
Displays a table of all versions for this project. | |
-latest |
Marks the target version as isLatest=true and unsets it for others. |
Requires VERSION argument. |
-clean |
Marks the target version as active=true and all others as active=false. |
Requires VERSION argument. |
-ci |
Recommended. Shortcut for -upload -latest -clean. |
Requires VERSION argument. |
-url |
Base URL of your Dependency-Track instance. Trailing slashes are stripped. | Default: https://dtrack.example.com |
-file |
Path to the SBOM file. | Default: sbom.json |
-verbose |
Prints HTTP request/response details (method, URL, status, body preview) for debugging. | Optional, additive to any other flag. |
-project |
Identify the project by UUID instead of PROJECT_NAME + VERSION. When set, the positional name/version are ignored. |
Replaces the PROJECT_NAME/VERSION positionals. |
- Go 1.21+ (uses
slicesandcmppackages). - Network: Access to the Dependency-Track API.
- Permissions: The API Key used must have
BOM_UPLOADandPROJECT_CREATION_UPLOADpermissions.
make build: produce the static binary.make test: rungo test -v -race ./....
- Dependency Track REST API documentation https://docs.dependencytrack.org/integrations/rest-api/