Skip to content

Separated paket.lock handling from NuGetComponentDetector to PaketCom…#1502

Open
Thorium wants to merge 8 commits intomicrosoft:mainfrom
Thorium:paket-component-detector
Open

Separated paket.lock handling from NuGetComponentDetector to PaketCom…#1502
Thorium wants to merge 8 commits intomicrosoft:mainfrom
Thorium:paket-component-detector

Conversation

@Thorium
Copy link

@Thorium Thorium commented Oct 29, 2025

Fix Paket Package Manager Support for .NET Ecosystem (#1404)

Overview

This PR adds comprehensive support for Paket, a mature and widely-used alternative package manager in the .NET ecosystem. Paket has been a critical dependency management tool for large enterprise C# applications and small F# projects since 2014, yet it was previously not properly supported as a separate detector in this codebase.

Business Impact

Why Paket Matters for Enterprise .NET

  1. Significant Market Adoption: Paket is the de facto standard package manager for F# projects and is heavily used in large-scale enterprise C# applications, particularly in:

    • Financial services (banking, trading systems)
    • Data analytics and scientific computing
    • Cloud infrastructure and DevOps tooling
    • Government and compliance-heavy industries
  2. Enterprise-Grade Dependency Management: Paket solves critical problems that NuGet has historically struggled with:

    • Deterministic Builds: Guarantees exact same package versions across all environments
    • Transitive Dependency Control: Fine-grained control over nested dependencies
    • Conflict Resolution: Superior algorithm for resolving version conflicts
    • Multi-Project Solutions: Centralized dependency management across large codebases
  3. Security and Compliance: Organizations using Paket require accurate dependency detection for:

    • Security vulnerability scanning (SBOM generation)
    • License compliance auditing
    • Supply chain risk management
    • Regulatory compliance (SOC2, GDPR, HIPAA)

Technical Justification for Separation

Why Paket Deserves Its Own Detector

While Paket manages NuGet packages, treating it as merely a "NuGet variant" is architecturally incorrect for several reasons:

1. Distinct Lock File Format

Paket's paket.lock file has a fundamentally different structure from NuGet's lock files:

// Paket structure
GROUP Build
RESTRICTION: == net6.0
STORAGE: NONE
NUGET
  remote: https://api.nuget.org/v3/index.json
    Package.Name (1.0.0) - restriction: || (>= net462) (>= netstandard2.0)
      Dependency (>= 2.0) - restriction: >= net8.0

// NuGet structure (project.assets.json)
{
  "version": 3,
  "targets": {
    ".NETFramework,Version=v4.7.2": {
      "Package.Name/1.0.0": {
        "dependencies": { ... }
      }
    }
  }
}

2. Different Dependency Resolution Semantics

  • Paket: Explicit graph with framework-specific restrictions and group isolation
  • NuGet: Implicit resolution with automatic conflict handling
  • Impact: Mixing detection logic would create false positives/negatives

3. Multiple Dependency Sources

Paket's paket.lock includes:

  • NUGET: NuGet packages (what we detect)
  • GITHUB: Direct GitHub repository references
  • HTTP: Direct file downloads from URLs
  • GIT: Git repository dependencies

Treating Paket as "just NuGet" ignores this multi-source reality and could lead to incomplete dependency graphs.

4. Group-Based Dependency Isolation

Paket supports dependency groups (Build, Server, Test, Client) which are:

  • Logically isolated from each other
  • May have different framework restrictions
  • Critical for understanding the true dependency scope

5. Previous Architecture Was Incorrect

The NuGet detector previously included paket.lock in its search patterns, which was:

  • Architecturally wrong: Mixed concerns of two different package managers
  • Incomplete: Didn't properly parse Paket's format
  • Misleading: Reported Paket packages under "NuGet" detector
  • Bug-prone: Could miss packages or create duplicates

Implementation Details

What This PR Delivers

1. New Paket Detector (PaketComponentDetector.cs)

  • Standalone detector specifically for paket.lock files
  • Properly parses Paket's hierarchical format:
    • GROUP sections
    • RESTRICTION clauses
    • STORAGE directives
    • Framework-specific dependency restrictions
  • Correctly identifies explicit vs. transitive dependencies
  • Handles multiple remote sources

2. Comprehensive Test Coverage (15 tests)

Tests cover real-world scenarios including:

  • Simple package detection
  • Complex dependency trees
  • Multiple groups (Build, Server, Test, Client)
  • Framework-specific restrictions (- restriction: || (>= net462) (>= net8.0))
  • Storage directives (STORAGE: NONE)
  • Version constraints with all operators (>=, <, ~>, exact)
  • Pre-release and build metadata versions
  • Mixed HTTP/GITHUB/NUGET sections (correctly ignoring non-NuGet)
  • Edge cases (empty files, malformed entries)

3. Clean Architecture

  • Separation of Concerns: Paket detection logic is now isolated from NuGet
  • Single Responsibility: Each detector handles only its package manager
  • No Duplication: Removed paket.lock from NuGet detector's search patterns
  • Proper Registration: Added to dependency injection container

4. Complete Documentation

  • Detector documentation (docs/detectors/paket.md)
  • Updated main detector list (docs/detectors/README.md)
  • Updated NuGet documentation to remove Paket references

Code Quality

  • ✅ All 15 unit tests passing
  • ✅ Zero build warnings or errors
  • ✅ Follows existing detector patterns and conventions
  • ✅ Code analysis rules satisfied (CA1866, IDE0005, FAA0001)
  • ✅ Proper error handling and logging
  • ✅ Efficient regex-based parsing

Risk Assessment

Low Risk Change

  1. Additive Only: No breaking changes to existing detectors
  2. Well-Tested: 15 comprehensive tests including real-world scenarios
  3. Isolated: New detector doesn't affect other detection logic
  4. Backwards Compatible: Existing scans continue to work as before

What Could Go Wrong (and Why It Won't)

"Breaking NuGet detection"
✅ NuGet detector is unchanged except for removing incorrect paket.lock reference

"Missing packages"
✅ Actually fixes missing packages - Paket projects were underreported before

"Performance impact"
✅ Minimal - only scans paket.lock files (typically 1 per solution)

Real-World Validation

Successfully tested against real-world paket.lock from Thorium/WebsitePlayground:

  • ✅ Detected all 100+ packages across 4 groups
  • ✅ Properly handled complex framework restrictions
  • ✅ Correctly identified explicit vs. transitive dependencies
  • ✅ Ignored HTTP and GITHUB sections as expected
  • ✅ No false positives or duplicates

Migration Path

For Users

No action required. Paket projects will now be automatically and correctly detected.

For Maintainers

Before: Paket packages incorrectly reported under "NuGet" detector
After: Paket packages correctly reported under "Paket" detector

This is a data quality improvement, not a breaking change.

Success Metrics

Post-deployment, we expect:

  • ✅ Increased detection coverage for .NET projects using Paket
  • ✅ More accurate SBOM generation for enterprise F# and C# codebases
  • ✅ Better security posture for organizations using Paket
  • ✅ Reduced false negatives in vulnerability scanning

Conclusion

This PR elevates Paket to its rightful place as a first-class package manager in the .NET ecosystem, alongside NuGet. By properly separating concerns and implementing robust detection logic, we ensure accurate dependency tracking for the thousands of enterprise applications that rely on Paket for deterministic, conflict-free dependency management.

The implementation is low-risk, well-tested, and architecturally sound. It fixes an existing gap in detection coverage while improving code organization and maintainability.

Files Changed

Added:
  src/Microsoft.ComponentDetection.Detectors/paket/PaketComponentDetector.cs
  test/Microsoft.ComponentDetection.Detectors.Tests/PaketComponentDetectorTests.cs
  docs/detectors/paket.md

Modified:
  src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs
  src/Microsoft.ComponentDetection.Detectors/nuget/NuGetComponentDetector.cs
  docs/detectors/README.md
  docs/detectors/nuget.md

Ready for Review
All tests passing | Zero warnings | Complete documentation | Real-world validated

@Thorium Thorium requested a review from a team as a code owner October 29, 2025 12:32
@Thorium Thorium requested a review from pauld-msft October 29, 2025 12:32
@FernandoRojo
Copy link
Contributor

Hey @Thorium! Sorry for the delay in reviewing this, but thanks for putting this together! Your implementation is a significant improvement over the current implementation and we're excited to have more contributions.

That said, there are a few things that need to be addressed to move forward with this.

Primarily, The Initial merge of a new detector should be IDefaultOff to allow us to verify telemetry and methodically promote the detector as we establish confidence. If there is substantial interest in promotion to a default detector then we can begin the process of moving it through those phases.

I will add other comments on specific items in the PR but that was the big one.

Copy link
Contributor

@FernandoRojo FernandoRojo left a comment

Choose a reason for hiding this comment

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

Overall i'm very satisfied with the detector as is, and would be very happy to merge after setting the DefaultOff interface, and we can work through next steps if we want to promote this to a default detector.

Copilot AI review requested due to automatic review settings March 24, 2026 10:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class Paket (paket.lock) detection to the Component Detection tool by introducing a dedicated Paket detector, wiring it into the orchestrator, updating NuGet detection to stop scanning Paket lockfiles, and documenting the new detector.

Changes:

  • Added PaketComponentDetector to parse paket.lock and register NuGet components/relationships.
  • Registered the new detector in DI and removed paket.lock from NuGetComponentDetector search patterns.
  • Added Paket detector docs and a new test suite.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
test/Microsoft.ComponentDetection.Detectors.Tests/PaketComponentDetectorTests.cs Adds unit tests for Paket lock parsing scenarios.
src/Microsoft.ComponentDetection.Orchestrator/Extensions/ServiceCollectionExtensions.cs Registers PaketComponentDetector in DI.
src/Microsoft.ComponentDetection.Detectors/paket/PaketComponentDetector.cs Implements a new file-based detector for paket.lock.
src/Microsoft.ComponentDetection.Detectors/nuget/NuGetComponentDetector.cs Removes paket.lock from NuGet detector search patterns.
docs/detectors/paket.md Documents Paket detection behavior and limitations.
docs/detectors/nuget.md Updates NuGet docs to remove Paket references.
docs/detectors/README.md Adds Paket detector to the detectors list.

Thorium and others added 2 commits March 24, 2026 11:09
Copilot suggestion commit

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 24, 2026 11:17
@Thorium
Copy link
Author

Thorium commented Mar 24, 2026

All feedback addressed.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

@Thorium
Copy link
Author

Thorium commented Mar 25, 2026

@FernandoRojo Paket typically dumps all solution assemblies to a single paket.lock where are potentially GROUPS. Should this tool exclude (case-insensitively) groups Test/Tests/Docs/Build ? Because those packages don't end-up to the end product, they are just development time tools.

Edit: This is now fixed in a new commit

Copilot AI review requested due to automatic review settings March 25, 2026 10:15
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comment on lines +78 to +85
## Known Limitations

- This detector is currently **DefaultOff** and must be explicitly enabled
- Only NuGet dependencies from the `NUGET` section are detected
- GitHub, HTTP, and Git dependencies are not currently supported
- Without cross-referencing the `paket.dependencies` file, the detector cannot reliably distinguish between direct and transitive dependencies; it uses the dependency graph within the lock file to approximate this
- Development dependency classification is based on group names only; it does not cross-reference `paket.references` files to verify which packages are actually used by test vs. production projects (planned for a future iteration)
- The detector assumes the lock file format follows the standard Paket conventions
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The docs/PR narrative says no user action is required, but the Paket detector is marked DefaultOff here without showing how to enable it (e.g., --DetectorArgs Paket=EnableIfDefaultOff). Also, since the NuGet detector currently still scans paket.lock, enabling Paket may result in duplicated NuGet components unless the scan is filtered to only run Paket. Consider updating this section to include the exact enablement syntax and to clarify how to avoid double-counting until NuGet no longer processes paket.lock.

Copilot uses AI. Check for mistakes.
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.

3 participants