From fd67255482d897d59f0cf7ceb2c59dc705aa2835 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Tue, 13 Jan 2026 20:34:11 -0500 Subject: [PATCH 01/20] Add some integration tests for the Server project --- bitwarden-server.sln | 8 +- .../Server.IntegrationTest.csproj | 23 ++++ test/Server.IntegrationTest/Server.cs | 44 ++++++++ test/Server.IntegrationTest/ServerTests.cs | 102 ++++++++++++++++++ 4 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 test/Server.IntegrationTest/Server.IntegrationTest.csproj create mode 100644 test/Server.IntegrationTest/Server.cs create mode 100644 test/Server.IntegrationTest/ServerTests.cs diff --git a/bitwarden-server.sln b/bitwarden-server.sln index ae9571a4a546..1a46d1e2c803 100644 --- a/bitwarden-server.sln +++ b/bitwarden-server.sln @@ -140,10 +140,11 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeederApi", "util\SeederApi\SeederApi.csproj", "{9F08DFBB-482B-4C9D-A5F4-6BDA6EC2E68F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeederApi.IntegrationTest", "test\SeederApi.IntegrationTest\SeederApi.IntegrationTest.csproj", "{A2E067EF-609C-4D13-895A-E054C61D48BB}" -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SSO.Test", "bitwarden_license\test\SSO.Test\SSO.Test.csproj", "{7D98784C-C253-43FB-9873-25B65C6250D6}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sso.IntegrationTest", "bitwarden_license\test\Sso.IntegrationTest\Sso.IntegrationTest.csproj", "{FFB09376-595B-6F93-36F0-70CAE90AFECB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.IntegrationTest", "test\Server.IntegrationTest\Server.IntegrationTest.csproj", "{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -372,6 +373,10 @@ Global {FFB09376-595B-6F93-36F0-70CAE90AFECB}.Debug|Any CPU.Build.0 = Debug|Any CPU {FFB09376-595B-6F93-36F0-70CAE90AFECB}.Release|Any CPU.ActiveCfg = Release|Any CPU {FFB09376-595B-6F93-36F0-70CAE90AFECB}.Release|Any CPU.Build.0 = Release|Any CPU + {E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -432,6 +437,7 @@ Global {A2E067EF-609C-4D13-895A-E054C61D48BB} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F} {7D98784C-C253-43FB-9873-25B65C6250D6} = {287CFF34-BBDB-4BC4-AF88-1E19A5A4679B} {FFB09376-595B-6F93-36F0-70CAE90AFECB} = {287CFF34-BBDB-4BC4-AF88-1E19A5A4679B} + {E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E01CBF68-2E20-425F-9EDB-E0A6510CA92F} diff --git a/test/Server.IntegrationTest/Server.IntegrationTest.csproj b/test/Server.IntegrationTest/Server.IntegrationTest.csproj new file mode 100644 index 000000000000..362ada84a01b --- /dev/null +++ b/test/Server.IntegrationTest/Server.IntegrationTest.csproj @@ -0,0 +1,23 @@ + + + + Exe + enable + + + + + + + + + + + + + + + + + + diff --git a/test/Server.IntegrationTest/Server.cs b/test/Server.IntegrationTest/Server.cs new file mode 100644 index 000000000000..5a34ab8326b6 --- /dev/null +++ b/test/Server.IntegrationTest/Server.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace Bit.Server.IntegrationTest; + +public class Server : WebApplicationFactory +{ + public string? ContentRoot { get; set; } + public string? WebRoot { get; set; } + public bool ServeUnknown { get; set; } + public bool? WebVault { get; set; } + public string? AppIdLocation { get; set; } + + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + base.ConfigureWebHost(builder); + + builder.ConfigureLogging(logging => + { + logging.SetMinimumLevel(LogLevel.Debug); + }); + + var config = new Dictionary + { + {"contentRoot", ContentRoot}, + {"webRoot", WebRoot}, + {"serveUnknown", ServeUnknown.ToString().ToLowerInvariant()}, + }; + + if (WebVault.HasValue) + { + config["webVault"] = WebVault.Value.ToString().ToLowerInvariant(); + } + + if (!string.IsNullOrEmpty(AppIdLocation)) + { + config["appIdLocation"] = AppIdLocation; + } + + builder.UseConfiguration(new ConfigurationBuilder().AddInMemoryCollection(config).Build()); + } +} diff --git a/test/Server.IntegrationTest/ServerTests.cs b/test/Server.IntegrationTest/ServerTests.cs new file mode 100644 index 000000000000..cf143ee2d27b --- /dev/null +++ b/test/Server.IntegrationTest/ServerTests.cs @@ -0,0 +1,102 @@ +using System.Net; +using System.Runtime.CompilerServices; + +namespace Bit.Server.IntegrationTest; + +public class ServerTests +{ + [Fact] + public async Task AttachmentsStyleUse() + { + using var tempDir = new TempDir(); + + await tempDir.WriteAsync("my-file.txt", "Hello!"); + + using var server = new Server + { + ContentRoot = tempDir.Info.FullName, + WebRoot = ".", + ServeUnknown = true, + }; + + var client = server.CreateClient(); + + var response = await client.GetAsync("/my-file.txt", TestContext.Current.CancellationToken); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("Hello!", await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken)); + } + + [Fact] + public async Task WebVaultStyleUse() + { + using var tempDir = new TempDir(); + + await tempDir.WriteAsync("index.html", ""); + await tempDir.WriteAsync(Path.Join("app", "file.js"), "AppStuff"); + await tempDir.WriteAsync(Path.Join("locales", "file.json"), "LocalesStuff"); + await tempDir.WriteAsync(Path.Join("fonts", "file.ttf"), "FontsStuff"); + await tempDir.WriteAsync(Path.Join("connectors", "file.js"), "ConnectorsStuff"); + await tempDir.WriteAsync(Path.Join("scripts", "file.js"), "ScriptsStuff"); + await tempDir.WriteAsync(Path.Join("images", "file.avif"), "ImagesStuff"); + await tempDir.WriteAsync(Path.Join("test", "file.json"), "{}"); + + using var server = new Server + { + ContentRoot = tempDir.Info.FullName, + WebRoot = ".", + ServeUnknown = false, + WebVault = true, + AppIdLocation = Path.Join(tempDir.Info.FullName, "test", "file.json"), + }; + + var client = server.CreateClient(); + + // Going to root should return the default file + var response = await client.GetAsync("", TestContext.Current.CancellationToken); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("", await response.Content.ReadAsStringAsync(TestContext.Current.CancellationToken)); + // No caching on the default document + Assert.Null(response.Headers.CacheControl?.MaxAge); + + await ExpectMaxAgeAsync("app/file.js", TimeSpan.FromDays(14)); + await ExpectMaxAgeAsync("locales/file.json", TimeSpan.FromDays(14)); + await ExpectMaxAgeAsync("fonts/file.ttf", TimeSpan.FromDays(14)); + await ExpectMaxAgeAsync("connectors/file.js", TimeSpan.FromDays(14)); + await ExpectMaxAgeAsync("scripts/file.js", TimeSpan.FromDays(14)); + await ExpectMaxAgeAsync("images/file.avif", TimeSpan.FromDays(7)); + + response = await client.GetAsync("app-id.json", TestContext.Current.CancellationToken); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Equal("application/json", response.Content.Headers.ContentType?.MediaType); + + async Task ExpectMaxAgeAsync(string path, TimeSpan maxAge) + { + response = await client.GetAsync(path); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.NotNull(response.Headers.CacheControl); + Assert.Equal(maxAge, response.Headers.CacheControl.MaxAge); + } + } + + private class TempDir([CallerMemberName] string test = null!) : IDisposable + { + public DirectoryInfo Info { get; } = Directory.CreateTempSubdirectory(test); + + public void Dispose() + { + Info.Delete(recursive: true); + } + + public async Task WriteAsync(string fileName, string content) + { + var fullPath = Path.Join(Info.FullName, fileName); + var directory = Path.GetDirectoryName(fullPath); + if (directory != null) + { + Directory.CreateDirectory(directory); + } + + await File.WriteAllTextAsync(fullPath, content, TestContext.Current.CancellationToken); + } + } +} From c7942d20ac23806a338ccaad8cc8677c363cdc28 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Tue, 13 Jan 2026 20:40:03 -0500 Subject: [PATCH 02/20] Not sure why this project got removed? --- bitwarden-server.sln | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bitwarden-server.sln b/bitwarden-server.sln index 1a46d1e2c803..409906e2d0f0 100644 --- a/bitwarden-server.sln +++ b/bitwarden-server.sln @@ -141,6 +141,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeederApi", "util\SeederApi EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SeederApi.IntegrationTest", "test\SeederApi.IntegrationTest\SeederApi.IntegrationTest.csproj", "{A2E067EF-609C-4D13-895A-E054C61D48BB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SSO.Test", "bitwarden_license\test\SSO.Test\SSO.Test.csproj", "{7D98784C-C253-43FB-9873-25B65C6250D6}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sso.IntegrationTest", "bitwarden_license\test\Sso.IntegrationTest\Sso.IntegrationTest.csproj", "{FFB09376-595B-6F93-36F0-70CAE90AFECB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.IntegrationTest", "test\Server.IntegrationTest\Server.IntegrationTest.csproj", "{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}" From 6c844ea581061bde830be0997eef201cd734a5fb Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:14:21 -0500 Subject: [PATCH 03/20] Format --- test/Server.IntegrationTest/Server.cs | 2 +- test/Server.IntegrationTest/ServerTests.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Server.IntegrationTest/Server.cs b/test/Server.IntegrationTest/Server.cs index 5a34ab8326b6..403ccdb3d33e 100644 --- a/test/Server.IntegrationTest/Server.cs +++ b/test/Server.IntegrationTest/Server.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; diff --git a/test/Server.IntegrationTest/ServerTests.cs b/test/Server.IntegrationTest/ServerTests.cs index cf143ee2d27b..e432f5377573 100644 --- a/test/Server.IntegrationTest/ServerTests.cs +++ b/test/Server.IntegrationTest/ServerTests.cs @@ -1,4 +1,4 @@ -using System.Net; +using System.Net; using System.Runtime.CompilerServices; namespace Bit.Server.IntegrationTest; From 1c9ff89db174cbb904315b12db9c32392c3a6b65 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Wed, 14 Jan 2026 10:10:29 -0500 Subject: [PATCH 04/20] capture debug output --- test/Server.IntegrationTest/Properties/AssemblyInfo.cs | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/Server.IntegrationTest/Properties/AssemblyInfo.cs diff --git a/test/Server.IntegrationTest/Properties/AssemblyInfo.cs b/test/Server.IntegrationTest/Properties/AssemblyInfo.cs new file mode 100644 index 000000000000..d0ccb303b5e1 --- /dev/null +++ b/test/Server.IntegrationTest/Properties/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: CaptureTrace] From 2ecdc13f2d2532acc348fcca0d9ca4781ff2748f Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:35:12 -0500 Subject: [PATCH 05/20] Update tests to work with the now legacy WebHostBuilder - I accidentally had the updated Program locally and that was why tests were working for me locally --- test/Server.IntegrationTest/Server.cs | 35 ++++++++++++++------------- util/Server/Program.cs | 10 ++++++-- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/test/Server.IntegrationTest/Server.cs b/test/Server.IntegrationTest/Server.cs index 403ccdb3d33e..073dbffb5a6c 100644 --- a/test/Server.IntegrationTest/Server.cs +++ b/test/Server.IntegrationTest/Server.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.TestHost; namespace Bit.Server.IntegrationTest; @@ -13,32 +12,34 @@ public class Server : WebApplicationFactory public bool? WebVault { get; set; } public string? AppIdLocation { get; set; } - protected override void ConfigureWebHost(IWebHostBuilder builder) + protected override IWebHostBuilder? CreateWebHostBuilder() { - base.ConfigureWebHost(builder); - - builder.ConfigureLogging(logging => - { - logging.SetMinimumLevel(LogLevel.Debug); - }); - - var config = new Dictionary + var args = new List { - {"contentRoot", ContentRoot}, - {"webRoot", WebRoot}, - {"serveUnknown", ServeUnknown.ToString().ToLowerInvariant()}, + "/contentRoot", + ContentRoot ?? "", + "/webRoot", + WebRoot ?? "", + "/serveUnknown", + ServeUnknown.ToString().ToLowerInvariant(), }; if (WebVault.HasValue) { - config["webVault"] = WebVault.Value.ToString().ToLowerInvariant(); + args.Add("/webVault"); + args.Add(WebVault.Value.ToString().ToLowerInvariant()); } if (!string.IsNullOrEmpty(AppIdLocation)) { - config["appIdLocation"] = AppIdLocation; + args.Add("/appIdLocation"); + args.Add(AppIdLocation); } - builder.UseConfiguration(new ConfigurationBuilder().AddInMemoryCollection(config).Build()); + var builder = WebHostBuilderFactory.CreateFromTypesAssemblyEntryPoint([.. args]) + ?? throw new InvalidProgramException("Could not create builder from assembly."); + + builder.UseSetting("TEST_CONTENTROOT_SERVER", ContentRoot); + return builder; } } diff --git a/util/Server/Program.cs b/util/Server/Program.cs index a2d7e5f68765..3d563830ab20 100644 --- a/util/Server/Program.cs +++ b/util/Server/Program.cs @@ -6,6 +6,13 @@ namespace Bit.Server; public class Program { public static void Main(string[] args) + { + var builder = CreateWebHostBuilder(args); + var host = builder.Build(); + host.Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) { var config = new ConfigurationBuilder() .AddCommandLine(args) @@ -37,7 +44,6 @@ public static void Main(string[] args) builder.UseWebRoot(webRoot); } - var host = builder.Build(); - host.Run(); + return builder; } } From a5f1b3f815878023c337a1c32c00202449cf56e2 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:55:16 -0500 Subject: [PATCH 06/20] Formatting...again --- test/Server.IntegrationTest/Properties/AssemblyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Server.IntegrationTest/Properties/AssemblyInfo.cs b/test/Server.IntegrationTest/Properties/AssemblyInfo.cs index d0ccb303b5e1..80afc76e2e38 100644 --- a/test/Server.IntegrationTest/Properties/AssemblyInfo.cs +++ b/test/Server.IntegrationTest/Properties/AssemblyInfo.cs @@ -1 +1 @@ -[assembly: CaptureTrace] +[assembly: CaptureTrace] From 753c702cccc2c5dc01c0bf91a4bb24e716fa887d Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Wed, 14 Jan 2026 13:32:52 -0500 Subject: [PATCH 07/20] Update to `IHostBuilder` style --- test/Server.IntegrationTest/Server.cs | 29 ++++++++----------- util/Server/Program.cs | 40 +++++++++++++-------------- 2 files changed, 30 insertions(+), 39 deletions(-) diff --git a/test/Server.IntegrationTest/Server.cs b/test/Server.IntegrationTest/Server.cs index 073dbffb5a6c..963e6e0ecd7e 100644 --- a/test/Server.IntegrationTest/Server.cs +++ b/test/Server.IntegrationTest/Server.cs @@ -1,6 +1,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; -using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.Configuration; namespace Bit.Server.IntegrationTest; @@ -12,34 +12,27 @@ public class Server : WebApplicationFactory public bool? WebVault { get; set; } public string? AppIdLocation { get; set; } - protected override IWebHostBuilder? CreateWebHostBuilder() + protected override void ConfigureWebHost(IWebHostBuilder builder) { - var args = new List + base.ConfigureWebHost(builder); + + var config = new Dictionary { - "/contentRoot", - ContentRoot ?? "", - "/webRoot", - WebRoot ?? "", - "/serveUnknown", - ServeUnknown.ToString().ToLowerInvariant(), + {"contentRoot", ContentRoot}, + {"webRoot", WebRoot}, + {"serveUnknown", ServeUnknown.ToString().ToLowerInvariant()}, }; if (WebVault.HasValue) { - args.Add("/webVault"); - args.Add(WebVault.Value.ToString().ToLowerInvariant()); + config["webVault"] = WebVault.Value.ToString().ToLowerInvariant(); } if (!string.IsNullOrEmpty(AppIdLocation)) { - args.Add("/appIdLocation"); - args.Add(AppIdLocation); + config["appIdLocation"] = AppIdLocation; } - var builder = WebHostBuilderFactory.CreateFromTypesAssemblyEntryPoint([.. args]) - ?? throw new InvalidProgramException("Could not create builder from assembly."); - - builder.UseSetting("TEST_CONTENTROOT_SERVER", ContentRoot); - return builder; + builder.UseConfiguration(new ConfigurationBuilder().AddInMemoryCollection(config).Build()); } } diff --git a/util/Server/Program.cs b/util/Server/Program.cs index 3d563830ab20..edebb7e0e3bc 100644 --- a/util/Server/Program.cs +++ b/util/Server/Program.cs @@ -6,27 +6,30 @@ namespace Bit.Server; public class Program { public static void Main(string[] args) - { - var builder = CreateWebHostBuilder(args); - var host = builder.Build(); - host.Run(); - } - - public static IWebHostBuilder CreateWebHostBuilder(string[] args) { var config = new ConfigurationBuilder() .AddCommandLine(args) .Build(); - var builder = new WebHostBuilder() - .UseConfiguration(config) - .UseKestrel() - .UseStartup() - .ConfigureLogging((hostingContext, logging) => + var builder = new HostBuilder() + .ConfigureWebHost(builder => { - logging.AddConsole().AddDebug(); + builder.UseConfiguration(config); + builder.UseKestrel(); + builder.UseStartup(); + builder.ConfigureKestrel((_,_) => {}); + + var webRoot = config.GetValue("webRoot"); + if (string.IsNullOrWhiteSpace(webRoot)) + { + builder.UseWebRoot(webRoot); + } }) - .ConfigureKestrel((context, options) => { }); + .ConfigureLogging(logging => + { + logging.AddConsole() + .AddDebug(); + }); var contentRoot = config.GetValue("contentRoot"); if (!string.IsNullOrWhiteSpace(contentRoot)) @@ -38,12 +41,7 @@ public static IWebHostBuilder CreateWebHostBuilder(string[] args) builder.UseContentRoot(Directory.GetCurrentDirectory()); } - var webRoot = config.GetValue("webRoot"); - if (string.IsNullOrWhiteSpace(webRoot)) - { - builder.UseWebRoot(webRoot); - } - - return builder; + var host = builder.Build(); + host.Run(); } } From 00cc684af02b5878c880c5b31e62c302740b8a44 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Wed, 14 Jan 2026 16:17:18 -0500 Subject: [PATCH 08/20] Formatting --- util/Server/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/Server/Program.cs b/util/Server/Program.cs index edebb7e0e3bc..bc00b46ecbcd 100644 --- a/util/Server/Program.cs +++ b/util/Server/Program.cs @@ -17,7 +17,7 @@ public static void Main(string[] args) builder.UseConfiguration(config); builder.UseKestrel(); builder.UseStartup(); - builder.ConfigureKestrel((_,_) => {}); + builder.ConfigureKestrel((_, _) => { }); var webRoot = config.GetValue("webRoot"); if (string.IsNullOrWhiteSpace(webRoot)) From cddcfd24602abe7e57d247a9f1b43fb17fbd378e Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Wed, 4 Mar 2026 09:01:30 -0600 Subject: [PATCH 09/20] make integration test work on existing databases --- .../Tools/SendRepositoryTests.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/Infrastructure.IntegrationTest/Tools/SendRepositoryTests.cs b/test/Infrastructure.IntegrationTest/Tools/SendRepositoryTests.cs index bcc525e0d29a..e1df69b7b083 100644 --- a/test/Infrastructure.IntegrationTest/Tools/SendRepositoryTests.cs +++ b/test/Infrastructure.IntegrationTest/Tools/SendRepositoryTests.cs @@ -37,7 +37,6 @@ public async Task CreateAsync_Works(ISendRepository sendRepository) } [DatabaseTheory, DatabaseData] - // This test runs best on a fresh database and may fail on subsequent runs with other tests. public async Task GetByDeletionDateAsync_Works(ISendRepository sendRepository) { var deletionDate = DateTime.UtcNow.AddYears(-1); @@ -61,7 +60,7 @@ public async Task GetByDeletionDateAsync_Works(ISendRepository sendRepository) }); var toDeleteSends = await sendRepository.GetManyByDeletionDateAsync(deletionDate); - var toDeleteSend = Assert.Single(toDeleteSends); - Assert.Equal(shouldDeleteSend.Id, toDeleteSend.Id); + Assert.Contains(toDeleteSends, s => s.Id == shouldDeleteSend.Id); + Assert.DoesNotContain(toDeleteSends, s => s.Id == shouldKeepSend.Id); } } From 39af40e80ad2f7b7f288364135abb76f2d7bf7de Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 11:45:25 -0600 Subject: [PATCH 10/20] mimekit .net10 support and security patch --- src/Core/Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 54a8a0483fb2..c0c05a7d6445 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -38,7 +38,7 @@ - + From 932b81a967b98de4f839ae536a6ad5cd0c9e6eca Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 14:35:47 -0600 Subject: [PATCH 11/20] updated csproj files --- Directory.Build.props | 7 ++++++- bitwarden_license/src/Sso/Sso.csproj | 3 --- .../test/SSO.Test/SSO.Test.csproj | 2 +- .../Scim.IntegrationTest.csproj | 2 +- .../Sso.IntegrationTest.csproj | 4 ++-- global.json | 4 ++-- src/Core/Core.csproj | 17 ++++++++-------- .../Infrastructure.EntityFramework.csproj | 20 ++++++++++++------- src/Notifications/Notifications.csproj | 6 +++--- .../Core.IntegrationTest.csproj | 2 +- .../Events.IntegrationTest.csproj | 2 +- .../Identity.IntegrationTest.csproj | 2 +- .../Infrastructure.Dapper.Test.csproj | 2 +- .../Infrastructure.IntegrationTest.csproj | 6 +++--- .../IntegrationTestCommon.csproj | 2 +- .../Server.IntegrationTest.csproj | 2 +- util/Migrator/Migrator.csproj | 2 +- .../MsSqlMigratorUtility.csproj | 4 ++-- util/MySqlMigrations/MySqlMigrations.csproj | 2 +- .../PostgresMigrations.csproj | 2 +- util/RustSdk/RustSdk.csproj | 2 +- util/Seeder/Seeder.csproj | 2 +- util/SeederApi/SeederApi.csproj | 2 +- util/SeederUtility/SeederUtility.csproj | 2 +- util/Setup/Setup.csproj | 2 +- .../SqlServerEFScaffold.csproj | 2 +- util/SqliteMigrations/SqliteMigrations.csproj | 2 +- 27 files changed, 57 insertions(+), 50 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index adf984f7d195..7f3d88b869ec 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - net8.0 + net10.0 2026.2.1 @@ -11,6 +11,11 @@ annotations enable true + + $(NoWarn);NU1608 diff --git a/bitwarden_license/src/Sso/Sso.csproj b/bitwarden_license/src/Sso/Sso.csproj index 709e8c2c4a52..d3adf65ffacd 100644 --- a/bitwarden_license/src/Sso/Sso.csproj +++ b/bitwarden_license/src/Sso/Sso.csproj @@ -8,9 +8,6 @@ - - - diff --git a/bitwarden_license/test/SSO.Test/SSO.Test.csproj b/bitwarden_license/test/SSO.Test/SSO.Test.csproj index 4b509c9a50a3..afa8c22104d3 100644 --- a/bitwarden_license/test/SSO.Test/SSO.Test.csproj +++ b/bitwarden_license/test/SSO.Test/SSO.Test.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/bitwarden_license/test/Scim.IntegrationTest/Scim.IntegrationTest.csproj b/bitwarden_license/test/Scim.IntegrationTest/Scim.IntegrationTest.csproj index d0d329397c91..919411df1c82 100644 --- a/bitwarden_license/test/Scim.IntegrationTest/Scim.IntegrationTest.csproj +++ b/bitwarden_license/test/Scim.IntegrationTest/Scim.IntegrationTest.csproj @@ -11,7 +11,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/bitwarden_license/test/Sso.IntegrationTest/Sso.IntegrationTest.csproj b/bitwarden_license/test/Sso.IntegrationTest/Sso.IntegrationTest.csproj index 42d0743d514b..e4d9bed852c7 100644 --- a/bitwarden_license/test/Sso.IntegrationTest/Sso.IntegrationTest.csproj +++ b/bitwarden_license/test/Sso.IntegrationTest/Sso.IntegrationTest.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable @@ -14,7 +14,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/global.json b/global.json index 970250aec979..ee5bf6a6aa84 100644 --- a/global.json +++ b/global.json @@ -1,11 +1,11 @@ { "sdk": { - "version": "8.0.100", + "version": "10.0.103", "rollForward": "latestFeature" }, "msbuild-sdks": { "Microsoft.Build.Traversal": "4.1.0", - "Microsoft.Build.Sql": "1.0.0", + "Microsoft.Build.Sql": "2.1.0", "Bitwarden.Server.Sdk": "1.4.0" } } diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index c0c05a7d6445..3728e6417b57 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -29,7 +29,7 @@ - + @@ -39,7 +39,7 @@ - + @@ -47,10 +47,10 @@ - - - - + + + + @@ -61,7 +61,7 @@ - + @@ -73,8 +73,7 @@ - - + diff --git a/src/Infrastructure.EntityFramework/Infrastructure.EntityFramework.csproj b/src/Infrastructure.EntityFramework/Infrastructure.EntityFramework.csproj index 180bcd770575..75513e6b22c1 100644 --- a/src/Infrastructure.EntityFramework/Infrastructure.EntityFramework.csproj +++ b/src/Infrastructure.EntityFramework/Infrastructure.EntityFramework.csproj @@ -2,18 +2,24 @@ $(WarningsNotAsErrors);CA1304;CA1305 + + $(NoWarn);NU1608 - - - - - - - + + + + + + + diff --git a/src/Notifications/Notifications.csproj b/src/Notifications/Notifications.csproj index 76278fdea83c..f98d955d08b5 100644 --- a/src/Notifications/Notifications.csproj +++ b/src/Notifications/Notifications.csproj @@ -8,12 +8,12 @@ - - + + - + diff --git a/test/Core.IntegrationTest/Core.IntegrationTest.csproj b/test/Core.IntegrationTest/Core.IntegrationTest.csproj index 133793d3d831..d645cdd24e41 100644 --- a/test/Core.IntegrationTest/Core.IntegrationTest.csproj +++ b/test/Core.IntegrationTest/Core.IntegrationTest.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/test/Events.IntegrationTest/Events.IntegrationTest.csproj b/test/Events.IntegrationTest/Events.IntegrationTest.csproj index dbfe14789214..1072149dc40b 100644 --- a/test/Events.IntegrationTest/Events.IntegrationTest.csproj +++ b/test/Events.IntegrationTest/Events.IntegrationTest.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable false true diff --git a/test/Identity.IntegrationTest/Identity.IntegrationTest.csproj b/test/Identity.IntegrationTest/Identity.IntegrationTest.csproj index 8a3c0d0fc221..b16c8efe10e5 100644 --- a/test/Identity.IntegrationTest/Identity.IntegrationTest.csproj +++ b/test/Identity.IntegrationTest/Identity.IntegrationTest.csproj @@ -12,7 +12,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/test/Infrastructure.Dapper.Test/Infrastructure.Dapper.Test.csproj b/test/Infrastructure.Dapper.Test/Infrastructure.Dapper.Test.csproj index 7a6bd3ba2053..f3d28d60682a 100644 --- a/test/Infrastructure.Dapper.Test/Infrastructure.Dapper.Test.csproj +++ b/test/Infrastructure.Dapper.Test/Infrastructure.Dapper.Test.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable false true diff --git a/test/Infrastructure.IntegrationTest/Infrastructure.IntegrationTest.csproj b/test/Infrastructure.IntegrationTest/Infrastructure.IntegrationTest.csproj index 262a0fe85615..c175ffd461da 100644 --- a/test/Infrastructure.IntegrationTest/Infrastructure.IntegrationTest.csproj +++ b/test/Infrastructure.IntegrationTest/Infrastructure.IntegrationTest.csproj @@ -8,9 +8,9 @@ - - - + + + diff --git a/test/IntegrationTestCommon/IntegrationTestCommon.csproj b/test/IntegrationTestCommon/IntegrationTestCommon.csproj index 8ed593d058d7..453e2dcd3e51 100644 --- a/test/IntegrationTestCommon/IntegrationTestCommon.csproj +++ b/test/IntegrationTestCommon/IntegrationTestCommon.csproj @@ -7,7 +7,7 @@ - + diff --git a/test/Server.IntegrationTest/Server.IntegrationTest.csproj b/test/Server.IntegrationTest/Server.IntegrationTest.csproj index 362ada84a01b..7798985cb2d6 100644 --- a/test/Server.IntegrationTest/Server.IntegrationTest.csproj +++ b/test/Server.IntegrationTest/Server.IntegrationTest.csproj @@ -13,7 +13,7 @@ - + diff --git a/util/Migrator/Migrator.csproj b/util/Migrator/Migrator.csproj index 29caf74f3941..a8a9859f3e7a 100644 --- a/util/Migrator/Migrator.csproj +++ b/util/Migrator/Migrator.csproj @@ -13,7 +13,7 @@ - + diff --git a/util/MsSqlMigratorUtility/MsSqlMigratorUtility.csproj b/util/MsSqlMigratorUtility/MsSqlMigratorUtility.csproj index 7e68a91b65e1..3a3df2040b81 100644 --- a/util/MsSqlMigratorUtility/MsSqlMigratorUtility.csproj +++ b/util/MsSqlMigratorUtility/MsSqlMigratorUtility.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/util/MySqlMigrations/MySqlMigrations.csproj b/util/MySqlMigrations/MySqlMigrations.csproj index b297ea10416e..cb5de6c59525 100644 --- a/util/MySqlMigrations/MySqlMigrations.csproj +++ b/util/MySqlMigrations/MySqlMigrations.csproj @@ -12,7 +12,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/util/PostgresMigrations/PostgresMigrations.csproj b/util/PostgresMigrations/PostgresMigrations.csproj index 66f3abe769e9..b0805f5b4476 100644 --- a/util/PostgresMigrations/PostgresMigrations.csproj +++ b/util/PostgresMigrations/PostgresMigrations.csproj @@ -11,7 +11,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/util/RustSdk/RustSdk.csproj b/util/RustSdk/RustSdk.csproj index 14cc01736567..61dd2bcd9602 100644 --- a/util/RustSdk/RustSdk.csproj +++ b/util/RustSdk/RustSdk.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable Bit.RustSDK diff --git a/util/Seeder/Seeder.csproj b/util/Seeder/Seeder.csproj index 1988c7d393cf..a2f07e3c18b4 100644 --- a/util/Seeder/Seeder.csproj +++ b/util/Seeder/Seeder.csproj @@ -2,7 +2,7 @@ - net8.0 + net10.0 enable enable Bit.Seeder diff --git a/util/SeederApi/SeederApi.csproj b/util/SeederApi/SeederApi.csproj index 53e9941c1cb4..43a75eab69a9 100644 --- a/util/SeederApi/SeederApi.csproj +++ b/util/SeederApi/SeederApi.csproj @@ -2,7 +2,7 @@ bitwarden-seeder-api - net8.0 + net10.0 enable enable false diff --git a/util/SeederUtility/SeederUtility.csproj b/util/SeederUtility/SeederUtility.csproj index b0e9f7b5e40b..e55b41a85dd8 100644 --- a/util/SeederUtility/SeederUtility.csproj +++ b/util/SeederUtility/SeederUtility.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 enable enable Bit.SeederUtility diff --git a/util/Setup/Setup.csproj b/util/Setup/Setup.csproj index b4ab0bd806cc..1d45d32af11b 100644 --- a/util/Setup/Setup.csproj +++ b/util/Setup/Setup.csproj @@ -13,7 +13,7 @@ - + diff --git a/util/SqlServerEFScaffold/SqlServerEFScaffold.csproj b/util/SqlServerEFScaffold/SqlServerEFScaffold.csproj index a2fb8173bf06..fd96f22655b5 100644 --- a/util/SqlServerEFScaffold/SqlServerEFScaffold.csproj +++ b/util/SqlServerEFScaffold/SqlServerEFScaffold.csproj @@ -5,7 +5,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/util/SqliteMigrations/SqliteMigrations.csproj b/util/SqliteMigrations/SqliteMigrations.csproj index 26def0dad201..259f306c2924 100644 --- a/util/SqliteMigrations/SqliteMigrations.csproj +++ b/util/SqliteMigrations/SqliteMigrations.csproj @@ -13,7 +13,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all From f53c099a639e06ccc82751802fa08bb93b49e11f Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 14:46:15 -0600 Subject: [PATCH 12/20] x509 api upgrade --- .../Auth/Models/Request/OrganizationSsoRequestModel.cs | 2 +- .../Billing/Services/Implementations/LicensingService.cs | 2 +- src/Core/Utilities/CoreHelpers.cs | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Api/Auth/Models/Request/OrganizationSsoRequestModel.cs b/src/Api/Auth/Models/Request/OrganizationSsoRequestModel.cs index 349bdebb8834..b71e809f5c32 100644 --- a/src/Api/Auth/Models/Request/OrganizationSsoRequestModel.cs +++ b/src/Api/Auth/Models/Request/OrganizationSsoRequestModel.cs @@ -147,7 +147,7 @@ public IEnumerable Validate(ValidationContext context) try { var certData = CoreHelpers.Base64UrlDecode(StripPemCertificateElements(IdpX509PublicCert)); - new X509Certificate2(certData); + X509CertificateLoader.LoadCertificate(certData); } catch (FormatException) { diff --git a/src/Core/Billing/Services/Implementations/LicensingService.cs b/src/Core/Billing/Services/Implementations/LicensingService.cs index 6f0cdec8f55b..f4a1dc0470a3 100644 --- a/src/Core/Billing/Services/Implementations/LicensingService.cs +++ b/src/Core/Billing/Services/Implementations/LicensingService.cs @@ -62,7 +62,7 @@ public LicensingService( "‎B34876439FCDA2846505B2EFBBA6C4A951313EBE"; if (_globalSettings.SelfHosted) { - _certificate = CoreHelpers.GetEmbeddedCertificateAsync(environment.IsDevelopment() ? "licensing_dev.cer" : "licensing.cer", null) + _certificate = CoreHelpers.GetEmbeddedCertificateAsync(environment.IsDevelopment() ? "licensing_dev.cer" : "licensing.cer") .GetAwaiter().GetResult(); } else if (CoreHelpers.SettingHasValue(_globalSettings.Storage?.ConnectionString) && diff --git a/src/Core/Utilities/CoreHelpers.cs b/src/Core/Utilities/CoreHelpers.cs index 1461601d184a..eb68547b0a21 100644 --- a/src/Core/Utilities/CoreHelpers.cs +++ b/src/Core/Utilities/CoreHelpers.cs @@ -141,17 +141,17 @@ public static string CleanCertificateThumbprint(string thumbprint) public static X509Certificate2 GetCertificate(string file, string password) { - return new X509Certificate2(file, password); + return X509CertificateLoader.LoadPkcs12FromFile(file, password); } - public async static Task GetEmbeddedCertificateAsync(string file, string password) + public async static Task GetEmbeddedCertificateAsync(string file) { var assembly = typeof(CoreHelpers).GetTypeInfo().Assembly; using (var s = assembly.GetManifestResourceStream($"Bit.Core.{file}")!) using (var ms = new MemoryStream()) { await s.CopyToAsync(ms); - return new X509Certificate2(ms.ToArray(), password); + return X509CertificateLoader.LoadCertificate(ms.ToArray()); } } @@ -176,7 +176,7 @@ public static string GetEmbeddedResourceContentsAsync(string file) using var memStream = new MemoryStream(); await blobRef.DownloadToAsync(memStream).ConfigureAwait(false); - return new X509Certificate2(memStream.ToArray(), password); + return X509CertificateLoader.LoadPkcs12(memStream.ToArray(), password); } catch (RequestFailedException ex) when (ex.ErrorCode == BlobErrorCode.ContainerNotFound || ex.ErrorCode == BlobErrorCode.BlobNotFound) From 43d2afab865c9fea576756fdc7edc5d13180ac92 Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 15:15:27 -0600 Subject: [PATCH 13/20] missed an x509 upgrade --- .../src/Sso/Utilities/DynamicAuthenticationSchemeProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitwarden_license/src/Sso/Utilities/DynamicAuthenticationSchemeProvider.cs b/bitwarden_license/src/Sso/Utilities/DynamicAuthenticationSchemeProvider.cs index db574e71c536..b05f91f0f3a4 100644 --- a/bitwarden_license/src/Sso/Utilities/DynamicAuthenticationSchemeProvider.cs +++ b/bitwarden_license/src/Sso/Utilities/DynamicAuthenticationSchemeProvider.cs @@ -406,7 +406,7 @@ private DynamicAuthenticationScheme GetSaml2AuthenticationScheme(string name, Ss if (!string.IsNullOrWhiteSpace(config.IdpX509PublicCert)) { var cert = CoreHelpers.Base64UrlDecode(config.IdpX509PublicCert); - idp.SigningKeys.AddConfiguredKey(new X509Certificate2(cert)); + idp.SigningKeys.AddConfiguredKey(X509CertificateLoader.LoadCertificate(cert)); } idp.ArtifactResolutionServiceUrls.Clear(); // This must happen last since it calls Validate() internally. From 943e15d2842f3e8c7bf75860f7f7f61095cd210e Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 15:16:52 -0600 Subject: [PATCH 14/20] nullable fixups --- src/Core/Settings/GlobalSettings.cs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Core/Settings/GlobalSettings.cs b/src/Core/Settings/GlobalSettings.cs index b9ba879b0b2f..0d38621bdf81 100644 --- a/src/Core/Settings/GlobalSettings.cs +++ b/src/Core/Settings/GlobalSettings.cs @@ -259,7 +259,7 @@ public string ConnectionString _readOnlyConnectionString = null; } - _connectionString = value.Trim('"'); + _connectionString = value?.Trim('"'); } } @@ -267,13 +267,13 @@ public string ReadOnlyConnectionString { get => string.IsNullOrWhiteSpace(_readOnlyConnectionString) ? _connectionString : _readOnlyConnectionString; - set => _readOnlyConnectionString = value.Trim('"'); + set => _readOnlyConnectionString = value?.Trim('"'); } public string JobSchedulerConnectionString { get => _jobSchedulerConnectionString; - set => _jobSchedulerConnectionString = value.Trim('"'); + set => _jobSchedulerConnectionString = value?.Trim('"'); } } @@ -325,19 +325,19 @@ public class AzureServiceBusSettings public string ConnectionString { get => _connectionString; - set => _connectionString = value.Trim('"'); + set => _connectionString = value?.Trim('"'); } public string EventTopicName { get => _eventTopicName; - set => _eventTopicName = value.Trim('"'); + set => _eventTopicName = value?.Trim('"'); } public string IntegrationTopicName { get => _integrationTopicName; - set => _integrationTopicName = value.Trim('"'); + set => _integrationTopicName = value?.Trim('"'); } } @@ -372,27 +372,27 @@ public class RabbitMqSettings public string HostName { get => _hostName; - set => _hostName = value.Trim('"'); + set => _hostName = value?.Trim('"'); } public string Username { get => _username; - set => _username = value.Trim('"'); + set => _username = value?.Trim('"'); } public string Password { get => _password; - set => _password = value.Trim('"'); + set => _password = value?.Trim('"'); } public string EventExchangeName { get => _eventExchangeName; - set => _eventExchangeName = value.Trim('"'); + set => _eventExchangeName = value?.Trim('"'); } public string IntegrationExchangeName { get => _integrationExchangeName; - set => _integrationExchangeName = value.Trim('"'); + set => _integrationExchangeName = value?.Trim('"'); } } } @@ -422,7 +422,7 @@ public class ConnectionStringSettings : IConnectionStringSettings public string ConnectionString { get => _connectionString; - set => _connectionString = value.Trim('"'); + set => _connectionString = value?.Trim('"'); } } @@ -445,7 +445,7 @@ public FileStorageSettings(GlobalSettings globalSettings, string urlName, string public string ConnectionString { get => _connectionString; - set => _connectionString = value.Trim('"'); + set => _connectionString = value?.Trim('"'); } public string BaseDirectory From 820d5a06067da1b9fd98f2e028a416b5db07e671 Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 15:31:58 -0600 Subject: [PATCH 15/20] fix bugged test --- .../ServiceAccounts/ServiceAccountSecretsDetailsQueryTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Queries/ServiceAccounts/ServiceAccountSecretsDetailsQueryTests.cs b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Queries/ServiceAccounts/ServiceAccountSecretsDetailsQueryTests.cs index 0f926ceae9cb..55004a7a5d9c 100644 --- a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Queries/ServiceAccounts/ServiceAccountSecretsDetailsQueryTests.cs +++ b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Queries/ServiceAccounts/ServiceAccountSecretsDetailsQueryTests.cs @@ -38,13 +38,13 @@ public async Task GetManyByOrganizationId_CallsDifferentRepoMethods( if (includeAccessToSecrets) { await sutProvider.GetDependency().Received(1) - .GetManyByOrganizationIdWithSecretsDetailsAsync(Arg.Is(AssertHelper.AssertPropertyEqual(mockSaDetails.ServiceAccount.OrganizationId)), + .GetManyByOrganizationIdWithSecretsDetailsAsync(Arg.Is(AssertHelper.AssertPropertyEqual(organizationId)), Arg.Any(), Arg.Any()); } else { await sutProvider.GetDependency().Received(1) - .GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(mockSa.OrganizationId)), + .GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(organizationId)), Arg.Any(), Arg.Any()); Assert.Equal(0, result.First().AccessToSecrets); } From 12dfdcbcb86071ab34a9947e7e9c0ad9a7da6f55 Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 18:26:00 -0600 Subject: [PATCH 16/20] dockerfiles --- bitwarden_license/src/Scim/Dockerfile | 4 ++-- bitwarden_license/src/Sso/Dockerfile | 4 ++-- src/Admin/Dockerfile | 4 ++-- src/Api/Dockerfile | 4 ++-- src/Billing/Dockerfile | 4 ++-- src/Events/Dockerfile | 4 ++-- src/EventsProcessor/Dockerfile | 4 ++-- src/Icons/Dockerfile | 4 ++-- src/Identity/Dockerfile | 4 ++-- src/Notifications/Dockerfile | 4 ++-- util/Attachments/Dockerfile | 4 ++-- util/MsSqlMigratorUtility/Dockerfile | 4 ++-- util/Setup/Dockerfile | 4 ++-- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/bitwarden_license/src/Scim/Dockerfile b/bitwarden_license/src/Scim/Dockerfile index fca3d83572dc..084b3618219a 100644 --- a/bitwarden_license/src/Scim/Dockerfile +++ b/bitwarden_license/src/Scim/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/bitwarden_license/src/Sso/Dockerfile b/bitwarden_license/src/Sso/Dockerfile index cbd049b9bd95..33d859d798e3 100644 --- a/bitwarden_license/src/Sso/Dockerfile +++ b/bitwarden_license/src/Sso/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/src/Admin/Dockerfile b/src/Admin/Dockerfile index 84248639cf7b..e0dae6ffafa5 100644 --- a/src/Admin/Dockerfile +++ b/src/Admin/Dockerfile @@ -12,7 +12,7 @@ RUN npm run build ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -47,7 +47,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/src/Api/Dockerfile b/src/Api/Dockerfile index beacee89aeb4..5e561361fe3f 100644 --- a/src/Api/Dockerfile +++ b/src/Api/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/src/Billing/Dockerfile b/src/Billing/Dockerfile index 1e182dedffdb..2455b6858c5d 100644 --- a/src/Billing/Dockerfile +++ b/src/Billing/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/src/Events/Dockerfile b/src/Events/Dockerfile index 913e94da45d8..a9efeda671f0 100644 --- a/src/Events/Dockerfile +++ b/src/Events/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/src/EventsProcessor/Dockerfile b/src/EventsProcessor/Dockerfile index 433552d321ee..b71c68ec06e2 100644 --- a/src/EventsProcessor/Dockerfile +++ b/src/EventsProcessor/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/src/Icons/Dockerfile b/src/Icons/Dockerfile index 5cd2b405d411..63fb6caca5bd 100644 --- a/src/Icons/Dockerfile +++ b/src/Icons/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -36,7 +36,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/src/Identity/Dockerfile b/src/Identity/Dockerfile index e79439f275f4..457e46401f66 100644 --- a/src/Identity/Dockerfile +++ b/src/Identity/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/src/Notifications/Dockerfile b/src/Notifications/Dockerfile index 031df0b1b67c..fcaedf8ab777 100644 --- a/src/Notifications/Dockerfile +++ b/src/Notifications/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/util/Attachments/Dockerfile b/util/Attachments/Dockerfile index 5ba22918c497..586e87c448f8 100644 --- a/util/Attachments/Dockerfile +++ b/util/Attachments/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/util/MsSqlMigratorUtility/Dockerfile b/util/MsSqlMigratorUtility/Dockerfile index b8bd7ff4a116..468b45a33f42 100644 --- a/util/MsSqlMigratorUtility/Dockerfile +++ b/util/MsSqlMigratorUtility/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -38,7 +38,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 AS app +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS app ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" diff --git a/util/Setup/Dockerfile b/util/Setup/Dockerfile index 2ab86c69ed86..db19f59661b1 100644 --- a/util/Setup/Dockerfile +++ b/util/Setup/Dockerfile @@ -1,7 +1,7 @@ ############################################### # Build stage # ############################################### -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine3.21 AS build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build # Docker buildx supplies the value for this arg ARG TARGETPLATFORM @@ -37,7 +37,7 @@ RUN . /tmp/rid.txt && dotnet publish \ ############################################### # App stage # ############################################### -FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.21 +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine ARG TARGETPLATFORM LABEL com.bitwarden.product="bitwarden" com.bitwarden.project="setup" From 14711187e0aeb3151d514eed661f8b3f23b02db1 Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 18:27:50 -0600 Subject: [PATCH 17/20] pre-net9 b64 decoding support --- .../Utilities/EncryptedStringAttribute.cs | 31 ++++++++++++++++--- test/Core.Test/Utilities/CoreHelpersTests.cs | 4 ++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/Core/Utilities/EncryptedStringAttribute.cs b/src/Core/Utilities/EncryptedStringAttribute.cs index 9c59287df6a2..70af8c74c856 100644 --- a/src/Core/Utilities/EncryptedStringAttribute.cs +++ b/src/Core/Utilities/EncryptedStringAttribute.cs @@ -1,5 +1,4 @@ -using System.Buffers.Text; -using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations; using Bit.Core.Enums; #nullable enable @@ -111,7 +110,7 @@ private static bool ValidatePieces(ReadOnlySpan encryptionPart, int requir if (requiredPieces == 1) { // Only one more part is needed so don't split and check the chunk - if (rest.IsEmpty || !Base64.IsValid(rest)) + if (rest.IsEmpty || !IsValidBase64(rest)) { return false; } @@ -128,7 +127,7 @@ private static bool ValidatePieces(ReadOnlySpan encryptionPart, int requir } // Is the required chunk valid base 64? - if (chunk.IsEmpty || !Base64.IsValid(chunk)) + if (chunk.IsEmpty || !IsValidBase64(chunk)) { return false; } @@ -141,4 +140,28 @@ private static bool ValidatePieces(ReadOnlySpan encryptionPart, int requir // No more parts are required, so check there are no extra parts return rest.IndexOf('|') == -1; } + + // System.Buffers.Text.Base64.IsValid enforces canonical padding (non-zero unused bits are rejected) + // starting with .NET 9. Bitwarden clients may produce non-canonical base64 for random encrypted bytes, + // so we validate only character set, length, and padding structure. + private static bool IsValidBase64(ReadOnlySpan value) + { + if (value.IsEmpty || value.Length % 4 != 0) return false; + + var paddingCount = 0; + if (value[^1] == '=') paddingCount++; + if (value[^2] == '=') paddingCount++; + + for (int i = 0; i < value.Length - paddingCount; i++) + { + char c = value[i]; + if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || c == '+' || c == '/')) + { + return false; + } + } + + return true; + } } diff --git a/test/Core.Test/Utilities/CoreHelpersTests.cs b/test/Core.Test/Utilities/CoreHelpersTests.cs index d006df536ba2..c9894ca74a80 100644 --- a/test/Core.Test/Utilities/CoreHelpersTests.cs +++ b/test/Core.Test/Utilities/CoreHelpersTests.cs @@ -410,7 +410,9 @@ public void TokenIsValid_Success(string unprotectedTokenTemplate, string firstPa { var protector = new TestDataProtector(string.Format(unprotectedTokenTemplate, CoreHelpers.ToEpocMilliseconds(creationTime))); - Assert.Equal(isValid, CoreHelpers.TokenIsValid(firstPart, protector, "protected_token", userEmail, id, expirationInHours)); + // TestDataProtector ignores the decoded bytes; value just needs to be valid base64url + var token = CoreHelpers.Base64UrlEncode(Encoding.UTF8.GetBytes("protected_token")); + Assert.Equal(isValid, CoreHelpers.TokenIsValid(firstPart, protector, token, userEmail, id, expirationInHours)); } private class TestDataProtector : IDataProtector From e9b108d5e3003418ef72d46a8d2c7a6b1c125a70 Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 18:47:23 -0600 Subject: [PATCH 18/20] known networks update --- src/SharedWeb/Utilities/ServiceCollectionExtensions.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs index 8d65547f7621..426926cc0bb4 100644 --- a/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs +++ b/src/SharedWeb/Utilities/ServiceCollectionExtensions.cs @@ -597,14 +597,14 @@ public static void UseForwardedHeaders(this IApplicationBuilder app, IGlobalSett var proxyNetworks = globalSettings.KnownNetworks.Split(','); foreach (var proxyNetwork in proxyNetworks) { - if (Microsoft.AspNetCore.HttpOverrides.IPNetwork.TryParse(proxyNetwork.Trim(), out var ipn)) + if (System.Net.IPNetwork.TryParse(proxyNetwork.Trim(), out var ipn)) { - options.KnownNetworks.Add(ipn); + options.KnownIPNetworks.Add(ipn); } } } - if (options.KnownProxies.Count > 1 || options.KnownNetworks.Count > 1) + if (options.KnownProxies.Count > 1 || options.KnownIPNetworks.Count > 1) { options.ForwardLimit = null; } From 5e444802a9f0e50b6180e2f9df13a527dcc9db22 Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 18:50:38 -0600 Subject: [PATCH 19/20] linq2db and ef upgrade --- .../AdminConsole/Repositories/OrganizationRepository.cs | 2 +- .../Billing/Repositories/ProviderInvoiceItemRepository.cs | 2 +- .../Dirt/Repositories/OrganizationApplicationRepository.cs | 2 +- .../Dirt/Repositories/OrganizationReportRepository.cs | 1 + .../Repositories/PasswordHealthReportApplicationRepository.cs | 2 +- .../Endpoints/IdentityServerTwoFactorTests.cs | 2 +- .../Vault/Repositories/CipherRepositoryTests.cs | 2 +- .../Factories/IdentityApplicationFactory.cs | 2 +- 8 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs index efead6e24aae..af2f11e355b1 100644 --- a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs +++ b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs @@ -10,7 +10,7 @@ using Bit.Core.Models.Data.Organizations; using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Repositories; -using LinqToDB.Tools; +using LinqToDB; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/src/Infrastructure.EntityFramework/Billing/Repositories/ProviderInvoiceItemRepository.cs b/src/Infrastructure.EntityFramework/Billing/Repositories/ProviderInvoiceItemRepository.cs index ed729070ae99..6c143ecd7153 100644 --- a/src/Infrastructure.EntityFramework/Billing/Repositories/ProviderInvoiceItemRepository.cs +++ b/src/Infrastructure.EntityFramework/Billing/Repositories/ProviderInvoiceItemRepository.cs @@ -2,7 +2,7 @@ using Bit.Core.Billing.Providers.Entities; using Bit.Core.Billing.Providers.Repositories; using Bit.Infrastructure.EntityFramework.Repositories; -using LinqToDB; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using EFProviderInvoiceItem = Bit.Infrastructure.EntityFramework.Billing.Models.ProviderInvoiceItem; diff --git a/src/Infrastructure.EntityFramework/Dirt/Repositories/OrganizationApplicationRepository.cs b/src/Infrastructure.EntityFramework/Dirt/Repositories/OrganizationApplicationRepository.cs index f408ed85ba4a..b5504906b49f 100644 --- a/src/Infrastructure.EntityFramework/Dirt/Repositories/OrganizationApplicationRepository.cs +++ b/src/Infrastructure.EntityFramework/Dirt/Repositories/OrganizationApplicationRepository.cs @@ -2,7 +2,7 @@ using Bit.Core.Dirt.Repositories; using Bit.Infrastructure.EntityFramework.Dirt.Models; using Bit.Infrastructure.EntityFramework.Repositories; -using LinqToDB; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; namespace Bit.Infrastructure.EntityFramework.Dirt.Repositories; diff --git a/src/Infrastructure.EntityFramework/Dirt/Repositories/OrganizationReportRepository.cs b/src/Infrastructure.EntityFramework/Dirt/Repositories/OrganizationReportRepository.cs index d08e70c35325..98829c8ea17c 100644 --- a/src/Infrastructure.EntityFramework/Dirt/Repositories/OrganizationReportRepository.cs +++ b/src/Infrastructure.EntityFramework/Dirt/Repositories/OrganizationReportRepository.cs @@ -8,6 +8,7 @@ using Bit.Core.Dirt.Repositories; using Bit.Infrastructure.EntityFramework.Repositories; using LinqToDB; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; diff --git a/src/Infrastructure.EntityFramework/Dirt/Repositories/PasswordHealthReportApplicationRepository.cs b/src/Infrastructure.EntityFramework/Dirt/Repositories/PasswordHealthReportApplicationRepository.cs index 296a542a8bb7..d49dd93cb035 100644 --- a/src/Infrastructure.EntityFramework/Dirt/Repositories/PasswordHealthReportApplicationRepository.cs +++ b/src/Infrastructure.EntityFramework/Dirt/Repositories/PasswordHealthReportApplicationRepository.cs @@ -2,7 +2,7 @@ using Bit.Core.Dirt.Repositories; using Bit.Infrastructure.EntityFramework.Dirt.Models; using Bit.Infrastructure.EntityFramework.Repositories; -using LinqToDB; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; namespace Bit.Infrastructure.EntityFramework.Dirt.Repositories; diff --git a/test/Identity.IntegrationTest/Endpoints/IdentityServerTwoFactorTests.cs b/test/Identity.IntegrationTest/Endpoints/IdentityServerTwoFactorTests.cs index d0d35f5d7bfe..74ee098b82f0 100644 --- a/test/Identity.IntegrationTest/Endpoints/IdentityServerTwoFactorTests.cs +++ b/test/Identity.IntegrationTest/Endpoints/IdentityServerTwoFactorTests.cs @@ -20,7 +20,7 @@ using Duende.IdentityModel; using Duende.IdentityServer.Models; using Duende.IdentityServer.Stores; -using LinqToDB; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; using NSubstitute; using Xunit; diff --git a/test/Infrastructure.EFIntegration.Test/Vault/Repositories/CipherRepositoryTests.cs b/test/Infrastructure.EFIntegration.Test/Vault/Repositories/CipherRepositoryTests.cs index a314d15ddab9..cc673e3a2487 100644 --- a/test/Infrastructure.EFIntegration.Test/Vault/Repositories/CipherRepositoryTests.cs +++ b/test/Infrastructure.EFIntegration.Test/Vault/Repositories/CipherRepositoryTests.cs @@ -8,7 +8,7 @@ using Bit.Infrastructure.EFIntegration.Test.Repositories.EqualityComparers; using Bit.Infrastructure.EntityFramework.Repositories.Queries; using Bit.Test.Common.AutoFixture.Attributes; -using LinqToDB; +using Microsoft.EntityFrameworkCore; using Xunit; using EfAdminConsoleRepo = Bit.Infrastructure.EntityFramework.AdminConsole.Repositories; using EfRepo = Bit.Infrastructure.EntityFramework.Repositories; diff --git a/test/IntegrationTestCommon/Factories/IdentityApplicationFactory.cs b/test/IntegrationTestCommon/Factories/IdentityApplicationFactory.cs index af60cadce464..12f28c586cbe 100644 --- a/test/IntegrationTestCommon/Factories/IdentityApplicationFactory.cs +++ b/test/IntegrationTestCommon/Factories/IdentityApplicationFactory.cs @@ -15,9 +15,9 @@ using Bit.Identity.IdentityServer; using Bit.Identity.IdentityServer.RequestValidators; using Bit.Test.Common.Helpers; -using LinqToDB; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; using NSubstitute; using Xunit; From f3973f0850d60c18ba226c7434e272b374837001 Mon Sep 17 00:00:00 2001 From: Derek Nance Date: Fri, 6 Mar 2026 19:01:35 -0600 Subject: [PATCH 20/20] update json deserialization err msg --- test/Core.Test/Models/Api/Request/PushSendRequestModelTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Core.Test/Models/Api/Request/PushSendRequestModelTests.cs b/test/Core.Test/Models/Api/Request/PushSendRequestModelTests.cs index e3728995999c..fd12963aac81 100644 --- a/test/Core.Test/Models/Api/Request/PushSendRequestModelTests.cs +++ b/test/Core.Test/Models/Api/Request/PushSendRequestModelTests.cs @@ -108,7 +108,7 @@ public void Validate_RequiredFieldNotProvided_Invalid(string requiredField) var serialized = JsonSerializer.Serialize(dictionary, JsonHelpers.IgnoreWritingNull); var jsonException = Assert.Throws(() => JsonSerializer.Deserialize>(serialized)); - Assert.Contains($"missing required properties, including the following: {requiredField}", + Assert.Contains($"was missing required properties including: '{requiredField}'", jsonException.Message); }