.NET Analyzer

The .NET analyzer detects NuGet package dependencies in .NET applications by analyzing multiple dependency sources with defined precedence rules.

Detection Sources and Precedence

The analyzer uses the following sources in order of precedence (highest to lowest fidelity):

PrioritySourceDescription
1packages.lock.jsonLocked resolved versions; highest trust for version accuracy
2*.deps.jsonInstalled/published packages; authoritative for “what shipped”
3SDK-style project files*.csproj/*.fsproj/*.vbproj + Directory.Packages.props (CPM) + Directory.Build.props
4packages.configLegacy format; lowest precedence

Operating Modes

Installed Mode (deps.json present)

When *.deps.json files exist, the analyzer operates in installed mode:

Declared-Only Mode (no deps.json)

When no *.deps.json files exist, the analyzer falls back to declared-only mode:

Declared-Only Components

Components emitted from declared sources include these metadata fields:

FieldDescription
declaredOnlyAlways "true" for declared-only components
declared.sourceSource file type (e.g., csproj, packages.lock.json, packages.config)
declared.locatorRelative path to source file
declared.versionSourceHow version was determined: direct, centralpkg, lockfile, property, unresolved
declared.tfm[N]Target framework(s)
declared.isDevelopmentDependency"true" if marked as development dependency
provenance"declared" for declared-only components

Unresolved Version Identity

When a version cannot be resolved (e.g., CPM enabled but missing version, unresolved property placeholder), the component uses an explicit key format:

declared:nuget/<normalized-id>/<version-source-hash>

Where version-source-hash = first 8 characters of SHA-256(<source>|<locators>|<raw-version-string>)

Additional metadata for unresolved versions:

FieldDescription
declared.versionResolved"false"
declared.unresolvedReasonOne of: cpm-missing, property-unresolved, version-omitted
declared.rawVersionOriginal unresolved string (e.g., $(SerilogVersion))

This explicit key format prevents collisions with real pkg:nuget/<id>@<ver> PURLs.

Bundling Detection

The analyzer detects bundled executables (single-file apps, ILMerge/ILRepack assemblies) using bounded candidate selection:

Candidate Selection Rules

Bundling Metadata

When bundling is detected, metadata is attached to entrypoint components (or synthetic bundle markers):

FieldDescription
bundle.detected"true"
bundle.filePathRelative path to bundled executable
bundle.kindsinglefile, ilmerge, ilrepack, costurafody, unknown
bundle.sizeBytesFile size in bytes
bundle.estimatedAssembliesEstimated number of bundled assemblies
bundle.indicator[N]Detection indicators (top 5)
bundle.skipped"true" if file was skipped
bundle.skipReasonReason for skipping (e.g., size-exceeded)

Dependency Edges

When emitDependencyEdges=true is set in the analyzer configuration (dotnet-il.config.json), the analyzer emits dependency edge metadata for both installed and declared packages.

Edge Metadata Format

Each edge is emitted with the following metadata fields:

FieldDescription
edge[N].targetNormalized package ID of the dependency
edge[N].reasonRelationship type (e.g., declared-dependency)
edge[N].confidenceConfidence level (high, medium, low)
edge[N].sourceSource of the edge information (deps.json, packages.lock.json)

Edge Sources

Example Configuration

{
  "emitDependencyEdges": true
}

Central Package Management (CPM)

The analyzer supports .NET CPM via Directory.Packages.props:

  1. When ManagePackageVersionsCentrally=true in the project or props file
  2. Package versions are resolved from <PackageVersion> items in Directory.Packages.props
  3. If a package version cannot be found in CPM, it’s marked as unresolved with declared.unresolvedReason=cpm-missing

Known Limitations

  1. No full MSBuild evaluation: The analyzer uses lightweight XML parsing, not MSBuild evaluation. Complex conditions and imports may not be fully resolved.

  2. No restore/feed access: The analyzer does not perform NuGet restore or access package feeds. Only locally available information is used.

  3. Property resolution: Property placeholders ($(PropertyName)) are resolved using Directory.Build.props and project properties, but transitive or complex property evaluation is not supported.

  4. Bundled content: Bundling detection identifies likely bundles but cannot extract embedded dependency information.

Files Created/Modified

See SPRINT_0404_0001_0001_scanner_dotnet_detection_gaps.md for implementation details and decisions.