Skip to content

[SPIKE] Re-evaluate CentralPackageTransitivePinningEnabled to retire WireMock PrivateAssets="all" workaround #1051

@dlrivada

Description

@dlrivada

Context

In PR #1041 (security bump that aligned OpenTelemetry.Exporter.OpenTelemetryProtocol to 1.15.3), enabling CentralPackageTransitivePinningEnabled = true in Directory.Packages.props was tried as the cleanest way to ensure transitive package versions are pinned by Central Package Management (CPM). It was reverted because it surfaced pre-existing dependency conflicts that are out of scope for a security patch:

  1. Microsoft.CodeAnalysis.Common — Marten/JasperFx pulls 5.0.0 transitively, while the Encina central version is pinned at 4.14.0. Direct conflict, NU1605 error.
  2. Grpc.Tools — Aspire 13.2.2 pulls 2.78.0 transitively, while the Encina central version is pinned at 2.71.0. Direct conflict.

As a stopgap, Encina.OpenTelemetry.csproj and Encina.Testing.WireMock.csproj were given direct PackageReference entries with PrivateAssets="all" to pin the OTLP package without enabling CPM transitive pinning globally. After #1043 lands, Encina.OpenTelemetry legitimately consumes the OTLP package via its public API and drops PrivateAssets="all". Encina.Testing.WireMock keeps the workaround — the package is fixtures-only and doesn't consume OTLP at any API level; the reference exists purely to pin the version.

This SPIKE evaluates whether CentralPackageTransitivePinningEnabled can be enabled now that the dependency landscape may have shifted (newer Marten/JasperFx, Aspire updates, .NET 10 patch family alignment in #1041). If yes, retire the WireMock PrivateAssets="all" workaround.

Options to Evaluate

Option A: Enable CentralPackageTransitivePinningEnabled = true globally

  • Description: Set <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled> in Directory.Packages.props. NuGet pins all transitive package versions to whatever is declared centrally; conflicts surface as restore errors.
  • Pros: Single source of truth for all package versions; zero stopgap workarounds; reproducible builds across all clones; security audits become straightforward.
  • Cons: Requires resolving the Marten/JasperFx and Aspire conflicts first. May require bumping Microsoft.CodeAnalysis.Common to 5.0.0 (which itself may cascade) and Grpc.Tools to 2.78.0+ (which Aspire requires anyway).
  • Effort: M-L — depends on conflict depth.

Option B: Keep CPM transitive pinning disabled, document the WireMock workaround permanently

  • Description: Leave CentralPackageTransitivePinningEnabled off (current state). Add a permanent comment in Encina.Testing.WireMock.csproj explaining why PrivateAssets="all" is required for the OTLP reference.
  • Pros: Zero risk; no upstream coordination needed; minimal change.
  • Cons: Permanent workaround; future similar situations require new direct PrivateAssets="all" references in random packages; harder for new contributors to understand the dependency model.
  • Effort: XS — just a comment.

Option C: Enable CentralPackageTransitivePinningEnabled per-project (selective)

  • Description: Use <CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled> only on the projects that need it (e.g., Encina.OpenTelemetry, Encina.Testing.WireMock). Leave it off globally.
  • Pros: Mitigates the OTLP transitive-pinning gap without forcing the Marten/Aspire conflicts to be resolved up front.
  • Cons: Inconsistent build configuration across the repo; the per-project flag is poorly documented and not idiomatic.
  • Effort: S — but adds maintenance burden.

Decision Criteria

  • Build reproducibility — does CPM transitive pinning eliminate "works on my machine" version drift?
  • Maintenance burden — how many PrivateAssets="all" workarounds exist today, and would Option A retire them all?
  • Conflict surface — how deep are the Marten/JasperFx and Aspire conflicts now (April 2026), versus when fix(security): bump vulnerable packages (DataProtection 10.0.7, OpenTelemetry 1.15.3) #1041 was authored?
  • Security audit posture — does CPM transitive pinning make NuGet advisory triage easier?
  • Performance impact — N/A (CPM is build-time only)
  • Provider coverage — N/A (build infrastructure)

Scope

In Scope

  • Audit current state of transitive dependency conflicts: run dotnet restore --force-evaluate Encina.slnx with CentralPackageTransitivePinningEnabled = true and capture the full conflict list.
  • Compare against the conflicts documented in fix(security): bump vulnerable packages (DataProtection 10.0.7, OpenTelemetry 1.15.3) #1041 — have any been resolved upstream?
  • Estimate the cost of resolving each conflict (bump central versions, suppress, isolate to specific projects).
  • Recommend Option A, B, or C with concrete next-step issues if implementation is required.
  • Document findings in docs/infrastructure/cpm-transitive-pinning.md (new file).

Out of Scope

  • Actually implementing Option A (would be a separate [INFRA] issue).
  • General NuGet dependency hygiene cleanup beyond what CPM transitive pinning forces.
  • Migrating off Marten or Aspire if their conflict surface is judged unmanageable.

Deliverables

  • Technical document in docs/infrastructure/cpm-transitive-pinning.md with:
    • Current conflict matrix (package, source, central version, transitive version)
    • Estimated effort to resolve each conflict
    • Recommendation (Option A/B/C)
  • If Option A recommended: [INFRA] follow-up issue with concrete plan to enable CPM transitive pinning + resolve conflicts
  • If Option B recommended: PR adding a permanent comment to Encina.Testing.WireMock.csproj
  • If Option C recommended: PR adding per-project flag with rationale comment
  • Updated CLAUDE.md "Build Environment Known Issues" section if applicable

Time Box

Estimated investigation time: 4-8 hours (one focused day, including documentation).

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-ci-cdCI/CD pipelines and automationcomplexity-mediumComplexity: MediumdependenciesPull requests that update a dependency fileinvestigationResearch and evaluation tasksnugetNuGet package updatespriority-lowPriority: Low (⭐⭐)

    Projects

    Status
    Todo

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions