Skip to content

Use the Docker image directly

For everyday use we recommend the scan-sbom.sh script, which handles language detection, image selection, and volume mounts for you. This document explains how to call the image directly with docker run in environments where the script cannot live (CI runners, Kubernetes jobs, and so on).

Images and tags

Image Purpose
ghcr.io/sktelecom/bomlens Scanning and post-processing (canonical name)
ghcr.io/sktelecom/sbom-generator, ghcr.io/sktelecom/sbom-scanner Aliases of the same image (former names, same digest)
ghcr.io/sktelecom/bomlens-firmware Firmware analysis (includes GPL tools, opt-in) (legacy alias: sbom-scanner-firmware)
ghcr.io/sktelecom/bomlens-deep-cve Bundles grype for deep CVE matching (opt-in). Used by the CLI's --deep-cve and by the web UI's Deep CVE matching toggle, both of which pull it automatically as a sibling container when it is not already the running image
ghcr.io/sktelecom/bomlens-aibom Generates an AI-model ML-BOM (opt-in, legacy alias: sbom-scanner-aibom). Used by --model/--model-file and the web UI's AI model tile, pulled automatically as a sibling container

latest and version tags are available. All published images (ghcr.io/sktelecom/bomlens, bomlens-firmware, bomlens-deep-cve, bomlens-aibom, and their aliases) support both linux/amd64 and linux/arm64, so pulling any of them on an arm64 host (an Apple Silicon Mac, an Arm server) works natively. Images are signed with cosign before publishing.

docker pull ghcr.io/sktelecom/bomlens:latest

What is in the image

It is a lightweight image (based on python 3.12 slim) without language toolchains. For source scans, transitive dependency resolution is handled by the script, which pulls per-language cdxgen images separately. See Architecture for the structure.

Tool Version Role
syft v1.51.0 Scans images, binaries, and directories
Trivy v0.74.0 Vulnerability report
cosign v3.1.3 SBOM signing
jq SBOM normalization and notice generation
ScanCode Toolkit 32.5.0 Precise license detection (included only in opt-in builds)
docker CLI 29.7.2 Starts a sibling cdxgen container when the web UI runs a source scan
cdxgen 12.8.4 Model pedigree enrichment (bomlens-aibom image only)

Tool versions are pinned with ARG in docker/Dockerfile.

Running directly

Select the analysis mode with the MODE environment variable. All examples below leave their outputs in the current directory and do not upload anything (UPLOAD_ENABLED=false).

Analyze a Docker image

On Git Bash (Windows), MSYS rewrites both /var/run/docker.sock and the container-side /host-output into Windows paths before Docker ever sees them, silently breaking both mounts. MSYS_NO_PATHCONV and MSYS2_ARG_CONV_EXCL below turn that rewriting off, and cygpath -m converts the host side back by hand instead (scripts/scan-sbom.sh uses the same pair for the same reason). WSL2, macOS and Linux shells don't rewrite paths and skip straight to the plain docker run line.

HOSTPATH="$(cygpath -m "$(pwd)" 2>/dev/null || pwd)"
MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' docker run --rm \
  -v "$HOSTPATH":/host-output \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e MODE=IMAGE \
  -e TARGET_IMAGE="nginx:alpine" \
  -e UPLOAD_ENABLED=false \
  -e HOST_OUTPUT_DIR=/host-output \
  -e PROJECT_NAME="Nginx" \
  -e PROJECT_VERSION="alpine" \
  ghcr.io/sktelecom/bomlens:latest

Analyze a binary file

HOSTPATH="$(cygpath -m "$(pwd)" 2>/dev/null || pwd)"
MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' docker run --rm \
  -v "$HOSTPATH":/target \
  -v "$HOSTPATH":/host-output \
  -e MODE=BINARY \
  -e TARGET_FILE=/target/firmware.bin \
  -e UPLOAD_ENABLED=false \
  -e HOST_OUTPUT_DIR=/host-output \
  -e PROJECT_NAME="Firmware" \
  -e PROJECT_VERSION="1.0" \
  ghcr.io/sktelecom/bomlens:latest

Analyze a source directory

HOSTPATH="$(cygpath -m "$(pwd)" 2>/dev/null || pwd)"
MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' docker run --rm \
  -v "$HOSTPATH":/src \
  -v "$HOSTPATH":/host-output \
  -e MODE=SOURCE \
  -e UPLOAD_ENABLED=false \
  -e HOST_OUTPUT_DIR=/host-output \
  -e PROJECT_NAME="MyApp" \
  -e PROJECT_VERSION="1.0.0" \
  ghcr.io/sktelecom/bomlens:latest

In direct runs, SOURCE mode has syft read the package manifests inside the container, so it may only capture direct dependencies. If you need transitive dependencies, use scan-sbom.sh, which routes to the per-language cdxgen images. Syft's manifest readers need a lockfile (package-lock.json, npm-shrinkwrap.json, yarn.lock, pnpm-lock.yaml for Node, and the equivalent for other ecosystems) to resolve any of a project's declared dependencies; without one, direct-run SOURCE mode has nothing to read and the scan fails with guidance rather than reporting an empty result as complete.

Notice and reports in one run

In direct runs, the notice and security reports are off by default. Turn on the following variables to get the same outputs as the CLI's --all.

HOSTPATH="$(cygpath -m "$(pwd)" 2>/dev/null || pwd)"
MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' docker run --rm \
  -v "$HOSTPATH":/host-output \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e MODE=IMAGE \
  -e TARGET_IMAGE="nginx:alpine" \
  -e GENERATE_NOTICE=true \
  -e GENERATE_SECURITY=true \
  -e GENERATE_REPORT=true \
  -e UPLOAD_ENABLED=false \
  -e HOST_OUTPUT_DIR=/host-output \
  -e PROJECT_NAME="Nginx" \
  -e PROJECT_VERSION="alpine" \
  ghcr.io/sktelecom/bomlens:latest

Environment variables

Variable Required Default Description
MODE No POSTPROCESS Analysis mode: SOURCE, IMAGE, BINARY, ROOTFS, FIRMWARE, ANALYZE. Left unset, the container only post-processes an SBOM already sitting in the output directory — set it explicitly to actually scan something.
PROJECT_NAME Yes Project name
PROJECT_VERSION Yes Project version
TARGET_IMAGE Per mode Image name for IMAGE mode (requires the docker.sock mount)
TARGET_FILE Per mode File path for BINARY/FIRMWARE mode (path inside the container)
TARGET_DIR Per mode Directory path for ROOTFS mode
UPLOAD_ENABLED true If false, save locally without uploading (same as CLI --generate-only)
HOST_OUTPUT_DIR Mounted path to copy the outputs to
GENERATE_NOTICE false Generate the open-source notice (CLI --notice)
GENERATE_SECURITY false Generate the Trivy security report (CLI --security)
GENERATE_REPORT false Generate the open-source risk analysis report (off in direct runs, unlike the CLI default)
ENRICH_MAVEN_CPE true Attach an NVD-matchable cpe:2.3 to maven components (derived from the groupId) so a CPE-aware engine can reach their NVD-only CVEs; unmapped groups get no CPE (skipped for AI SBOMs)
ENRICH_GITHUB_CPE true Attach an NVD-matchable cpe:2.3 to a small, hand-verified set of pkg:github/ components (source-repository-only coordinates, typical for large C/C++ projects with no package-manager ecosystem) so a CPE-aware engine can reach their NVD-only CVEs; anything not in the curated list gets no CPE (skipped for AI SBOMs)
ENRICH_INTERPRETER_CPE true Attach an NVD-matchable cpe:2.3 to a small, hand-verified set of interpreter components (e.g. Python packaged as a conda or NuGet artifact) so a CPE-aware engine can reach their NVD-only CVEs; anything not in the curated list gets no CPE (skipped for AI SBOMs)
SECURITY_NVD_VERIFY false With --deep-cve: verify each grype nvd:cpe finding against the live NVD version range and drop out-of-range false positives (needs NVD_API_KEY + network; adds minutes). Off by default — findings are kept and flagged version-unverified
NVD_API_KEY For SECURITY_NVD_VERIFY NVD API key used by the deep-cve version filter; passed to the container by name only (never inlined)
ENRICH_EOL true Flag components past their upstream end-of-life from a bundled offline snapshot (skipped for AI SBOMs)
ENRICH_MALICIOUS true Flag components that are known-malicious packages (typosquats, hijacked accounts) from a bundled offline OSV snapshot. A separate signal from vulnerabilities: the response is removal and credential rotation, not an upgrade
ENRICH_OS_CONTEXT true Synthesize an operating-system component from distro package PURLs (rpm, deb, and apk). Trivy selects the distro vulnerability feed from that component, so without it the OS packages in a supplier SBOM or rootfs scan would get no OS CVE matches at all. No-op when the SBOM has no recognizable distro packages — including a distro Trivy carries no feed for, such as OpenWRT (skipped for AI SBOMs)
ENRICH_DISTRO_SUPPLIER true Fill supplier on an rpm, deb, or apk component with the distro project's name, read from the operating-system component ENRICH_OS_CONTEXT synthesizes. Left blank for a distro with no confirmed supplier name, an ambiguous (mixed-distro) SBOM, or a component that already carries a supplier (skipped for AI SBOMs)
STALENESS_ENRICH false Add deps.dev version currency (how many releases behind latest); needs network access
ENRICH_HF_SECURITY true AIBOM mode: read HuggingFace's per-file security scan results (ClamAV + picklescan) into the ML-BOM; metadata only, no file download
API_KEY, API_URL For uploads Upload credential and server URL. DT uses X-Api-Key; TRUSCA uses a Bearer token
UPLOAD_TARGET dependency-track Upload destination: dependency-track (DT-compatible) or trusca (native ingest, not DT-compatible)
TRUSCA_PROJECT_ID When trusca Target TRUSCA project id (UUID). Must already exist (no auto-create)
TRUSCA_REF main Ingest ref label
TRUSCA_RELEASE PROJECT_VERSION Ingest release label
BOMLENS_MAVEN_FULL_GRAPH Maven source scans: set 1 to keep the full resolved graph instead of filtering to compile/runtime scope
BOMLENS_NODE_FULL_GRAPH Node.js source scans: set 1 to keep the full dev-plus-production graph instead of the production-only set
BOMLENS_ANDROID_FULL_GRAPH - - Android source scans (Android SDK image): set 1 to keep the full graph, build and test tooling included, instead of filtering to the release runtime classpath
BOMLENS_PHP_FULL_GRAPH - - PHP (Composer) source scans: set 1 to keep the full require-plus-require-dev graph instead of filtering to the required set
BOMLENS_KEEP_BUILD_OUTPUT Source scans: set 1 to leave the resolved tree in place. By default the scan restores the files its resolvers rewrote (go.mod, go.sum, Cargo.lock, Gemfile.lock, Package.resolved) and removes the build directories they created, so the scanned project is handed back as it was
BOMLENS_PREP_TIMEOUT - 900 (1800 for Gradle/Android steps) Seconds a single dependency-resolution step (Cargo, Go, Bundler, pip, npm, Swift, Gradle/Android) is allowed to run before it is stopped and the scan moves on without it. Set to override both defaults for every step. A step that fails or times out is logged with its own output and recorded on the SBOM as bomlens:pipeline-step-failed; the scan itself still completes
BOMLENS_CANCEL_GRACE 30 Seconds a cancelled scan (CLI Ctrl+C, or the web UI's cancel button) gets to stop cleanly before it is force-stopped. Applies to the CLI and --ui; the desktop app always uses the default
BOMLENS_INCLUDE_NON_SHIPPED - - Source scans: set 1 to keep the manifests under test, example, benchmark and demo folders and the GitHub Actions workflows in .github/workflows, which are left out by default
CYCLONEDX_SPEC_VERSIONS 1.3 1.4 1.5 1.6 Accepted CycloneDX spec versions for the conformance check (space-separated); overrides the default range
AI_CYCLONEDX_SPEC_VERSIONS 1.3 1.4 1.5 1.6 1.7 Accepted CycloneDX versions for AI SBOMs (ML-BOM), which additionally allow 1.7
SPDX_SPEC_VERSIONS SPDX-2.2 SPDX-2.3 Accepted SPDX spec versions for the conformance check
PURL_MIN_PCT 90 Conformance check: minimum percentage of components with a PURL (mandatory check). Applies to a --deep-cve scan too, CLI or web UI
LICENSE_MIN_PCT 80 Conformance check: minimum percentage of components with a license (recommended, warn only). Applies to a --deep-cve scan too, CLI or web UI
HASH_MIN_PCT 50 Conformance check: minimum percentage of components with a hash (recommended, warn only). Applies to a --deep-cve scan too, CLI or web UI
FIELD_MIN_PCT 80 Conformance check: minimum percentage coverage for advisory per-component regulatory fields. Applies to a --deep-cve scan too, CLI or web UI

TRUSCA's (formerly TrustedOSS Portal) native ingest endpoint (POST /v1/projects/{id}/sbom-ingest, Bearer auth) is not Dependency-Track compatible. To push to a regular Dependency-Track server, keep UPLOAD_TARGET=dependency-track (the default).

For the full mapping between CLI flags and environment variables, see the flag mapping in Architecture.

Building and publishing the image

The procedure for building the image yourself or publishing it for multiple platforms is in the contributor-facing docker/README.


Related: Getting started | CLI reference | Architecture