Skip to content

[SCI] add ProjectReference extractor for inter-module dependency analysis for csproj build file trees#178

Merged
anderruiz merged 1 commit into
mainfrom
ander/dotnet-csproj-build-file-trees
Jun 23, 2026
Merged

[SCI] add ProjectReference extractor for inter-module dependency analysis for csproj build file trees#178
anderruiz merged 1 commit into
mainfrom
ander/dotnet-csproj-build-file-trees

Conversation

@anderruiz

@anderruiz anderruiz commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add GetArtifact() method to NuGetCsprojExtractor that extracts internal <ProjectReference> dependencies from .csproj files, resolving relative paths to absolute filesystem paths with backslash normalization, deduplication, and existence checking
  • Register SimpleProcessor for FileTypeCsproj to enable transitive dependency closure via BFS, matching the existing Bazel pattern
  • Add ProjectReference XML type to ItemGroup and handle it in the custom XML unmarshaller

Implementation Details

Follows the BazelBuildExtractor pattern exactly:

  • GetArtifact() reads .csproj XML, extracts <ProjectReference Include="..."> entries, resolves paths relative to the file's directory
  • IsManifestParser() returns false
  • Compile-time interface checks for ArtifactExtractor and ManifestExtractor
  • New file named csproj-project-refs.go (not parse- prefix) to avoid triggering expectNumberOfParsersCalled test count
> go run examples/main.go /Users/ander.ruiz/go/src/github.com/DataDog/eShopOnWeb

--- Build Files (10 found) ---
  [*.csproj] src/ApplicationCore/ApplicationCore.csproj
    dep (hop=1): src/BlazorShared/BlazorShared.csproj
  [*.csproj] src/BlazorAdmin/BlazorAdmin.csproj
    dep (hop=1): src/BlazorShared/BlazorShared.csproj
  [*.csproj] src/BlazorShared/BlazorShared.csproj
  [*.csproj] src/Infrastructure/Infrastructure.csproj
    dep (hop=1): src/ApplicationCore/ApplicationCore.csproj
    dep (hop=2): src/BlazorShared/BlazorShared.csproj
  [*.csproj] src/PublicApi/PublicApi.csproj
    dep (hop=1): src/ApplicationCore/ApplicationCore.csproj
    dep (hop=2): src/BlazorShared/BlazorShared.csproj
    dep (hop=1): src/Infrastructure/Infrastructure.csproj
  [*.csproj] src/Web/Web.csproj
    dep (hop=1): src/ApplicationCore/ApplicationCore.csproj
    dep (hop=1): src/BlazorAdmin/BlazorAdmin.csproj
    dep (hop=1): src/BlazorShared/BlazorShared.csproj
    dep (hop=1): src/Infrastructure/Infrastructure.csproj
  [*.csproj] tests/FunctionalTests/FunctionalTests.csproj
    dep (hop=1): src/ApplicationCore/ApplicationCore.csproj
    dep (hop=2): src/BlazorAdmin/BlazorAdmin.csproj
    dep (hop=2): src/BlazorShared/BlazorShared.csproj
    dep (hop=2): src/Infrastructure/Infrastructure.csproj
    dep (hop=1): src/PublicApi/PublicApi.csproj
    dep (hop=1): src/Web/Web.csproj
  [*.csproj] tests/IntegrationTests/IntegrationTests.csproj
    dep (hop=2): src/ApplicationCore/ApplicationCore.csproj
    dep (hop=3): src/BlazorAdmin/BlazorAdmin.csproj
    dep (hop=3): src/BlazorShared/BlazorShared.csproj
    dep (hop=1): src/Infrastructure/Infrastructure.csproj
    dep (hop=2): src/Web/Web.csproj
    dep (hop=1): tests/UnitTests/UnitTests.csproj
  [*.csproj] tests/PublicApiIntegrationTests/PublicApiIntegrationTests.csproj
    dep (hop=2): src/ApplicationCore/ApplicationCore.csproj
    dep (hop=2): src/BlazorAdmin/BlazorAdmin.csproj
    dep (hop=2): src/BlazorShared/BlazorShared.csproj
    dep (hop=2): src/Infrastructure/Infrastructure.csproj
    dep (hop=1): src/PublicApi/PublicApi.csproj
    dep (hop=1): src/Web/Web.csproj
  [*.csproj] tests/UnitTests/UnitTests.csproj
    dep (hop=1): src/ApplicationCore/ApplicationCore.csproj
    dep (hop=2): src/BlazorAdmin/BlazorAdmin.csproj
    dep (hop=2): src/BlazorShared/BlazorShared.csproj
    dep (hop=2): src/Infrastructure/Infrastructure.csproj
    dep (hop=1): src/Web/Web.csproj

Files Changed

File Change
pkg/extractor/dotnet/types.go Add ProjectReference struct and field to ItemGroup
pkg/extractor/dotnet/xml-parser.go Handle ProjectReference in custom XML unmarshaller
pkg/extractor/dotnet/csproj-project-refs.go New: GetArtifact(), IsManifestParser(), interface checks
pkg/extractor/dotnet/csproj-project-refs_test.go New: 8 tests (XML, unit, integration)
pkg/sbomgen/simple_processor.go Register SimpleProcessor for FileTypeCsproj

Test plan

  • TestProjectReferenceXMLUnmarshal — XML parsing captures ProjectReference entries
  • TestNuGetCsprojExtractor_GetArtifact_ExtractsProjectDeps — resolves 2 ProjectReference entries to absolute paths
  • TestNuGetCsprojExtractor_GetArtifact_ResolvesRelativePaths — handles .. segments and backslashes
  • TestNuGetCsprojExtractor_GetArtifact_SkipsNonExistent — non-existent targets excluded
  • TestNuGetCsprojExtractor_GetArtifact_DeduplicatesDeps — duplicate references yield one entry
  • TestNuGetCsprojExtractor_GetArtifact_EmptyProjectRefs — no ProjectReference returns empty ProjectDeps
  • TestNuGetCsprojExtractor_IsManifestParser — returns false
  • TestNuGetCsprojExtractor_Integration_TransitiveClosure — A->B->C chain produces correct direct deps
  • Full go test ./... passes with zero failures (no regressions)

🤖 Generated with Claude Code

@anderruiz
anderruiz requested a review from a team as a code owner June 22, 2026 15:35
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Jun 22, 2026

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 53.45%
Overall Coverage: 84.17% (-0.24%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 40db565 | 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: 1c21eb714b

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

// entries as ProjectDeps. Each reference is resolved to an absolute filesystem
// path relative to the .csproj file's directory. Non-existent targets are
// silently skipped. Duplicates are deduplicated.
func (e NuGetCsprojExtractor) GetArtifact(f extractor.DepFile, ctx extractor.ScanContext) (*models.ScannedArtifact, error) {

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 project refs for locked csproj projects

When a project has an adjacent packages.lock.json, scanDir selects NuGetLockExtractor; NuGetCsprojExtractor.ShouldExtract returns false for that .csproj, and ExtractDeps only calls GetArtifact on the selected extractor. Because this ProjectReference extraction is only implemented on NuGetCsprojExtractor, locked NuGet projects never populate ProjectDeps, so GetBuildFileTrees(..., FileTypeCsproj) reports empty dependency trees for the common locked-project case. Please wire the lock-extractor/matcher path to run the same csproj artifact extraction.

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.

Fixed. Added GetArtifact() to NuGetLockExtractor in the same file — it finds the adjacent .csproj in the lock file directory and reuses extractCsprojInternalDeps(), so locked projects now populate ProjectDeps the same way as non-locked ones.

@anderruiz
anderruiz force-pushed the ander/dotnet-csproj-build-file-trees branch 2 times, most recently from 28745d8 to 7c7eb16 Compare June 22, 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: 7c7eb16d16

ℹ️ 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/dotnet/csproj-project-refs.go Outdated
Add GetArtifact() and IsManifestParser() methods to NuGetCsprojExtractor
to extract internal <ProjectReference> dependencies from .csproj files.
This enables transitive dependency closure via SimpleProcessor BFS,
matching the existing pattern used by BazelBuildExtractor.

Changes:
- Add ProjectReference type and field to ItemGroup (types.go)
- Handle ProjectReference in custom XML unmarshaller (xml-parser.go)
- Implement GetArtifact() with path resolution, deduplication, and
  existence checking (csproj-project-refs.go)
- Register SimpleProcessor for FileTypeCsproj (simple_processor.go)
- Add comprehensive unit and integration tests

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
@anderruiz
anderruiz force-pushed the ander/dotnet-csproj-build-file-trees branch from 7c7eb16 to 40db565 Compare June 22, 2026 20:40
@anderruiz anderruiz changed the title feat(dotnet): add ProjectReference tracing for csproj build file trees [SCI] add ProjectReference tracing for csproj build file trees Jun 22, 2026
@anderruiz anderruiz changed the title [SCI] add ProjectReference tracing for csproj build file trees [SCI] add ProjectReference extractor for inter-module dependency analysis for csproj build file trees Jun 22, 2026
@anderruiz
anderruiz merged commit 9aa4694 into main Jun 23, 2026
11 checks passed
@anderruiz
anderruiz deleted the ander/dotnet-csproj-build-file-trees branch June 23, 2026 12:36
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