From d8fcf302356ad05d2bdd6c79c636ae12c1d252a6 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 20:42:35 +0000 Subject: [PATCH 1/2] Disable GSS encryption on the database connection Npgsql defaults GssEncryptionMode to Prefer, so opening a physical connection loads libgssapi_krb5.so.2 for a GSS encryption probe. The Alpine runtime image has no krb5-libs, and the container printed "Error loading shared library libgssapi_krb5.so.2" at startup. The app never uses Kerberos or GSS, so the connection string now disables the probe instead of the image shipping a library nothing needs. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Uovdgb1RrvqLz2omxdk9ah --- src/Data/EvilCase.Data/Bootstrap.cs | 6 ++- .../Data/ConnectionStringTests.cs | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/Tests/EvilCase.Tests/Data/ConnectionStringTests.cs diff --git a/src/Data/EvilCase.Data/Bootstrap.cs b/src/Data/EvilCase.Data/Bootstrap.cs index 5dcc3cc89..7be552e70 100644 --- a/src/Data/EvilCase.Data/Bootstrap.cs +++ b/src/Data/EvilCase.Data/Bootstrap.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Npgsql; namespace EvilBrains.EvilCase.Data; @@ -21,7 +22,10 @@ public static IServiceCollection AddEvilCaseData(this IServiceCollection service var connectionStringSection = configuration.GetRequiredSection("EvilBrains:EvilCase:ConnectionString"); var connectionString = connectionStringSection.Value ?? throw new InvalidOperationException("Connection string not found"); - options.UseNpgsql(connectionString, static npgsql => npgsql.UseEvilCaseMigrations()); + // The app never uses GSS, and the probe loads a native library the Alpine image lacks. + var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString) { GssEncryptionMode = GssEncryptionMode.Disable }; + + options.UseNpgsql(connectionStringBuilder.ConnectionString, static npgsql => npgsql.UseEvilCaseMigrations()); options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); options.AddInterceptors( serviceProvider.GetRequiredService(), diff --git a/src/Tests/EvilCase.Tests/Data/ConnectionStringTests.cs b/src/Tests/EvilCase.Tests/Data/ConnectionStringTests.cs new file mode 100644 index 000000000..51c707030 --- /dev/null +++ b/src/Tests/EvilCase.Tests/Data/ConnectionStringTests.cs @@ -0,0 +1,40 @@ +using EvilBrains.EvilCase.Data; +using EvilBrains.EvilCase.Data.DbContexts; +using EvilBrains.EvilCase.Domain.Users; +using EvilBrains.EvilCase.Tests.Auth; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting.Internal; +using Npgsql; + +namespace EvilBrains.EvilCase.Tests.Data; + +public class ConnectionStringTests +{ + [Test] + public void TheContextDisablesGssEncryption() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary { ["EvilBrains:EvilCase:ConnectionString"] = "Host=127.0.0.1;Database=evilcase-tests" }) + .Build(); + + var services = new ServiceCollection() + .AddSingleton(configuration) + .AddSingleton(new HostingEnvironment { EnvironmentName = "Testing" }) + .AddScoped() + .AddEvilCaseData(); + + using var provider = services.BuildServiceProvider(); + using var scope = provider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + + var connectionString = new NpgsqlConnectionStringBuilder(context.Database.GetConnectionString()); + + Assert.That( + connectionString.GssEncryptionMode, + Is.EqualTo(GssEncryptionMode.Disable), + "the connection must not probe GSS encryption, which loads a native library the Alpine image lacks"); + } +} From 13a22c377c3ae8f96197136f1e4477ca6d18ab6b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 30 Oct 2026 20:50:57 +0000 Subject: [PATCH 2/2] Drop the rationale comment and the internal hosting type from the test The test substitutes IHostEnvironment instead of constructing Microsoft.Extensions.Hosting.Internal.HostingEnvironment. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Uovdgb1RrvqLz2omxdk9ah --- src/Data/EvilCase.Data/Bootstrap.cs | 1 - src/Tests/EvilCase.Tests/Data/ConnectionStringTests.cs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Data/EvilCase.Data/Bootstrap.cs b/src/Data/EvilCase.Data/Bootstrap.cs index 7be552e70..32401bda6 100644 --- a/src/Data/EvilCase.Data/Bootstrap.cs +++ b/src/Data/EvilCase.Data/Bootstrap.cs @@ -22,7 +22,6 @@ public static IServiceCollection AddEvilCaseData(this IServiceCollection service var connectionStringSection = configuration.GetRequiredSection("EvilBrains:EvilCase:ConnectionString"); var connectionString = connectionStringSection.Value ?? throw new InvalidOperationException("Connection string not found"); - // The app never uses GSS, and the probe loads a native library the Alpine image lacks. var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString) { GssEncryptionMode = GssEncryptionMode.Disable }; options.UseNpgsql(connectionStringBuilder.ConnectionString, static npgsql => npgsql.UseEvilCaseMigrations()); diff --git a/src/Tests/EvilCase.Tests/Data/ConnectionStringTests.cs b/src/Tests/EvilCase.Tests/Data/ConnectionStringTests.cs index 51c707030..7bfb1a8a4 100644 --- a/src/Tests/EvilCase.Tests/Data/ConnectionStringTests.cs +++ b/src/Tests/EvilCase.Tests/Data/ConnectionStringTests.cs @@ -6,7 +6,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Hosting.Internal; using Npgsql; namespace EvilBrains.EvilCase.Tests.Data; @@ -22,7 +21,7 @@ public void TheContextDisablesGssEncryption() var services = new ServiceCollection() .AddSingleton(configuration) - .AddSingleton(new HostingEnvironment { EnvironmentName = "Testing" }) + .AddSingleton(Substitute.For()) .AddScoped() .AddEvilCaseData();