Unpack is a versatile CLI tool and library for analyzing software components. It goes beyond simple file extraction, providing deep insights into dependencies within codebases, artifacts, and Software Bills of Materials (SBOMs).
Whether you're a developer, security researcher, or compliance officer, Unpack helps you understand the composition of your software.
- Dependency Extraction: Analyzes source code to discover dependencies for various languages.
- Artifact Inspection: Reads the dependency data built into artifacts, such as the module list a Go executable carries, on their own or inside container images.
- SBOM Parsing: Reads and understands major SBOM formats: SPDX 2.2, 2.3 and 3.0.1, and CycloneDX.
- Multiple Output Formats: Displays dependencies as a visual tree or exports to standard SBOM formats.
- Extensible Architecture: Easily extendable to support new languages and package managers.
- Attestation Support: Wraps SBOM outputs in an in-toto attestation for verifiable supply chain security.
Built binaries are available for Linux, macOS, and Windows.
Download the latest prerelease
To install the latest development version directly from the source, use the Go compiler:
go install github.com/carabiner-dev/unpack@mainUnpack provides two main commands: extract and sbom.
Use extract to discover dependencies directly from a source code repository.
Example: Basic Tree View
# Analyze the codebase in the current directory and display a dependency tree
unpack extract .pkg:golang/github.com/carabiner-dev/unpack@v0.1.0-pre3.1+0400cac1
├ pkg:golang/github.com/titanous/rocacheck@v0.0.0-20171023193734-afe73141d399
├ pkg:golang/google.golang.org/protobuf@v1.36.5
│ ├ pkg:golang/github.com/google/go-cmp@v0.5.5
...
Example: Generate an SPDX SBOM
# Output the dependency graph as an SPDX 2.3 JSON file
unpack extract --format=spdx /path/to/your/code > my-project.spdx.json
# ...or as SPDX 3.0.1
unpack extract --format=spdx3 /path/to/your/code > my-project.spdx3.jsonThe output formats are:
--format |
Writes |
|---|---|
tree |
an ASCII dependency tree (the default) |
spdx |
SPDX 2.3, JSON |
spdx3 |
SPDX 3.0.1, JSON-LD |
cyclonedx, cdx |
CycloneDX 1.7, JSON |
Example: Target a Platform
Some ecosystems resolve different dependencies for different platforms.
Python is one: a uv.lock holds the resolution for every environment the
project supports, and the extraction reads it for one.
# What does this project install on an ARM Linux box running Python 3.10?
unpack extract --platform linux/arm64 --python-version 3.10 /path/to/your/codeBy default unpack resolves for the platform it runs on, and for Python, the newest interpreter version the lockfile supports.
Example: Create a Signed Attestation
# Generate an SBOM and wrap it in a signed in-toto attestation.
# Attesting without naming a format writes SPDX 3.0.1.
unpack extract --attest /path/to/your/code
# ...or name the format yourself
unpack extract --attest --format=spdx /path/to/your/codeAttestations are made under the predicate type of what they carry:
https://spdx.dev/Document/v3 for SPDX 3, https://spdx.dev/Document for
SPDX 2, and https://cyclonedx.org/bom for CycloneDX.
Use sbom to read, convert, and re-export existing SBOM files.
# Read an SBOM and display its contents as a tree
unpack sbom -p /path/to/sbom.spdx.json
# Convert an SBOM to CycloneDX
unpack sbom -p /path/to/sbom.spdx.json --format=cyclonedx
# Convert an SPDX 2.3 SBOM to SPDX 3.0.1
unpack sbom -p /path/to/sbom.spdx.json --format=spdx3
# Read an SBOM out of the attestation carrying it
unpack sbom -p /path/to/sbom.intoto.jsonSBOMs often travel wrapped in a security envelope rather than as bare
documents. sbom reads them either way: when the file is not a bill of
materials itself, it is opened as a sigstore bundle, a DSSE envelope or a
plain in-toto statement, and the SBOM is read from the predicate inside.
This makes unpack sbom --attest output readable straight back.
Note that opening an envelope is not verifying it. Signatures travel along
with the statement but sbom does not check them, so the data it returns is
exactly as trustworthy as the file it came from. Verify attestations with a
tool that does before trusting what they carry.
Some components an analysis finds cannot be opened: a binary with no
embedded dependency data, a vendored library, a package the system did not
install. If an SBOM for it exists, hand it to unpack and it is stitched in.
Every command that produces dependency data takes --add-sbom with a file or
a directory of files, in any format unpack sbom reads, bare or enveloped.
# Enrich an image scan with the SBOMs of the binaries it ships
unpack image --add-sbom ./sboms/ -f spdx ghcr.io/example/app:1.2.3
# Complete a shallow SBOM with the documents describing its components
unpack sbom -p app.spdx.json --add-sbom deps/ -f spdxBefore the analysis, the supplements are parsed and the components they describe are remembered by hash and purl. Whenever the analysis finds one of them, the supplement's data goes under it: merged into the component when the two are the same kind of thing, or hung below a file as the package it was generated from. Supplements chain, so a document describing a dependency of another document's subject applies too. Components two supplements both describe are collapsed into one. Every stitched component carries a reference to the document it came from, and supplements that described nothing found are reported.
Use ls to scan a directory and list the codebases found, along with their IDs. These IDs can then be used with the extract command.
Example: List codebases in a directory (table format)
# List all discovered codebases in the current directory
unpack ls .ID LANGUAGE PATH
golang:. golang .
npm:frontend npm frontend
rust:backend/api rust backend/api
Example: List codebases in JSON format
unpack ls --format=json /path/to/projectExample: List codebases ignoring specific patterns
unpack ls --ignore "*/testdata/*" --ignore "temp/" .Some artifacts carry their own dependency data. A Go executable records
the exact modules linked into it, with versions and checksums, and a Rust
executable built with cargo-auditable records its crate graph. artifact
reads them straight out of the file: no source tree, no build.
# Show the module tree built into a Go binary
unpack artifact ./bin/tool
# Scan a release directory; files that are not recognized artifacts are skipped
unpack artifact -f spdx ./dist
# Attest what a binary is made of
unpack artifact --sign -o tool.bundle.json ./bin/toolContainer image scans run the same probe over the image filesystem, so a Go
binary in a distroless image shows up with its modules next to the OS
package inventory. The scan skips the distribution's own directories, such
as /usr/bin and /usr/lib, whose contents belong to the installed packages,
and looks where applications land: /app, /opt, /usr/local, the root.
Use unpack image --no-artifacts to skip the scan, --skip-artifact gobinary
to leave out one kind of artifact, --skip-path to leave out more paths, and
--scan-system-dirs to scan everything.
Unpack includes decomposers for seven package ecosystems. See the decomposer documentation for details. Container image scans additionally report installed Python environments (site-packages) and Composer vendor directories next to the OS package inventory, and the modules built into any Go executable they hold.
| Ecosystem | Lock file | Manifest | Remote enrichment |
|---|---|---|---|
| Go | go.sum |
go.mod |
Go module proxy |
| Maven | (none) | pom.xml |
Maven Central |
| PHP (Composer) | composer.lock |
composer.json |
(none — licenses are in the lock) |
| JavaScript | package-lock.json, pnpm-lock.yaml, yarn.lock |
package.json |
(none) |
| Python | uv.lock, poetry.lock, requirements.txt |
pyproject.toml (poetry) |
PyPI JSON API |
| Ruby (Bundler) | Gemfile.lock |
(not read) | rubygems.org API |
| Rust | Cargo.lock |
Cargo.toml |
crates.io API |
| sbt | (a dependency snapshot, --sbt-snapshot) |
(not read) | (none) |
| Artifact | Reads | Remote enrichment |
|---|---|---|
| Go executables | Embedded build information | Go module proxy + deps.dev |
| Rust executables | The cargo-auditable record | crates.io API |
Support for more ecosystems is planned.
We welcome contributions! Whether it's reporting a bug, suggesting a feature, or submitting a pull request, your feedback is valuable.
- Open an Issue: If you find a problem or have an idea for an improvement, please open a new issue.
- Pull Requests: Feel free to fork the repository and submit a pull request with your changes.
This tool and its libraries are released under the Apache 2.0 License and copyright by Carabiner Systems, Inc. See the LICENSE file for more details. Feel free to open issues to report problems or request features. Patches are welcome!