feat(sbomgen): add Gradle build file tree support#164
Conversation
|
🎯 Code Coverage (details) 🔗 Commit SHA: a8defe5 | Docs | Datadog PR Page | Give us feedback! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 15e3e9bc43
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 16b0510057
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
16b0510 to
9cd4702
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6efa90f90b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f558831ea6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
f558831 to
a191028
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a1910285d3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…pport
Add GetArtifact to GradleLockExtractor and GradleVerificationMetadataExtractor
so that build.gradle / build.gradle.kts files appear as file-type SBOM
components and carry inter-module dependency edges in GetBuildFileTrees.
GetArtifact reads the accompanying build.gradle to extract:
- top-level `group = "..."` assignment → sets artifact.Name = "group:projectDir"
so findArtifact can match this subproject when it appears as a dependency
in another module's lockfile, producing dependency edges via createFileComponents
- project(':submodule') references → resolved to filesystem paths and stored
in ScannedArtifact.ProjectDeps, producing direct build-file→build-file edges
in the SBOM dependency graph for GetBuildFileTrees BFS traversal
Supporting changes:
- Add ScannedArtifact.ProjectDeps []ArtifactDetail (pkg/models)
- Process ProjectDeps in addFileDependencies to emit SBOM dependency edges (cyclonedx.go)
- Relativize ProjectDeps filenames alongside artifact.Filename in scanner
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Register SimpleProcessor for FileTypeBuildGradle and FileTypeBuildGradleKts so GetBuildFileTrees resolves transitive dependency edges for Gradle modules via BFS, matching the pattern already used for Maven and Python. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
a191028 to
7e52a72
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e52a724b8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
rjcoulter22
left a comment
There was a problem hiding this comment.
lgtm, but some questions and comments
…pport
- Remove dead `dep.Filename == ""` guard in cyclonedx.go: ProjectDeps
entries are always non-empty (extractGradleProjectDeps only appends
paths that pass os.Stat)
- Add stub file component for project(':...') targets with no lockfile,
so GetBuildFileTrees can traverse cross-subproject edges
- Fix test type mismatch: compare BuildFileWithHopCount.BuildFile field
instead of comparing directly with BuildFile
- Add TestSimpleProcessor_Gradle_ProjectDepWithNoLockfile to cover the
stub-component path end-to-end
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a8defe5d3f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // whose Filename points to the corresponding build.gradle (or build.gradle.kts) | ||
| // under rootDir. Refs that cannot be resolved to an existing file are skipped. | ||
| func extractGradleProjectDeps(content []byte, rootDir string) []models.ArtifactDetail { | ||
| projectRegex := cachedregexp.MustCompile(`project\(['"]([^'"]+)['"]\)`) |
There was a problem hiding this comment.
Parse named Gradle project references
In Gradle builds that declare internal dependencies with the named-argument forms project(path: ':lib') or project(path = ":lib") (often used when also specifying a configuration), this pattern produces no match, so ProjectDeps stays empty. If that target subproject has no lockfile/package occurrences of its own, no file component or dependency edge is emitted and GetBuildFileTrees omits the project relationship; handle the named path forms as well as the positional form.
Useful? React with 👍 / 👎.
| // can traverse the edge. A subproject with no lockfile of its own won't | ||
| // appear in artifacts, so we create a stub component here. | ||
| if _, exists := components[dep.Filename]; !exists { | ||
| components[dep.Filename] = cyclonedx.Component{ |
There was a problem hiding this comment.
Preserve edges from lockfile-less Gradle stubs
When app/build.gradle depends on project(':lib') and lib has no lockfile, this branch emits only a stub file component for lib/build.gradle. If that stubbed build file itself declares project(':core'), no artifact is ever scanned for lib, so no lib -> core dependency is serialized and the SimpleProcessor BFS stops at lib; parse dependency targets (or all build files) before stubbing them so transitive Gradle project edges are not dropped.
Useful? React with 👍 / 👎.
Summary
ArtifactExtractoron both Gradle lockfile extractors (GradleLockExtractor,GradleVerificationMetadataExtractor) — reads the adjacentbuild.gradle/build.gradle.ktsto extract:group:projectDiras the artifact name (for cross-subproject matching)project(':...')references →ProjectDepsfor build-file dependency edgesSimpleProcessorforFileTypeBuildGradleandFileTypeBuildGradleKtssoGetBuildFileTreesreturns Gradle build files with BFS-resolved transitive dependencies (same approach as Maven and Python)project(':...')targets with no lockfile of their own, soGetBuildFileTreescan traverse cross-subproject edges even when a subproject has no lockfileValidation
Validated against a multi-project Gradle repo with
gradle.lockfilefiles:build.gradlefiles now appear inGetBuildFileTreesoutput whenExtractArtifactIdsis enabled (default).Known limitations (documented TODOs for follow-up PRs)
artifact.Nameis set togroup:directoryName(e.g.com.example:app). The canonical name comes fromsettings.gradle(rootProject.name,include ':submodule'), which is not parsed yet — left for a follow-up PR.project(':lib')refs are extracted directly frombuild.gradle, but subproject names are resolved from directory names, not fromsettings.gradleincludes. Full accuracy requires parsingsettings.gradle.Test plan
GetArtifacton both extractors (nil when no build file, correct path when found, group extraction, project deps extraction)SimpleProcessorregistration (Gradle build files returned byGetBuildFileTrees)./scripts/run_tests.sh)./scripts/run_lints.sh)Generated with Claude Code