Skip to content

feat(sbomgen): add Gradle build file tree support#164

Merged
anderruiz merged 3 commits into
mainfrom
ander/gradle-buildfile-processor
Jun 17, 2026
Merged

feat(sbomgen): add Gradle build file tree support#164
anderruiz merged 3 commits into
mainfrom
ander/gradle-buildfile-processor

Conversation

@anderruiz

@anderruiz anderruiz commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Implements ArtifactExtractor on both Gradle lockfile extractors (GradleLockExtractor, GradleVerificationMetadataExtractor) — reads the adjacent build.gradle/build.gradle.kts to extract:
    • group:projectDir as the artifact name (for cross-subproject matching)
    • project(':...') references → ProjectDeps for build-file dependency edges
  • Registers SimpleProcessor for FileTypeBuildGradle and FileTypeBuildGradleKts so GetBuildFileTrees returns Gradle build files with BFS-resolved transitive dependencies (same approach as Maven and Python)
  • Emits stub file components for project(':...') targets with no lockfile of their own, so GetBuildFileTrees can traverse cross-subproject edges even when a subproject has no lockfile

Validation

Validated against a multi-project Gradle repo with gradle.lockfile files:

--- Build Files (3 found) ---
  [build.gradle] app/build.gradle
  ...

build.gradle files now appear in GetBuildFileTrees output when ExtractArtifactIds is enabled (default).

Known limitations (documented TODOs for follow-up PRs)

  • Artifact ID uses directory name: artifact.Name is set to group:directoryName (e.g. com.example:app). The canonical name comes from settings.gradle (rootProject.name, include ':submodule'), which is not parsed yet — left for a follow-up PR.
  • No inter-module dependency edges via settings.gradle: project(':lib') refs are extracted directly from build.gradle, but subproject names are resolved from directory names, not from settings.gradle includes. Full accuracy requires parsing settings.gradle.

Test plan

  • Unit tests for GetArtifact on both extractors (nil when no build file, correct path when found, group extraction, project deps extraction)
  • Unit test for SimpleProcessor registration (Gradle build files returned by GetBuildFileTrees)
  • Unit test for stub file component (subproject with no lockfile appears in tree)
  • All tests pass (./scripts/run_tests.sh)
  • Lints pass (./scripts/run_lints.sh)

Generated with Claude Code

@anderruiz
anderruiz requested a review from a team as a code owner June 15, 2026 10:43
@datadog-official

datadog-official Bot commented Jun 15, 2026

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 65.85%
Overall Coverage: 84.31% (-0.28%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: a8defe5 | Docs | Datadog PR Page | Give us feedback!

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread pkg/extractor/java/parse-gradle-lock.go

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread pkg/extractor/java/parse-gradle-lock.go
@anderruiz
anderruiz force-pushed the ander/gradle-buildfile-processor branch from 16b0510 to 9cd4702 Compare June 16, 2026 07:25

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread pkg/sbomgen/simple_processor_test.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread internal/output/sbom/cyclonedx.go
@anderruiz
anderruiz force-pushed the ander/gradle-buildfile-processor branch from f558831 to a191028 Compare June 16, 2026 09:30

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread pkg/extractor/java/parse-gradle-verification-metadata.go
anderruiz and others added 2 commits June 16, 2026 13:55
…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]>
@anderruiz
anderruiz force-pushed the ander/gradle-buildfile-processor branch from a191028 to 7e52a72 Compare June 16, 2026 11:55

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread pkg/extractor/java/parse-gradle-lock.go

@rjcoulter22 rjcoulter22 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, but some questions and comments

Comment thread internal/output/sbom/cyclonedx.go Outdated
Comment thread pkg/extractor/java/parse-gradle-lock.go
…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]>
@anderruiz
anderruiz merged commit 3ad4512 into main Jun 17, 2026
11 checks passed
@anderruiz
anderruiz deleted the ander/gradle-buildfile-processor branch June 17, 2026 15:40

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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\(['"]([^'"]+)['"]\)`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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{

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants