Skip to content

[PoC] Add GetBuildFileTrees API to extract manifest build files and their relations from SBOMs#157

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 10 commits into
mainfrom
ander/sbomgen-build-file-trees
Jun 4, 2026
Merged

[PoC] Add GetBuildFileTrees API to extract manifest build files and their relations from SBOMs#157
gh-worker-dd-mergequeue-cf854d[bot] merged 10 commits into
mainfrom
ander/sbomgen-build-file-trees

Conversation

@anderruiz

@anderruiz anderruiz commented May 27, 2026

Copy link
Copy Markdown
Contributor

Motivation

Downstream consumers of the pkg/sbomgen library need to identify which build/manifest files are present in a generated SBOM and understand their inter-module relationships — without having to parse CycloneDX JSON themselves.

This is currently being developed as a POC for Source Code Integration (SCI), which needs to map each build file to its transitive internal dependencies in order to attribute vulnerabilities to the correct folder scope.

Documentation

Document Link or Detail
RFC N/A
Incident N/A
Jira Ticket N/A

Changes overview

This PR contains two independent layers of changes with different audiences:

Layer 1 — SBOM generation (internal/, pkg/scanner/, pkg/extractor/) — affects all clients

These changes improve the SBOM that datadog-sbom-generator produces. They are independent of the library API and benefit every consumer of the generated SBOM, not just SCI.

internal/output/sbom/cyclonedx.go

  • addFileDependencies: when a Maven artifact has a <parent>, emits a maven:parentPom property on the file-type component so that parent/module relationships can be unambiguously distinguished in bom.Dependencies.
  • findArtifact: fixed a bug where modules using BOM import (<dependencyManagement>) without a <parent> element had their dependency versions extracted as empty strings, causing findArtifact to return nil and no bom.Dependencies edges to be emitted for those modules. Fixed by accepting a name-only match when version is empty.

internal/output/sbom/models.go

  • Added mavenParentPomProperty = "maven:parentPom" constant.

pkg/extractor/extract.go

  • Added GetArtifact to the Extractor interface and ExtractMavenPomArtifactIds option to ScanContext, enabling opt-in emission of file-type components and dependency edges for Maven POMs.

pkg/scanner/datadog_sbom_generator.go

  • Wires ExtractMavenPomArtifactIds from Options through to the scan context so callers can control the feature.

Layer 2 — Library API (pkg/sbomgen/) — specific to the SCI POC

These changes add a new public Go API on top of the SBOM, intended for programmatic consumers (currently only the SCI POC in code-workload-runner-sca). They do not affect the CLI output.

pkg/sbomgen/build_files.go (new)

  • FileType — string enum with 12 constants covering all manifest types.
  • BuildFile{FileType, FilePath, RepoPath} — identifies a build/manifest file within a repo.
  • GetBuildFileTrees(sbom []byte, filters ...FileType) map[BuildFile]BuildFileRelations — parses a CycloneDX SBOM and returns all manifest build files, each enriched with its transitive dependencies and an ecosystem-specific ID. Collects build files from both role=manifest evidence occurrences and file-type components (so parent POMs with no package occurrences are never missed). Dispatches each file type to a registered BuildFileProcessor.

pkg/sbomgen/build_file_processor.go (new)

  • BuildFileRelations{ID string, Dependencies []BuildFile} — flat list of ALL transitively reachable build files (sorted by path) plus an ecosystem-specific identifier.
  • BuildFileProcessor interface and ProcessorContext (carries FileDependencies, MavenParents, MavenArtifactIDs).
  • noopProcessor — returns empty Dependencies for unregistered file types.
  • RegisterBuildFileProcessor — allows processors to self-register via init().

pkg/sbomgen/maven_processor.go (new)

  • MavenProcessor — computes the full transitive closure of build-file dependencies via BFS over ProcessorContext.FileDependencies. FileDependencies carries both <parent> edges and local-module <dependency> edges, so BFS captures all reachable in-repo build files in one pass. Populates BuildFileRelations.ID with groupId:artifactId parsed from the osv-scanner:package purl. Handles cycles and external parents (filtered out if not present in the SBOM).

pkg/sbomgen/sbomgen.go

  • DefaultOptions() enables ExtractMavenPomArtifactIds by default so GetBuildFileTrees works out of the box.

README.md / examples/main.go

  • Added library usage documentation and a runnable example demonstrating GenerateSBOM + GetBuildFileTrees.

Testing

  • New tests were added for new logic.
  • Existing tests were updated for new logic, and not only so that they pass!
  • Benchmark results prove that performance is the same or better.

Layer 1 — SBOM generation:

  • Existing snapshot tests in internal/output/ updated to reflect the new maven:parentPom property and corrected bom.Dependencies edges for BOM-import modules.

Layer 2 — Library API:

  • pkg/sbomgen/build_files_test.go — 10 tests: manifest extraction, lockfile exclusion, FileType filtering, deduplication, file-type component collection, unknown types.
  • pkg/sbomgen/maven_processor_test.go — 7 tests: single root POM, parent-child, multi-module, deep 3-level hierarchy (transitive closure), external parent ignored, sibling module as dependency, parent POM via file-type component only.

Staging validation

  • Deployed and monitored using Datadog dashboards.
  • Proof that it works as expected, including profiling or UX screenshots.

Recovery

  • The change can be rolled back.

anderruiz and others added 2 commits May 27, 2026 14:21
…from CycloneDX SBOMs

- Add FileType constants for 12 manifest file types (pom.xml, Cargo.toml, package.json, etc.)
- Add BuildFile struct with FileType, FilePath, and RepoPath fields
- Implement GetBuildFileTrees parsing CycloneDX evidence occurrences to identify manifest files
- Support filtering by FileType, deduplication, and wildcard .csproj matching
- Add 10 comprehensive tests covering manifest extraction, lockfile exclusion, filtering, deduplication, subdirectory paths, csproj wildcard, empty/nil input, and unknown manifest types

Rationale: Downstream consumers (e.g. the transitive dependency tree feature) need to identify which build/manifest files are present in a generated SBOM. This function parses CycloneDX evidence occurrences and returns a deduplicated map of manifest BuildFiles, laying the groundwork for build file tree construction in a future PR.

This commit made by [/dd:git:commit:atomic](https://github.com/DataDog/claude-marketplace/tree/main/dd/commands/git/commit/atomic.md)
- Update examples/main.go to call GetBuildFileTrees on the generated SBOM
- Print count of manifest build files found and each BuildFile's type, path, and repo path
- Add Cargo.toml to testdata so the example produces visible output by default
- Sort output deterministically for reproducible display

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@anderruiz
anderruiz requested a review from a team as a code owner May 27, 2026 12:28
@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented May 27, 2026

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 70.06%
Overall Coverage: 84.28% (-0.85%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: d359f61 | 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: fb475d2808

ℹ️ 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/build_files.go Outdated

// exactFileTypes maps exact basenames to their FileType.
// build.gradle.kts is checked before build.gradle to avoid false matches.
var exactFileTypes = map[string]FileType{

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 Include all supported manifest basenames

GetBuildFileTrees drops every manifest whose basename is not in this classifier. That misses SBOMs this generator actually emits for supported manifests such as Go (parse-go-lock.go marks go.mod occurrences as LocationRoleManifest) and requirements variants (RequirementsTxtExtractor.ShouldExtract accepts any requirements*.txt), so Go projects or files like requirements-dev.txt have manifest evidence in the SBOM but are absent from the returned build-file map. Please extend this classifier/pattern matching to cover the supported manifest inputs before applying the filter.

Useful? React with 👍 / 👎.

@anderruiz anderruiz changed the title feat(sbomgen): add GetBuildFileTrees to extract manifest build files from SBOMs [JIRA] feat(sbomgen): add GetBuildFileTrees API to extract manifest build files from SBOMs May 29, 2026
@anderruiz anderruiz changed the title [JIRA] feat(sbomgen): add GetBuildFileTrees API to extract manifest build files from SBOMs feat(sbomgen): add GetBuildFileTrees API to extract manifest build files from SBOMs May 29, 2026

@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: c6dda04a7e

ℹ️ 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/build_files.go Outdated
continue
}

ft := fileTypeFromBasename(filepath.Base(loc.Block.FileName))

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 Normalize requirements variants before filtering

When callers pass FileTypeRequirementsTxt to filter for requirements manifests, supported files such as requirements-dev.txt are silently excluded: RequirementsTxtExtractor.ShouldExtract accepts any basename containing requirements and ending in .txt, and those occurrences are emitted with role=manifest, but this classifier returns the exact basename unless it is .csproj. As a result GetBuildFileTrees(sbom, FileTypeRequirementsTxt) returns nothing for these supported requirements SBOMs even though an unfiltered call would include them under a different ad-hoc FileType.

Useful? React with 👍 / 👎.

@anderruiz
anderruiz force-pushed the ander/sbomgen-build-file-trees branch 3 times, most recently from a9399ea to 8b52b94 Compare June 1, 2026 15:59

@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: 8b52b94fe0

ℹ️ 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".

}
r.Infof("Scanning directory '%s', resolved absolute path '%s'\n", dir, absolutePath)
pkgs, artifacts, err := scanDir(r, dir, repoRoot, actions.Recursive, !actions.NoIgnore, enabledParsers, actions.ExcludePaths, configExcludePaths)
pkgs, artifacts, err := scanDir(r, dir, repoRoot, actions.Recursive, !actions.NoIgnore, enabledParsers, actions.ExcludePaths, configExcludePaths, actions.ExtractMavenPomArtifactIds)

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 Maven artifact extraction by default

When the CLI calls DoScan, cmd/datadog-sbom-generator/scan/main.go constructs ScannerActions without setting this newly added option, so the zero value false is passed here and ExtractDeps skips every ArtifactExtractor. For Maven scans this drops the pom.xml file components and dependency edges that were previously emitted in CycloneDX output, which is visible in the updated CLI snapshots; either make the scanner default preserve the old behavior or set the new option in the CLI path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, it is intended to be removed

@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: 2123c40977

ℹ️ 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/sbomgen.go
DirectoryPaths: dirs,
ExcludePaths: opts.ExcludePaths,
Recursive: opts.Recursive,
ExtractMavenPomArtifactIds: opts.ExtractMavenPomArtifactIds,

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 Restore Maven artifacts for custom options

When library callers build Options themselves (for example Options{Recursive: true} or any existing literal that predated this field), this new bool remains false and is passed through to DoScan, so ExtractDeps no longer runs ArtifactExtractor.GetArtifact for Maven pom.xml files. Before this change those callers always got the Maven file components and parent dependency edges in the generated CycloneDX SBOM; only callers that happen to use DefaultOptions() preserve that behavior.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, it is intended to be removed

@anderruiz
anderruiz force-pushed the ander/sbomgen-build-file-trees branch from 2123c40 to 667ba52 Compare June 1, 2026 16:20

@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: 667ba52cbe

ℹ️ 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 on lines +106 to +107
if loc.Block.Role != "manifest" || loc.Block.FileName == "" {
continue

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 Inspect all occurrence sublocations for manifests

When a dependency occurrence has manifest evidence in name, namespace, or version whose filename differs from the declaration block, this only reads block and drops those files. Maven inheritance/property resolution already emits such occurrences (for example a child dependency block can have its version location in a parent pom.xml), so GetBuildFileTrees can omit a parent build file if it has no dependency block of its own. Please scan every PackageLocations sublocation with role=manifest, not just block.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a partial case, covering with the following comment

@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: e4709f1185

ℹ️ 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 on lines +98 to +99
if comp.Evidence == nil || comp.Evidence.Occurrences == nil {
continue

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 Include file-only POM components in the tree

When a Maven parent/aggregator POM has no dependency declarations of its own, the generated CycloneDX SBOM can still contain it as a file component and dependency target, but it has no evidence occurrences. This branch skips every component without Evidence.Occurrences, so that POM is never added to filesByPath; MavenProcessor then ignores child → parent edges to it and returns children with no parent, producing an incomplete build-file tree for common multi-module layouts where the root POM only defines modules/properties.

Useful? React with 👍 / 👎.

anderruiz and others added 3 commits June 1, 2026 22:00
…name

- Remove exactFileTypes map — FileType is now the basename from the SBOM occurrence
- fileTypeFromBasename simplified: only normalises dynamic-suffix types (*.csproj)
- Any role=manifest occurrence is now included regardless of known FileType constants
- Update TestDefaultFileTypeFromFilename → TestFileTypeFromBasename to match new signature
- Update TestGetBuildFileTrees_UnknownManifestIgnored → UnknownManifestIncluded

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ArtifactIds flag

The Maven pom.xml filename and dependsOn relationship tags are only
needed for SBOM-to-artifact mapping in downstream resolution logic, not
for general SBOM generation. Gate this behind ScanContext.ExtractArtifacts
(false by default) and thread it through ScannerActions.ExtractArtifacts.

In the library API (pkg/sbomgen), DefaultOptions() sets ExtractArtifacts: true
so callers using GenerateSBOM get the richer output without extra configuration.
The CLI leaves the flag unset, keeping its output free of file components and
dependsOn entries.

Also fix a pre-existing typo: BuildFclle -> BuildFile in pkg/sbomgen/build_files.go.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…BuildFileTrees

Introduce BuildFileProcessor interface and a global registry so that each
FileType can have a dedicated processor. GetBuildFileTrees now:
  1. Collects and deduplicates manifest occurrences from the SBOM
  2. Groups them by FileType
  3. Dispatches each group to its registered processor (noopProcessor as
     fallback, preserving existing behaviour)
  4. Merges all processor results into the returned map

RegisterBuildFileProcessor lets future processor packages (e.g. Maven)
register themselves via init(). No behaviour change for existing callers.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@anderruiz
anderruiz force-pushed the ander/sbomgen-build-file-trees branch from e4709f1 to b9f302d Compare June 1, 2026 20:01

@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: b9f302dd6d

ℹ️ 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/maven_processor.go Outdated
Comment on lines +30 to +33
for _, dep := range ctx.FileDependencies[f.FilePath] {
if _, ok := filesByPath[dep]; ok {
parentByChild[f.FilePath] = dep
break

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 Don't treat module dependencies as Maven parents

When a Maven POM has dependencies on other local modules, the SBOM dependency entry can contain those module POMs as well as the real parent POM: internal/output/sbom/cyclonedx.go adds artifact.Filename for internal Maven dependencies and sorts the list. This loop then treats the first known POM dependency as the parent, so cases like a module depending on a sibling module (or a root POM depending on a child module) produce incorrect parent/child build-file trees even though the edge is not from the <parent> element.

Useful? React with 👍 / 👎.

@anderruiz
anderruiz force-pushed the ander/sbomgen-build-file-trees branch from b9f302d to 1644730 Compare June 1, 2026 20:17

@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: 1644730886

ℹ️ 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".

// addBuildFile adds a build file identified by filePath to the grouped map if it
// passes the filterSet check and has not been seen before.
func addBuildFile(filePath string, filterSet map[FileType]struct{}, seen map[BuildFile]struct{}, grouped map[FileType][]BuildFile) {
ft := fileTypeFromBasename(filepath.Base(filePath))

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 Normalize SBOM paths before deriving file types

When GetBuildFileTrees parses an SBOM generated on Windows but is called on a Unix host, occurrence paths such as backend\Cargo.toml are passed to filepath.Base, which treats backslashes as ordinary characters on Unix. The resulting FileType becomes backend\Cargo.toml instead of Cargo.toml, so filtering with FileTypeCargoToml drops the manifest and unfiltered results are grouped under the wrong type; normalize \ separators or use a platform-independent basename before classification.

Useful? React with 👍 / 👎.

@anderruiz
anderruiz force-pushed the ander/sbomgen-build-file-trees branch from 1644730 to e5532c0 Compare June 1, 2026 20:31

@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: e5532c0d99

ℹ️ 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".

}
}

bf := BuildFile{FileType: ft, FilePath: filePath}

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 Normalize build file paths to the repo root

When callers pass an SBOM produced by GenerateSBOM or the CLI, this stores the raw file_name/BOMRef in BuildFile.FilePath, but those values are absolute paths: scanDir converts walked files with filepath.Abs, OpenLocalDepFile also absolutizes them, and extractors write f.Path() into package locations/artifacts. That makes the new API return machine-specific absolute paths despite the BuildFile.FilePath contract saying it is repo-relative, so consumers cannot reliably compare results across workspaces or use the documented path semantics.

Useful? React with 👍 / 👎.

@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: 606306f36d

ℹ️ 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 on lines +47 to +48
if strings.HasPrefix(basename, "requirements") && strings.HasSuffix(basename, ".txt") {
return FileTypeRequirementsTxt

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 Handle requirements.in manifests in filters

When a requirements.in source file exists, RequirementsInMatcher marks matched packages with LocationRoleManifest and uses the .in path as the occurrence filename, but this classifier only normalizes requirements*.txt. As a result GetBuildFileTrees(sbom, FileTypeRequirementsTxt) silently drops supported requirements manifests such as requirements.in or requirements-dev.in even though they are present in the SBOM; normalize these .in basenames to a requirements file type or expose a filterable FileType for them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not for now

@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: 38648fd8e4

ℹ️ 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 on lines +232 to +233
if id := parseMavenArtifactID(prop.Value); id != "" {
ctx.MavenArtifactIDs[comp.BOMRef] = id

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 Populate Maven IDs when groupId is inherited

When a Maven module omits <groupId> and inherits it from its parent, the file component purl generated by the existing artifact extractor has no namespace (the repo fixture other-dir/pom.xml is one such case, producing a value like pkg:maven/kafka-commons-client@...). Since the new API derives BuildFileRelations.ID only through parseMavenArtifactID, that common module shape gets an empty ID even though the README/API contract says Maven IDs are groupId:artifactId; resolve inherited group IDs or derive them through the parent metadata before storing this map entry.

Useful? React with 👍 / 👎.

Introduce typed parent/child relationships for build files:

- BuildFileRelations{Parent *BuildFile, Children []BuildFile} replaces the
  previously untyped []BuildFile map value in GetBuildFileTrees. This makes
  the parent-child direction explicit without embedding slices in the map key.

- ProcessorContext{FileDependencies map[string][]string} carries the SBOM
  dependency graph to processors. GetBuildFileTrees now parses bom.Dependencies
  and passes it to each processor, enabling enrichment without filesystem access.

- BuildFileProcessor.Process now receives a ProcessorContext alongside the files.

- MavenProcessor implements BuildFileProcessor for FileTypePomXML. It reads
  ctx.FileDependencies to resolve parent/child relationships between pom.xml
  files and populates BuildFileRelations accordingly. Registers via init().

- Tests cover: single root POM, simple parent-child, flat multi-module project,
  deep three-level hierarchy, and external/unknown parent (silently ignored).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@anderruiz
anderruiz force-pushed the ander/sbomgen-build-file-trees branch from 38648fd to d1880d8 Compare June 2, 2026 15:06
Modules that use BOM import (<dependencyManagement>) without a <parent>
cannot resolve dependency versions at extraction time, producing packages
with an empty version string. findArtifact previously required an exact
name+version match, so it returned nil for these packages, and
createFileComponents skipped adding dependency edges for those pom.xml
files.

Fix by relaxing findArtifact to accept a name-only match when version is
the empty string, so that internal module edges are still recorded even
when version resolution fails.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@anderruiz
anderruiz force-pushed the ander/sbomgen-build-file-trees branch from d1880d8 to d7e7791 Compare June 2, 2026 15:08
@anderruiz anderruiz changed the title feat(sbomgen): add GetBuildFileTrees API to extract manifest build files from SBOMs [PoC] Add GetBuildFileTrees API to extract manifest build files and their relations from SBOMs Jun 2, 2026

@piloulacdog piloulacdog 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.

approved with feedback to not block you.

// ExtractMavenPomArtifactIds controls whether Maven pom.xml artifact IDs
// and parent dependency relationships are extracted and included in the SBOM.
// When false, ScannedArtifact entries are never produced.
ExtractMavenPomArtifactIds bool

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.

the fact that we make it a default-ignore, means that we are changing the default behavior of the tool (which used to be default-add). I guess it's not a big deal if we didn't use it! did we? 👀

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It was intentional and something @marcwieserdev and I discussed

@@ -62,7 +62,7 @@ func Test_scanDir(t *testing.T) {
var excludedGlobs []string

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.

now in the datadog-sbom-generator it seems we only have tests with false. which means we no longer have a single example of main_test.snap with the flag true. Could we add at least one?

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.

the main_test.snap is a very easy way to test and understand actual generated sbom (they are more human readable than the Go tests)

Comment thread pkg/sbomgen/build_files.go Outdated
// the parent POM path for a Maven file-type component. It mirrors the constant
// in internal/output/sbom/models.go; kept here to avoid an internal→pkg import
// cycle.
const mavenParentPomProperty = "maven:parentPom"

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.

could we make it consistent with the other component properties we have? they are prefixed with datadog.

Suggested change
const mavenParentPomProperty = "maven:parentPom"
const mavenParentPomProperty = "datadog:maven-parent-pom"

Except of course if it's a global known property

Comment thread pkg/sbomgen/build_files.go Outdated
// osvScannerPackageProperty is the CycloneDX component property name that
// records the package URL for a file-type component. For Maven components the
// purl format is "pkg:maven/{groupId}/{artifactId}@{version}".
const osvScannerPackageProperty = "osv-scanner:package"

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.

if we now afford to change the default to the EXCLUDE the artifact, i assume it means we don't really have consumer of this property: osv-scanner:package ?
Should we take this opportunity to also standardize the name to: datadog:package? or whatever else which would make sense?

Comment thread pkg/sbomgen/build_files.go Outdated
func buildProcessorContext(bom *cyclonedx.BOM) ProcessorContext {
ctx := ProcessorContext{
FileDependencies: make(map[string][]string),
MavenParents: make(map[string]string),

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.

looks like this map is set/populated but never read. Is that a building block which is a leftover? or a component which will be used later?

Comment thread pkg/sbomgen/build_files.go Outdated
// purl format is "pkg:maven/{groupId}/{artifactId}@{version}".
const osvScannerPackageProperty = "osv-scanner:package"

// buildProcessorContext extracts enrichment data from the SBOM into a

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.

nitpick: i think this comment is due next to: buildProcessorContext definition? :p

…op unused MavenParents

Rename the property value from "maven:parentPom" to "datadog:maven-parent-pom"
to be consistent with other Datadog-prefixed CycloneDX properties.

Remove the MavenParents field from ProcessorContext — it was populated from
the property but never consumed by any processor (the MavenProcessor uses
FileDependencies for BFS traversal instead).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>

@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: 9b525b0ea5

ℹ️ 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/sbomgen.go
DirectoryPaths: dirs,
ExcludePaths: opts.ExcludePaths,
Recursive: opts.Recursive,
ExtractMavenPomArtifactIds: opts.ExtractMavenPomArtifactIds,

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 Return SBOMs when only Maven build files are found

With this option enabled, scanDir can now return Maven artifacts even when no packages were extracted, such as a repository that only contains parent/aggregator pom.xml files with no dependency declarations. GenerateSBOM still bubbles DoScan's NoPackagesFoundErr because DoScan checks only len(scannedPackages), so callers cannot produce the SBOM needed by GetBuildFileTrees for these build-file-only projects; treat non-empty artifacts as a successful scan or include them before the empty-package check.

Useful? React with 👍 / 👎.

}
}

bf := BuildFile{FileType: ft, FilePath: filePath}

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 scan root when deduplicating build files

When GenerateSBOM is called with multiple scan roots, DoScan serializes locations and artifacts relative to each root, so two different roots can both contribute a pom.xml/Cargo.toml path. Because RepoPath is left empty here and seen keys only on FileType and FilePath, GetBuildFileTrees collapses those distinct build files into one entry, losing a root and merging its relations; populate/use the root identity or otherwise make the SBOM refs unique across scan roots.

Useful? React with 👍 / 👎.

anderruiz and others added 2 commits June 4, 2026 13:17
…ckage

Standardize the Maven file-type component property to use the datadog: prefix,
consistent with datadog:maven-parent-pom. The property is only emitted for
Maven POMs (the only extractor implementing GetArtifact), so there are no
other ecosystem consumers to migrate.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants