Skip to content

Upgrade to .NET 10 and update NuGet packages to remove known vulnerabilities - #507

Draft
angrave wants to merge 2 commits into
stagingfrom
upgrade-dotnet10
Draft

angrave wants to merge 2 commits into
stagingfrom
upgrade-dotnet10

Conversation

@angrave

@angrave angrave commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

.NET 8 reaches end of support on 2026-11-10. This moves WebAPI to .NET 10 (LTS) and updates NuGet packages so that dotnet list package --vulnerable --include-transitive is clean for every project. Before: 13 vulnerable packages, including 1 critical (NuGet.Packaging) and several high (Npgsql, Microsoft.OpenApi.Readers, Microsoft.Data.SqlClient, Microsoft.Extensions.Caching.Memory).

The previous attempt (#497, reverted in #501) only changed the Docker base images. It left the projects on net8.0 with global.json pinned to 8.0. This PR moves the framework, SDK, packages, Dockerfiles and CI together.

Changes

  • net10.0 in all projects. global.json requires SDK 10.0.100+ (rollForward: latestFeature). CI uses 10.0.x.
  • Docker: sdk:10.0-noble / aspnet:10.0-noble. TaskEngine uses libasound2t64 and drops the libssl1.1 .deb workaround: Speech SDK 1.53 works with the system OpenSSL 3.
  • Package bumps: Microsoft.* / EF Core 10.0.14, Npgsql EF 10.0.3, RestSharp 114, Speech 1.53, Box.V2.Core 6.20.2 (the 10.x line is a different SDK), Swashbuckle 9.0.6 (keeps Microsoft.OpenApi 1.x), Microsoft.OpenApi 1.6.31, Protobuf / Grpc.Tools, CsvHelper 33, test packages.
  • Removed unused packages that pulled in vulnerable dependencies: EntityFrameworkCore.SqlServer, VisualStudio.Web.CodeGeneration.Design, Extensions.Hosting (now part of the shared framework), EF6 EntityFramework (UnitTests).
  • DateTime fix: Npgsql 8 in legacy timestamp mode read timestamp without time zone columns as DateTimeKind.Utc; Npgsql 9+ reads them as Unspecified. Without a fix, API JSON loses the trailing Z and clients would treat UTC times as local time. A value converter in CTDbContext.ConfigureConventions restores Utc on read. It doesn't change the schema, and migrations still apply with no pending model changes.

Deliberately not upgraded (no known vulnerabilities; upgrading means code changes): RabbitMQ.Client 7 (async rewrite), Swashbuckle 10 / Microsoft.OpenApi 2, ApplicationInsights 3, NEST → Elastic.Clients.Elasticsearch, xunit v3.

Testing

  • Solution builds in sdk:10.0. UnitTests: 193/193 pass.
  • Built both images and ran them with Postgres 11.7 and RabbitMQ 4.2 (pyapi devdocker compose). EF migrations apply. TaskEngine connects and consumes from all queues.
  • Ran the current classtranscribe/api:staging image next to the new one against the same database and crawled every GET route in the swagger spec as the test user. 294 normalized responses are identical; the only difference is /api/Admin/GetVersion build info. The swagger spec has the same 127 routes; the differences are cosmetic ("OK" instead of "Success", TimeSpan now documented as a string).
  • Speech SDK 1.53 in the new TaskEngine image: native library loads, the TLS connection to Azure works, and a dummy key gets the expected 401 AuthenticationFailure.

🤖 Generated with Claude Code

angrave and others added 2 commits October 27, 2026 18:26
…ilities

- Target net10.0 in all projects; global.json requires SDK 10.0.100+ (rollForward latestFeature); CI uses 10.0.x
- Docker: sdk/aspnet 10.0-noble images; TaskEngine uses libasound2t64 and no longer
  needs the libssl1.1 workaround (Speech SDK 1.53 works with OpenSSL 3)
- Bump Microsoft/EF Core packages to 10.0.14, Npgsql EF to 10.0.3, RestSharp 114,
  Speech SDK 1.53, Box.V2.Core 6.20.2, Swashbuckle 9.0.6, Microsoft.OpenApi 1.6.31,
  Protobuf/Grpc.Tools, CsvHelper 33 and test packages
- Remove unused packages that pulled in vulnerable dependencies:
  EntityFrameworkCore.SqlServer, VisualStudio.Web.CodeGeneration.Design,
  Extensions.Hosting (now part of the shared framework), EntityFramework 6 (UnitTests)
- Npgsql 9+ reads "timestamp without time zone" as DateTimeKind.Unspecified (Npgsql 8
  legacy mode returned Utc); add an EF value converter so DateTimes read from the DB are
  Utc again and API JSON keeps its trailing 'Z'

`dotnet list package --vulnerable --include-transitive` is now clean for all projects.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@angrave

angrave commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

Adversarial review (GLM-5.3 via opencode) and follow-up checks

GLM-5.3 reviewed this change read-only and found no confirmed functional regressions. It independently confirmed the DateTime converter is correct: Npgsql v8's legacy converter decoded timestamp as Utc, and v9+ decodes it as Unspecified. It also confirmed that the legacy switch is still in effect, since EF Core 9+ would throw on Migrate() if the timestamp mapping had changed. I checked each of its findings:

# Finding Outcome
1 TaskEngine DownloadAllPlaylists compares Term.EndDate (DateTime) with a DateTimeOffset; untested on EF Core 10 Verified OK. The new TaskEngine ran it against Postgres: publishing 1 tasks … Complete
2 Swagger schema changes (TimeSpan now string/date-span, OpenAPI 3.0.4) Known and listed in the PR. JSON on the wire is unchanged. Only clients generated from the spec would see a difference (the FrontEnd doesn't generate one)
3 Write path and date-filtered queries untested Verified OK. POST /api/Logs through the old and new API, then UserLogs/ByEvent and CourseLogs with start/end given as Z, no zone, +05:00, and defaults: responses identical, and both stored CreatedAt in UTC
4 RestSharp 110 → 114 in the CILogon token exchange Verified OK. Captured the raw request from both versions with the same code: body, encoding and content type identical, header order differs only. id_token is parsed identically
5 Box.V2.Core 5 → 6 runtime flows untested Needs Box credentials. The API surface used compiles unchanged. Manual smoke test recommended on staging
6 Speech SDK 1.34 → 1.53: only TLS and auth verified Needs an Azure key. Run one transcription on staging
7 CI uses actions/setup-dotnet@v1 Fixed: now v4
8 Stale amd64/libssl comment; unused legacy packages Comment removed. The EF Core 1.x/2.x-era no-op packages are left for a separate cleanup
9 Grpc.Core 2.46 / RabbitMQ.Client 6 kept Deliberate (no known vulnerabilities; upgrading means code changes)

🤖 Generated with Claude Code

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.

1 participant