Move to .NET 10, and give the DbContext its own project - #50
Merged
Conversation
Three changes that only make sense together. **.NET 10.** .NET 9 left support in May 2026, so every deployment of this service has been running an unpatched runtime. Target frameworks, the Microsoft.* and Npgsql packages, both container base images and CI's SDK all move to the 10.0 line. Swashbuckle stays on 9.0.6 — its 10.x release is a Microsoft.OpenApi v2 rewrite and belongs in its own change. **AuthService.Data.** `dotnet ef` loads a migrations assembly out of the startup project's output, so AuthService has to reference AuthService.Migrations.*; those projects need ApplicationDbContext, which lived in AuthService. That cycle is why no migration set could ever be generated (#17). The context, the entity types, the design-time factory and the provider wiring now live in a project that depends on nothing else here, and the graph is acyclic. Namespaces are unchanged, so not one `using` moved and the diff is file renames plus project files. `scripts/generate-migrations.sh` works now. Running it and committing the result is what remains of #17; CI's migration guard stops being a no-op the moment that lands. **Multi-arch images.** The published image gains linux/arm64, the last open item on #26. The Dockerfile cross-compiles with `-a $TARGETARCH` from a build-platform SDK rather than building under QEMU, which is what keeps the second platform cheap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqCTaRLXbyujh5WPaEMj7N
.NET 10 deprecates it (ASPDEPR005) in favour of KnownIPNetworks, which holds System.Net.IPNetwork rather than the HttpOverrides type of the same name. The upgrade compiled with two new warnings; this clears them. Not purely mechanical: System.Net.IPNetwork insists its base address is the network address, so a value like "10.0.0.5/8" now throws where the old type accepted it. Parsed through TryParse so a malformed Network:KnownNetworks entry is skipped like every other one here, rather than failing startup. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AqCTaRLXbyujh5WPaEMj7N
This was referenced Aug 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
The service targets .NET 10 instead of .NET 9 — target frameworks, packages, both container base images and CI's SDK.
ApplicationDbContextand the entity types move out ofAuthServiceinto a newAuthService.Dataproject, which is what finally makes migration generation possible. The published GHCR image gainslinux/arm64.Behaviourally the service is identical: no endpoint, response shape, configuration key or default changed.
Why
Closes #38, closes #41, closes #47
.NET 9 left support in May 2026. Every deployment of this service has been running an unpatched runtime since — which is a poor position for the component that issues everyone's tokens. Dependabot has been asking for the two halves of this separately (#38 for the runtime image, #41 for the SDK image); #38's Docker build failed because bumping the runtime image alone strands a
net9.0app on a 10.0 runtime. It only works as one change.The
AuthService.Dataextraction is the refactor #17 has been blocked on, and thelinux/arm64platform is the last open item from #26.Approach and alternatives
The reference cycle (#17).
dotnet efloads a migrations assembly out of the startup project's output directory, soAuthServicehas to referenceAuthService.Migrations.*. Those projects in turn need theApplicationDbContexttype their[DbContext(...)]attributes name — which lived inAuthService. Every attempt to generate a set failed withFile '.../AuthService.Migrations.PostgreSQL.dll' not found, and no combination of flags resolved it.src/AuthService.Data/holds the entity types,ApplicationDbContext,DesignTimeDbContextFactoryandDatabaseProviderExtensions, and depends on nothing else in the repository:Namespaces are deliberately unchanged (
AuthService.Data,AuthService.Models,AuthService.Extensions), so not oneusingin the service or the tests was touched. The C# diff is pure file renames; everything else is project files.DbSeederstayed behind inAuthService— it seeds throughIServiceProviderand logs againstProgram, so it belongs with the application, not the model.Rejected: renaming namespaces to match the new assembly, which would have turned a rename-only diff into a change to every file in the repository for no benefit.
Swashbuckle stays on 9.0.6. Dependabot's #48 offers 10.2.3, which fails to build: OpenAPI.NET v2 moved everything out of
Microsoft.OpenApi.Modelsand removedOpenApiSecurityScheme.Reference. That is an API migration, not a version bump, and it does not belong in a framework upgrade. 9.0.6 shipslib/net9.0, which resolves cleanly onnet10.0.Cross-compiling rather than QEMU. The Dockerfile pins its build stage to
$BUILDPLATFORMand passes-a $TARGETARCHto restore and publish. Emulating a .NET SDK build to produce an arm64 image is an order of magnitude slower than cross-compiling, and slow enough to make the second platform not worth having.Test tooling. Also carries the bumps from #45 (
Microsoft.NET.Test.Sdk18.9.0,xunit2.9.3,xunit.runner.visualstudio3.1.5), which could not merge on its own after #44 landed in the same block of the file.Security impact
Positive, and it is the main reason for the change: the service moves off a runtime that stopped receiving security patches in May 2026, onto the current LTS.
Nothing else about the security surface moves. Token signing, the JWKS endpoint, hashing and the authentication pipeline are untouched.
Breaking changes
None for consumers of the API.
For anyone building from source: the solution has a fourth project, and the .NET 10 SDK is now required. The Dockerfile copies all four project files, so
docker compose upand the published image are unaffected.Schema changes
None. The model is byte-identical — the files moved, nothing in them changed, so
docs/schema/upgrade/needs no new DDL.Worth saying explicitly since this PR is about migrations infrastructure: it makes generating a set possible, it does not generate one.
Database:SchemaModestill defaults toEnsureCreated.Checklist
dotnet build AuthService.slnpassesdotnet test AuthService.slnpassesdotnet format --verify-no-changespassesThe three build boxes are unticked deliberately: the environment this was written in has no .NET SDK and its egress policy blocks downloading one, so CI on this PR is the first execution of any of them. Please treat a green CI run, not my say-so, as the evidence.
Generated by Claude Code