Skip to content

build: adopt Central Package Management + lockfiles + transitive audit#321

Open
TalZaccai wants to merge 4 commits into
mainfrom
dev/talzacc/cpm-lockfile-modernization
Open

build: adopt Central Package Management + lockfiles + transitive audit#321
TalZaccai wants to merge 4 commits into
mainfrom
dev/talzacc/cpm-lockfile-modernization

Conversation

@TalZaccai
Copy link
Copy Markdown
Contributor

@TalZaccai TalZaccai commented Jun 2, 2026

Summary

Modernizes the .NET package management stack across the whole repo as preparation for an upcoming fix-dependabot-alerts workflow port (microsoft/TypeAgent / microsoft/TypeChat equivalent). With CPM + transitive pinning in place, automated transitive vulnerability remediation becomes a one-line edit to Directory.Packages.props per fix instead of editing many csproj files.

Pairs naturally with #319 (Dependabot grouping config) but can merge independently.

What changes

Feature What it does File
Central Package Management Single source of truth for every package version new Directory.Packages.props
Central Transitive Pinning <PackageVersion> forces a transitive across all projects same
NuGetAudit transitive mode NU190x warnings for both direct and transitive vulns at restore time new Directory.Build.props

All 20 SDK-style csproj files become version-less <PackageReference> entries. Per-project version sprawl collapses (e.g. Microsoft.NET.Test.Sdk previously had 2 versions across the repo).

Vulnerabilities discovered and fixed by the new audit

The transitive-mode audit immediately surfaced two existing advisories that Dependabot had been blind to (transitive scope wasn't being audited):

Package Was Now Advisory
Microsoft.SemanticKernel 1.68.0 1.71.0 GHSA-2ww3-72rp-wpp4 — critical: arbitrary file write via AI agent function calling
Microsoft.Bcl.Memory (transitive) 10.0.2 10.0.4 (pinned) GHSA-73j8-2gch-69rq — high: DoS via Base64Url out-of-bounds read

Other version reconciliations

Conflicting versions across projects were collapsed to the highest. The orphan tests/TypeChat.Tests.Pre6 net470 project uses VersionOverride to keep its older xunit / Microsoft.NET.Test.Sdk pins (newer versions dropped net470):

  • Microsoft.NET.Test.Sdk: 18.0.1 (was 17.5.0 + 18.0.1); Pre6 VersionOverride=17.5.0
  • xunit: 2.9.3 (was 2.4.2 + 2.9.3); Pre6 VersionOverride=2.4.2
  • xunit.runner.visualstudio: 3.1.5 (was 2.4.5 + 3.1.5); Pre6 VersionOverride=2.4.5

Other bumps required by the SK 1.71 transitive graph:

  • System.Text.Json 10.0.0 → 10.0.2
  • Microsoft.Extensions.AI 9.10.2 → 10.2.0
  • System.Numerics.Tensors 10.0.1 → 10.0.2

On lockfiles (intentionally not adopted)

An earlier revision of this PR committed packages.lock.json files for every project. Per reviewer feedback that was reverted in commit b57d385:

  • NuGet lockfiles are an opt-in feature; the .NET community (including dotnet/runtime) does not commit them by default.
  • Without dotnet restore --locked-mode enforced in CI, committed lockfiles are write-only churn that adds noise to every dependency PR without providing determinism.
  • Determinism / drift-detection can be added later as a focused follow-up PR (enable RestorePackagesWithLockFile + add --locked-mode to CI) without needing this scaffolding to land first.

packages.lock.json is now in .gitignore so opportunistic local restores with --use-lock-file don't get committed back.

Local validation

  • dotnet restore TypeChat.sln: ✅ clean, zero NU190x audit warnings
  • dotnet restore tests/EmojiApp/Emoji.sln: ✅ clean
  • dotnet build TypeChat.sln -c Release /warnaserror (CI's exact build line): ✅ 0 warnings, 0 errors
  • dotnet test tests/TypeChat.UnitTests: ✅ 154 passed, 0 failed

Notes for reviewers

  • The two new top-level files (Directory.Build.props + Directory.Packages.props) carry the policy; each existing src/Directory.Build.props and examples/Directory.Build.props now explicitly <Import> the root so the MSBuild auto-discovery chain isn't truncated.
  • tests/TypeChat.Tests.Pre6 (net470) is an orphan — not in TypeChat.sln and not built by CI. Pre-existing; unrelated to this PR.

Followup PR

A separate PR will add the fix-dependabot-alerts workflow (modeled on the microsoft/TypeAgent equivalent) that takes advantage of this scaffold.


Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Modernizes the .NET package management stack for the whole repo:

1. Central Package Management (CPM) - introduces root Directory.Packages.props as the single source of truth for every package version. All <PackageReference> entries across the 20 SDK-style csproj files become version-less; the previously per-project version sprawl (e.g. 3 different Microsoft.NET.Test.Sdk versions) collapses to a single declaration.

2. Central Transitive Pinning (CentralPackageTransitivePinningEnabled) - lets a <PackageVersion> entry in Directory.Packages.props force a transitive dependency to a specific version across every project, without having to add per-project top-level <PackageReference> entries. This becomes the override mechanism for fixing transitive security advisories.

3. Lockfile mode (RestorePackagesWithLockFile=true) - generates packages.lock.json next to each csproj on every restore, committed to source control. Enables deterministic CI restores via dotnet restore --locked-mode (opt-in) and gives Dependabot accurate transitive vulnerability detection.

4. NuGetAudit transitive mode (NuGetAuditMode=all) - surfaces known advisories for both direct and transitive dependencies as NU1901-NU1904 warnings at restore time. On by default in SDK 8.0+; this just enables transitive scanning.

Side effects (vulnerabilities discovered by the new audit and fixed in this PR):

- Microsoft.SemanticKernel 1.68.0 -> 1.71.0 (CVE-2026-25592 / GHSA-2ww3-72rp-wpp4, critical: arbitrary file write via AI agent function calling. Pulled in transitively as Microsoft.SemanticKernel.Core.)

- Microsoft.Bcl.Memory pinned to 10.0.4 via transitive pinning (CVE-2026-26127 / GHSA-73j8-2gch-69rq, high: DoS via Base64Url out-of-bounds read. Was being pulled in at 10.0.2 transitively via System.Text.Json 10.x.)

Other version reconciliations (chose the higher of conflicting versions):

- Microsoft.NET.Test.Sdk: tests on net8.0 use 18.0.1; the orphan net470 project uses VersionOverride=17.5.0

- xunit: net8.0 tests use 2.9.3; orphan net470 project uses VersionOverride=2.4.2

- xunit.runner.visualstudio: net8.0 tests use 3.1.5; orphan net470 project uses VersionOverride=2.4.5

- System.Text.Json 10.0.0 -> 10.0.2 (required by SK 1.71 transitive graph)

- Microsoft.Extensions.AI 9.10.2 -> 10.2.0 (required by SK 1.71)

- System.Numerics.Tensors 10.0.1 -> 10.0.2 (required by SK 1.71)

Verified locally:

- dotnet restore TypeChat.sln: clean, zero NU190x audit warnings

- dotnet restore tests/EmojiApp/Emoji.sln: clean

- dotnet build TypeChat.sln -c Release /warnaserror: 0 warnings, 0 errors

- dotnet test tests/TypeChat.UnitTests: 154 passed, 0 failed

Note: tests/TypeChat.Tests.Pre6 (net470) is an orphan project not included in TypeChat.sln and not built by CI; it does not generate a lockfile because TypeChat.TestLib only targets net8.0. This is a pre-existing condition unrelated to this change.

This PR is preparation for the upcoming fix-dependabot-alerts workflow port - with CPM + transitive pinning + lockfiles in place, automated transitive vulnerability remediation becomes a one-line edit to Directory.Packages.props per fix instead of editing many csproj files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@TalZaccai TalZaccai requested a review from a team as a code owner June 2, 2026 04:27
Per review feedback: NuGet lockfiles are an opt-in feature (not the .NET
community default; the dotnet/runtime repo does not commit them either)
and without CI enforcement (dotnet restore --locked-mode) they are
write-only churn that adds noise to PRs without providing determinism.

This commit removes them; CPM + transitive pinning still gives us a
single source of truth for versions, and NuGetAudit (mode=all) still
catches transitive CVEs at restore time. The 19 deleted files were
introduced by the previous commit on this branch and never enforced.

- Delete 19 packages.lock.json files
- .gitignore: add packages.lock.json so opportunistic local lockfile
  restores don't get committed again
- Directory.Build.props: drop RestorePackagesWithLockFile (audit kept)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
With RestorePackagesWithLockFile removed from Directory.Build.props the
default `dotnet restore` no longer produces lockfiles, so the ignore
pattern was paranoid. A developer who explicitly runs
`dotnet restore --use-lock-file` presumably wants the output visible.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown

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

Adopts .NET Central Package Management (CPM) repository-wide, introduces a new Directory.Build.props enabling transitive NuGet audit, and uses the resulting audit signal to bump two vulnerable packages (Microsoft.SemanticKernel → 1.71.0 and a pinned transitive Microsoft.Bcl.Memory 10.0.4). All 20 SDK-style csproj files become version-less <PackageReference> entries, with the legacy tests/TypeChat.Tests.Pre6 net470 project using VersionOverride to retain its older xunit/test SDK pins.

Changes:

  • Add root Directory.Packages.props (CPM + transitive pinning) and Directory.Build.props (NuGetAudit=true, NuGetAuditMode=all); existing src/ and examples/ Directory.Build.props explicitly <Import> the root so MSBuild's first-hit walk-up isn't truncated.
  • Strip Version= attributes from every <PackageReference> across src/, examples/, tests/, and src/package/nuget.props; reconcile previously-conflicting versions to the highest (e.g. Microsoft.NET.Test.Sdk 18.0.1, xunit 2.9.3) and apply VersionOverride in the net470 Pre6 test project.
  • Bump versions surfaced by the new transitive audit: Microsoft.SemanticKernel 1.68.0 → 1.71.0, transitive Microsoft.Bcl.Memory pinned to 10.0.4, System.Text.Json 10.0.0 → 10.0.2, Microsoft.Extensions.AI 9.10.2 → 10.2.0, System.Numerics.Tensors 10.0.1 → 10.0.2.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Directory.Packages.props New CPM manifest; single source of truth for all package versions, enables transitive pinning, pins vulnerable transitive Microsoft.Bcl.Memory 10.0.4.
Directory.Build.props New repo-root props enabling NuGetAudit in all (transitive) mode.
src/Directory.Build.props Explicitly imports root Directory.Build.props so MSBuild walk-up isn't stopped here.
examples/Directory.Build.props Same explicit root import as src/.
src/package/nuget.props Removes Version from Microsoft.SourceLink.GitHub reference.
src/typechat/TypeChat.csproj Drops versions on System.ComponentModel.Annotations, System.Text.Json, Microsoft.CodeAnalysis.CSharp.
src/typechat.schema/TypeChat.Schema.csproj Drops versions on Microsoft.CodeAnalysis.CSharp, System.ComponentModel.Annotations, System.Text.Json.
src/typechat.program/TypeChat.Program.csproj Drops versions on Microsoft.CodeAnalysis.CSharp, Microsoft.CSharp.
src/typechat.sk/TypeChat.SemanticKernel.csproj Drops versions on Azure.Identity, Microsoft.CSharp, Microsoft.Extensions.Configuration.Binder, Microsoft.SemanticKernel, System.Numerics.Tensors (effective SK bump to 1.71.0 via CPM).
src/typechat.meai/TypeChat.Extensions.AI.csproj Drops versions on Azure.Identity, Microsoft.CSharp, Microsoft.Extensions.AI, Microsoft.Extensions.Configuration.Binder.
examples/typechat.examplesLib/TypeChat.ExamplesLib.csproj Drops versions on Azure.Identity, Microsoft.Extensions.Configuration.*, System.CommandLine.
tests/EmojiApp/Emoji.csproj Drops versions on the three published Microsoft.TypeChat* packages.
tests/TypeChat.TestLib/TypeChat.TestLib.csproj Drops versions on Microsoft.CSharp, Microsoft.Extensions.Configuration.Json, Microsoft.NET.Test.Sdk, xunit, xunit.runner.visualstudio.
tests/TypeChat.UnitTests/TypeChat.UnitTests.csproj Drops versions on Microsoft.NET.Test.Sdk, xunit, xunit.runner.visualstudio.
tests/TypeChat.IntegrationTests/TypeChat.IntegrationTests.csproj Drops versions on Microsoft.NET.Test.Sdk, xunit, xunit.runner.visualstudio, Xunit.SkippableFact.
tests/TypeChat.Tests.Pre6/TypeChat.Tests.Pre6.csproj Uses VersionOverride for net470-compatible older Microsoft.NET.Test.Sdk 17.5.0, xunit 2.4.2, xunit.runner.visualstudio 2.4.5; drops versions on System.Linq and coverlet.collector.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@TalZaccai TalZaccai requested a review from robgruen June 2, 2026 04:49
Resolves conflicts from main commits #314 (Microsoft.Extensions.Configuration.Binder
10.0.1 -> 10.0.2) and #319 (Dependabot grouping config).

Conflict resolution:
- 3 csproj files (examples/typechat.examplesLib, src/typechat.meai,
  src/typechat.sk): kept ours (version-less PackageReferences, as
  required by CPM).
- Directory.Packages.props: bumped Microsoft.Extensions.Configuration.Binder
  PackageVersion from 10.0.1 to 10.0.2 to absorb the #314 change centrally
  so all consumers pick it up via CPM.
- .github/dependabot.yml, OpenAIConfig.cs, integration_tests.yml: merged
  in cleanly from main without conflict.

Validation:
- dotnet restore: clean, 0 NU190x warnings
- dotnet build /warnaserror: 0 warnings, 0 errors
- dotnet test tests/TypeChat.UnitTests: 154/154 passed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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