Bazel tool Overview
Detect provides limited support for Bazel projects using the updated Bazel tool. The Bazel tool is mode-agnostic and works seamlessly with both BZLMOD (MODULE.bazel) and WORKSPACE-based projects.
The Bazel tool discovers dependencies from the following dependency sources:
maven_jar - Legacy Maven dependencies
maven_install - Modern Maven dependencies via rules_jvm_external
haskell_cabal_library - Haskell Cabal packages
http_archive - Source archives from HTTP, Git, and other sources
The Bazel tool discovers library dependencies that have a GitHub released artifact location (URL) specified in an http_archive, go_repository, or git_repository rule.
Features
Mode-Agnostic: Automatically detects whether your project uses BZLMOD or WORKSPACE and adapts accordingly
Mode Detection Strategy: Uses
bazel mod graphto detect BZLMOD support; falls back to WORKSPACE mode for older Bazel versions (< 6.0)Automatic Pipeline Selection: Probes your Bazel dependency graph to determine which dependency sources are present and automatically runs the correct extraction pipelines
HTTP Detection Strategy:
For BZLMOD projects: Uses
bazel mod show_repoto robustly extract dependency URLs from external repositoriesFor WORKSPACE projects: Uses XML parsing to extract URLs from repository rules
HTTP Detection Strategy: Small/medium targets (≤150 external repos) are fully probed for precise detection. Large projects (>150 repos) automatically enable the HTTP pipeline to ensure completeness without probing overhead.
Supported Bazel Versions
Bazel 8.x: Fully supported
Bazel 7.x: Fully supported; Bzlmod is default and
bazel modcommands are stableBazel 6.4–6.9: Supported; Bzlmod supported with mature
modsubcommandsBazel 6.0–6.3: Limited support for Bzlmod (see note below)
Bazel 5.x and earlier: WORKSPACE mode only; Bzlmod features unavailable
Minimum version for Haskell Cabal: Bazel 2.1.0+
BCR Modules and Dependency Classification
Bazel supports several mechanisms for consuming external dependencies, which differ in the amount of dependency metadata and relationship information available to Detect and affects how Detect can classify dependencies as direct or transitive.
WORKSPACE-Based http_archive, git_repository, and go_repository
External source code is fetched directly into the build environment. These rules provide no dependency relationship metadata beyond the declarations present in the WORKSPACE file. All dependencies must be explicitly declared by the project as Bazel does not maintain a dependency graph for these repository types. The resulting dependency list is inherently flat, with no parent-child relationships available for analysis or reconstruction. As a result, Detect can identify these dependencies but reports all of them as direct dependencies.
Maven Dependencies via rules_jvm_external
Projects that use maven_install from rules_jvm_external rely on Maven's dependency resolution model. The complete dependency graph exists internally within the resolver and its lockfile infrastructure, however that information is not exposed through Bazel's module graph APIs.
Detect can extract Maven coordinates from the Bazel build configuration, but it cannot accurately determine dependency ancestry. Dependencies obtained through maven_install are therefore reported as a flat list rather than a hierarchical dependency tree.
Bazel Central Registry (BCR) Modules (bazel_dep in MODULE.bazel)
Dependencies declared with bazel_dep in MODULE.bazel provide the most complete dependency metadata available within Bazel. Modules published to the Bazel Central Registry (BCR) include their own MODULE.bazel that declares their own direct dependencies, following the same dependency management model used by Maven, npm, and Cargo. Beginning with Bazel 7.1, Bazel resolves the full transitive graph by reading each module's MODULE.bazel recursively and exposes the result via bazel mod graph --output json, which includes explicit parent-child relationships between modules. Detect consumes this data to accurately classify dependencies as either direct or transitive when generating a Bill of Materials (BOM).
For Bzlmod-based projects running Bazel 7.1 or later, Detect first executes bazel mod graph to obtain the complete module dependency hierarchy. Detect then invokes bazel mod show_repo for each module to resolve repository source locations and associated metadata.
Dependencies discovered via maven_install and http_archive are incorporated into the same BOM, however, because these dependency types do not expose equivalent graph information through Bazel, they are reported as flat dependency sets.
Combining Bazel Detection with Package Manager Detection for Additional Coverage
As a best practice, projects built with Bazel should not rely solely on the Bazel detector to produce a complete result. Bazel and package managers operate at different layers of the software supply chain, so Detect evaluates them independently to ensure comprehensive coverage.
Bazel Detection vs Package Manager Detection
The Bazel detector identifies Bazel-level dependencies: external repositories
and modules that Bazel resolves during the build, such as http_archive,
git_repository, go_repository, maven_install, and similar rules. For each
discovered repository, it attempts to extract a URL and match it against the
Black Duck Knowledge Base.
Package manager detectors identify ecosystem-level dependencies by parsing
manifest files: pom.xml, package.json, requirements.txt, go.mod,
Cargo.lock, Gemfile.lock, packages.config, and others. These detectors
operate on file content regardless of whether the project uses Bazel.
A Bazel external repository represents an archived bundle of source code. This archive can include package manager metadata for one or more ecosystems. The Bazel detector identifies the archive itself as a dependency, while package manager detectors analyze its contents to identify any supported manifest-based dependencies contained within.
Your Bazel target
└── @protobuf//:lib ← Bazel detector: matches via GitHub URL → KB entry
└── java/pom.xml ← Maven detector: discovers Java deps from manifest
└── python/setup.py ← PIP detector: discovers Python deps from manifest
└── js/package.json ← NPM detector: discovers JS deps from manifest
└── @internal_lib//:lib ← Bazel detector: private URL, no KB match
└── requirements.txt ← PIP detector: discovers Python deps inside the archive
└── go.mod ← Go detector: discovers Go deps inside the archiveIn this example, running only the Bazel detector identifies a single component
(protobuf), matched through its public GitHub repository. When both Bazel and
package manager detectors are used, the analysis includes protobuf along with
additional ecosystem-level dependencies discovered from supported manifests within
the repository. This combined approach also reveals content from @internal_lib
that would not be detected by the Bazel detector alone.
It is therefore expected that a Bazel-only scan will identify fewer components than a combined scan. This difference does not indicate missing Bazel dependencies. Rather, it reflects the ability of package manager detectors to identify additional ecosystem-specific components within Bazel-managed repositories. The extent of coverage depends on the ecosystems supported by Detect, the presence of manifest files within retrieved archives, and the configured search depth.
For a more complete dependency inventory, enable both:
bash <(curl -s -L https://detect.blackduck.com/detect11.sh) \
--detect.tools=BAZEL,DETECTOR \
--detect.bazel.target='//myproject:mytarget' \
--detect.detector.search.depth=5Using Bazel Fetch for Additional Coverage
The Bazel detector extracts URLs from standard repository rules (http_archive,
git_repository, go_repository). Environments that use custom repository
macros, private registry infrastructure, or other abstractions that do not
surface standard URLs through Bazel metadata will see reduced coverage from the
Bazel detector alone. The archives are fetched correctly by Bazel but their
URLs are not extractable by Detect.
In these environments, a bazel fetch workflow can provide additional coverage
by materializing external repositories on disk and allowing package manager
detectors to analyze their contents directly:
# Step 1: Fetch and extract all external dependencies for a target
bazel --output_base=/your/scan/dir/target_name fetch //your:target
# Step 2: Run Detect with DETECTOR against the extracted sources
bash <(curl -s -L https://detect.blackduck.com/detect11.sh) \
--detect.tools=DETECTOR \
--detect.source.path=/your/scan/dir/target_name/external/ \
--detect.detector.search.depth=5 \
--detect.accuracy.required=NONEThis approach enables the identification of ecosystem-level dependencies within extracted archives for supported ecosystems where manifest files are present. However, coverage is not guaranteed for all archives. Repositories that do not contain supported manifest files will not produce additional results, and the size of fetched sources may vary significantly depending on the target's dependency graph.
For environments where per-target isolation is needed, use --output_base to
scope the fetch to a directory of your choice:
# Each target gets its own output base; only that target's deps land there
bazel --output_base=/scan/firmware_ecu fetch //firmware:ecu_target
bazel --output_base=/scan/firmware_net fetch //firmware:net_targetUsage
Tool invocation:
The Bazel tool runs automatically when enabled via the detect.tools property. Ensure your configuration includes --detect.tools=BAZEL.
Requirements:
The
--detect.bazel.targetproperty to specify the Bazel build targetThe
bazelexecutable must be available on your$PATH
Basic Example
bash <(curl -s -L https://detect.blackduck.com/detect11.sh) \
--detect.tools=BAZEL \
--detect.bazel.target='//myproject:mytarget'Pipeline Details
The following example shows command-line invocations equivalent to those the Bazel tool uses to identify components.
Processing for the maven_install workspace rule
The Bazel tool runs a Bazel cquery on the given target to produce output from which it can parse artifact details such as group, artifact, and version for dependencies.
Detect's Bazel tool uses commands similar to the following for discovery of maven_install dependencies:
$ bazel cquery --noimplicit_deps 'kind(j.*import, deps(//tests/integration:ArtifactExclusionsTest))' --output build 2>&1 | grep maven_coordinates
tags = ["maven_coordinates=com.google.guava:guava:27.0-jre"],
tags = ["maven_coordinates=org.hamcrest:hamcrest:2.1"],
tags = ["maven_coordinates=org.hamcrest:hamcrest-core:2.1"],
tags = ["maven_coordinates=com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava"],
tags = ["maven_coordinates=org.checkerframework:checker-qual:2.5.2"],
tags = ["maven_coordinates=com.google.guava:failureaccess:1.0"],
tags = ["maven_coordinates=com.google.errorprone:error_prone_annotations:2.2.0"],
tags = ["maven_coordinates=com.google.code.findbugs:jsr305:3.0.2"],Then, it parses the group/artifact/version details from the values of the maven_coordinates tags.
Processing for the maven_jar workspace rule
The Bazel tool runs a Bazel query on the given target to get a list of jar dependencies. On each jar dependency, the Bazel tool runs another Bazel query to get its artifact details: group, artifact, and version.
Get list of dependencies:
$ bazel cquery 'filter("@.*:jar", deps(//:ProjectRunner))'
INFO: Invocation ID: dfe8718d-b4db-4bd9-b9b9-57842cca3fb4
@org_apache_commons_commons_io//jar:jar
@com_google_guava_guava//jar:jar
Loading: 0 packages loadedGet details for each dependency, prepending //external: to the dependency name for this command:
$ bazel query 'kind(maven_jar, //external:org_apache_commons_commons_io)' --output xml
INFO: Invocation ID: 0a320967-b2a8-4b36-ab47-e183bc4d4781
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<query version="2">
<rule class="maven_jar" location="/root/home/steve/examples/java-tutorial/WORKSPACE:6:1" name="//external:org_apache_commons_commons_io">
<string name="name" value="org_apache_commons_commons_io"/>
<string name="artifact" value="org.apache.commons:commons-io:1.3.2"/>
</rule>
</query>
Loading: 0 packages loadedFinally, it parses the group/artifact/version details from the value of the string element using the name of artifact.
Processing for the haskell_cabal_library workspace rule
Requires Bazel 2.1.0 or later.
Detect's Bazel tool extracts artifact project and version for dependencies by running a Bazel cquery on the given target.
The Bazel tool uses a command similar to the following to discover haskell_cabal_library dependencies:
$ bazel cquery --noimplicit_deps 'kind(haskell_cabal_library, deps(//cat_hs/lib/args:args))' --output jsonproto
{
"results": [{
"target": {
"type": "RULE",
"rule": {
...
"attribute": [{
...
}, {
"name": "name",
"type": "STRING",
"stringValue": "hspec",
"explicitlySpecified": true,
"nodep": false
}, {
"name": "version",
"type": "STRING",
"stringValue": "2.7.1",
"explicitlySpecified": true,
"nodep": false
}, {
...It then uses Gson to parse the JSON output into a parse tree, extracting the name and version from the corresponding rule attributes.
Processing for the http_archive workspace rule
The Bazel tool probes the Bazel dependency graph to determine if http_archive dependencies are present and then triggers the appropriate pipeline based on the Bazel era:
For bzlmod projects:
The tool uses
bazel mod show_repoto extract repository information and candidate GitHub URLs for external dependencies.Leverages Bazel's module system to accurately identify external dependencies and their sources.
Example command (run for each external repo):
$ bazel mod show_repo <repo_name> # Output includes repository details, including URLsThe tool parses the output to extract GitHub URLs and version information for each dependency.
For WORKSPACE-based projects:
The tool uses
bazel queryand XML parsing to extract URLs fromhttp_archive,go_repository, andgit_repositoryrules. Only URLs matching GitHub release/archive patterns are considered.Example commands:
# Get a list of external library dependencies $ bazel query 'kind(.*library, deps(//:bd_bazel))' # For each dependency, get details (example for http_archive): $ bazel query 'kind(.*, //external:com_github_gflags_gflags)' --output xmlThe tool parses the XML output to extract the GitHub URL and version for each dependency.
This dual approach ensures that the Bazel tool works seamlessly for both modern bzlmod-based and traditional WORKSPACE-based Bazel projects, always probing the graph to decide which pipeline to run.
Processing for BCR modules (Bzlmod mode on Bazel 7.1 or later)
When Detect runs in Bzlmod mode on Bazel 7.1 or later, it performs a dedicated Bazel Central Registry (BCR) dependency extraction step before executing the standard dependency discovery pipelines.
After BCR extraction completes, the http_archive discovery pipeline still runs to identify additional external dependencies. However, any dependency that was already identified and classified through the BCR module graph is deduplicated using its ExternalId. This ensures that the dependency relationships established by the BCR extractor are preserved, including the distinction between direct and transitive dependencies.
Without this deduplication step, dependencies discovered later through http_archive analysis could be incorrectly reclassified as direct dependencies, resulting in the loss of the dependency hierarchy derived from the Bzlmod module graph.
Custom http_archive definitions, private repositories, and non-BCR source archives absent from MODULE.bazel are not part of the BCR classification step. These dependencies are processed by the standard repository-rule analysis pipeline. However, that pipeline can only extract dependencies whose URLs match known GitHub release patterns. Private repositories, custom repository macros, and non-standard registry URLs will produce a WARN-level log entry and will be excluded from the BOM. See Using Bazel Fetch for Additional Coverage for a workaround in these environments.
Step 1 — Discover the full module dependency tree:
$ bazel mod graph --output jsonThe JSON output contains the complete module graph with parent-child edges. Direct dependencies (declared via bazel_dep in MODULE.bazel) appear at the root level; their transitive dependencies are nested beneath them.
Step 2 — Resolve each module to a source URL:
# Batched call (Bazel 7.1+, tried first)
$ bazel mod show_repo @module1 @module2 @module3 ...
# Per-module fallback if batch fails
$ bazel mod show_repo @module_nameDetect parses the show_repo output for GitHub URLs using the same extraction logic as the standard http_archive BZLMOD pipeline.
Step 3 — Build the classified BOM:
Modules declared via bazel_dep appear as direct dependencies. Their transitive dependencies appear nested under their respective parents rather than at the root. The BOM correctly reflects which components your project explicitly chose versus which came along transitively.
A WARN-level log entry is written for modules where no GitHub URL can be extracted (private repos, custom non-BCR rules), and excluded from the BOM. To assist in investigating what was missed, the warning includes the raw URL(s) found.
Examples
maven_install
git clone https://github.com/bazelbuild/rules_jvm_external
cd rules_jvm_external/
bash <(curl -s -L https://detect.blackduck.com/detect11.sh) --detect.bazel.target='//tests/integration:ArtifactExclusionsTest'haskell_cabal_library
git clone https://github.com/tweag/rules_haskell.git
cd rules_haskell/examples
bash <(curl -s -L https://detect.blackduck.com/detect11.sh) --detect.bazel.target='//cat_hs/lib/args:args'http_archive
# For a project with http_archive dependencies
git clone https://github.com/example/example-bazel-project.git
cd example-bazel-project
bash <(curl -s -L https://detect.blackduck.com/detect11.sh) --detect.bazel.target='//:mytarget'Getting Help
Refer to the Bazel Troubleshooting Guide
Check the Detect logs in the
runs/directory for detailed error messagesVerify your Bazel setup works:
bazel build //your:targetFor further assistance, contact Black Duck support with your Detect logs
Migrating from earlier versions of Detect
Upgrading to Detect 11.3.0
The Bazel tool was replaced entirely in Detect 11.3.0. The following changes are required if you are upgrading from an earlier version.
Property:
The detect.bazel.workspace.rules property was deprecated in Detect 11.3.0 and removed in 12.0.0. Use the detect.bazel.dependency.sources property which accepts the source names (MAVEN_INSTALL, MAVEN_JAR, HASKELL_CABAL_LIBRARY, HTTP_ARCHIVE). Use of detect.bazel.dependency.sources=NONE retains the source auto-detect behavior.
Mode Detection Behavior
The tool automatically determines your Bazel mode through the following process:
Attempts BZLMOD Detection: Runs
bazel mod graphSuccess with dependencies → BZLMOD Mode: Uses BZLMOD-specific pipelines
Empty graph → WORKSPACE Mode: Common in hybrid repos that declare MODULE.bazel for compatibility but manage dependencies via WORKSPACE
"Command not found" → WORKSPACE Mode: Bazel version < 6.0; assumes WORKSPACE mode with a warning
Auto-Detection vs Manual Override
Auto-Detection (Default):
Probes the dependency graph to detect which dependency sources are present
Runs targeted Bazel queries for each potential source type
More flexible but requires multiple Bazel command executions
Manual Override (detect.bazel.dependency.sources):
Skips graph probing
Directly runs pipelines for specified sources
Faster execution if you know your dependency types
Useful for CI/CD optimization
Example for known dependencies:
# Skip probing, directly extract Maven and HTTP dependencies
--detect.bazel.dependency.sources=MAVEN_INSTALL,HTTP_ARCHIVEPerformance Considerations
HTTP Detection: The tool automatically determines the best strategy based on project size. Small/medium projects (≤150 repos) are fully probed for precise detection. Large projects skip probing and always enable HTTP extraction for guaranteed completeness.
Target Specificity: More specific targets (for example,
//module:specific-target) are faster than broad targets (for example,//:all)Manual Override: Setting
detect.bazel.dependency.sourcesexplicitly can significantly speed up detection
Best Practices
Use specific build targets rather than workspace-wide targets for better performance
Use
--logging.level.detect=DEBUGwhen troubleshootingFor consistent CI/CD builds, set
--detect.bazel.mode=WORKSPACEorBZLMODexplicitlyIf dependency types are known, set
--detect.bazel.dependency.sourcesto avoid probing overhead