From 460afe1f48cf0eded8c7651e67bdfe6440139e57 Mon Sep 17 00:00:00 2001 From: Micaiah Martin Date: Tue, 4 Aug 2026 14:18:49 -0600 Subject: [PATCH 1/2] [SHOT-187] fix: Make database migration execution timeout configurable Migrations that rebuild an index on a large Event table can exceed the hardcoded five minute DbUp timeout. The whole upgrade is wrapped in a single transaction, so one slow script rolls the upgrade back and recovery needs manual SQL run against the customer database. The timeout can now be set through globalSettings__sqlServer__migrationExecutionTimeoutSeconds or the MsSqlMigratorUtility timeout option. Leaving it unset keeps the existing five minute default, so upgrades behave exactly as before. Setting it to zero applies no limit, matching sqlcmd and SqlCommand semantics. --- bitwarden-server.slnx | 1 + src/Core/Settings/GlobalSettings.cs | 2 + test/Migrator.Test/DbMigratorTests.cs | 36 + test/Migrator.Test/Migrator.Test.csproj | 28 + test/Migrator.Test/packages.lock.json | 1415 +++++++++++++++++++++++ test/Migrator.Test/xunit.runner.json | 3 + util/Migrator/DbMigrator.cs | 23 +- util/Migrator/Migrator.csproj | 4 + util/Migrator/MigratorConstants.cs | 2 + util/Migrator/SqlServerDbMigrator.cs | 3 +- util/MsSqlMigratorUtility/Program.cs | 13 +- util/Setup/EnvironmentFileBuilder.cs | 1 + util/Setup/Program.cs | 7 +- 13 files changed, 1529 insertions(+), 9 deletions(-) create mode 100644 test/Migrator.Test/DbMigratorTests.cs create mode 100644 test/Migrator.Test/Migrator.Test.csproj create mode 100644 test/Migrator.Test/packages.lock.json create mode 100644 test/Migrator.Test/xunit.runner.json diff --git a/bitwarden-server.slnx b/bitwarden-server.slnx index 634f06f7f237..cfbc1068737b 100644 --- a/bitwarden-server.slnx +++ b/bitwarden-server.slnx @@ -78,6 +78,7 @@ + diff --git a/src/Core/Settings/GlobalSettings.cs b/src/Core/Settings/GlobalSettings.cs index 6350618603c7..d6d726fe13bf 100644 --- a/src/Core/Settings/GlobalSettings.cs +++ b/src/Core/Settings/GlobalSettings.cs @@ -263,6 +263,8 @@ public class SqlSettings public bool SkipDatabasePreparation { get; set; } public bool DisableDatabaseMaintenanceJobs { get; set; } + public int? MigrationExecutionTimeoutSeconds { get; set; } + public string ConnectionString { get => _connectionString; diff --git a/test/Migrator.Test/DbMigratorTests.cs b/test/Migrator.Test/DbMigratorTests.cs new file mode 100644 index 000000000000..c63950b8e6c7 --- /dev/null +++ b/test/Migrator.Test/DbMigratorTests.cs @@ -0,0 +1,36 @@ +using Bit.Migrator; + +namespace Migrator.Test; + +public class DbMigratorTests +{ + private const int DefaultMinutes = 5; + + [Theory] + [InlineData(null)] + [InlineData(-1)] + public void ResolveExecutionTimeout_WithoutUsableOverride_UsesDefault(int? executionTimeoutSeconds) + { + var timeout = DbMigrator.ResolveExecutionTimeout(executionTimeoutSeconds, DefaultMinutes); + + Assert.Equal(TimeSpan.FromMinutes(DefaultMinutes), timeout); + } + + [Fact] + public void ResolveExecutionTimeout_ZeroOverride_MapsToNoLimit() + { + var timeout = DbMigrator.ResolveExecutionTimeout(0, DefaultMinutes); + + Assert.Equal(TimeSpan.Zero, timeout); + } + + [Theory] + [InlineData(1)] + [InlineData(3600)] + public void ResolveExecutionTimeout_WithOverride_UsesOverrideInSeconds(int executionTimeoutSeconds) + { + var timeout = DbMigrator.ResolveExecutionTimeout(executionTimeoutSeconds, DefaultMinutes); + + Assert.Equal(TimeSpan.FromSeconds(executionTimeoutSeconds), timeout); + } +} diff --git a/test/Migrator.Test/Migrator.Test.csproj b/test/Migrator.Test/Migrator.Test.csproj new file mode 100644 index 000000000000..737fdb93b630 --- /dev/null +++ b/test/Migrator.Test/Migrator.Test.csproj @@ -0,0 +1,28 @@ + + + + enable + enable + Exe + Migrator.Test + + + + + + + + + + + + + + + + + + + + + diff --git a/test/Migrator.Test/packages.lock.json b/test/Migrator.Test/packages.lock.json new file mode 100644 index 000000000000..80cbc435ef8a --- /dev/null +++ b/test/Migrator.Test/packages.lock.json @@ -0,0 +1,1415 @@ +{ + "version": 1, + "dependencies": { + "net10.0": { + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[18.7.0, 18.7.0]", + "resolved": "18.7.0", + "contentHash": "49xH9j4UzCh2hMohJp53g3wUTvyycECw7CtVht4gfCz5ykudB1uBcF6D0TtgJPjCtP76UPW53bQElKdCeX+dUg==", + "dependencies": { + "Microsoft.CodeCoverage": "18.7.0", + "Microsoft.TestPlatform.TestHost": "18.7.0" + } + }, + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[3.1.5, 3.1.5]", + "resolved": "3.1.5", + "contentHash": "tKi7dSTwP4m5m9eXPM2Ime4Kn7xNf4x4zT9sdLO/G4hZVnQCRiMTWoSZqI/pYTVeI27oPPqHBKYI/DjJ9GsYgA==" + }, + "xunit.v3": { + "type": "Direct", + "requested": "[3.2.1, 3.2.1]", + "resolved": "3.2.1", + "contentHash": "oefMPnMEQv9JXlc1mmj4XnNmylLWJA6XHncTcyM3LBvbepO+rsWfmIZ2gb2tO6WU29De4RxvEFHT5xxmsrjn8Q==", + "dependencies": { + "xunit.v3.mtp-v1": "[3.2.1]" + } + }, + "AdaptiveCards": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "b+sPwH0oyAflpgxCyNPMzH92xrQjWl6GuuEBv86/VhO6iHhiWv+PtwzqMS70nOXZQRzpl9YVHXAvn+dKot5IBQ==", + "dependencies": { + "Newtonsoft.Json": "13.0.3" + } + }, + "AspNetCoreRateLimit": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "6fq9+o1maGADUmpK/PvcF0DtXW2+7bSkIL7MDIo/agbIHKN8XkMQF4oze60DO731WaQmHmK260hB30FwPzCmEg==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.3", + "Microsoft.Extensions.Options": "6.0.0", + "Newtonsoft.Json": "13.0.2" + } + }, + "AspNetCoreRateLimit.Redis": { + "type": "Transitive", + "resolved": "2.0.0", + "contentHash": "3g6Mb4Y+rW14/oE7Qt8WFA9zS7XNdHx7TH3k/XQix7PtUWEZSSAK+VsqDhDIPkUysUHFBDUA7olNeTjytpzA/g==", + "dependencies": { + "AspNetCoreRateLimit": "5.0.0", + "StackExchange.Redis": "2.6.80" + } + }, + "AWSSDK.Core": { + "type": "Transitive", + "resolved": "4.0.3.3", + "contentHash": "YQv10JuxnciWh0QwnkarSbge4gXQV1qTURf5jkBjNUH/3jYS9QrbxopA4TK1qdjfOfP37tqiJkLSrRRNqX81aw==" + }, + "AWSSDK.SimpleEmail": { + "type": "Transitive", + "resolved": "4.0.2.5", + "contentHash": "LvV5mXlvpR3fTAJysO3KmUC6bR/KUZpdkcMJ5b6lYNpStlsFN+MXcaMh34TuwYaTCgIjF3bJb4oZifFkgh+Ccw==", + "dependencies": { + "AWSSDK.Core": "[4.0.3.3, 5.0.0)" + } + }, + "AWSSDK.SQS": { + "type": "Transitive", + "resolved": "4.0.2.5", + "contentHash": "bHA9m/2RZHNKt6NGvQ56rfEDj/pfUlcwPeCg2HmPJ3jZPyoerBuEsYvFkMP3YJNv3aoycNWZoiDk0/ULP0tEyA==", + "dependencies": { + "AWSSDK.Core": "[4.0.3.3, 5.0.0)" + } + }, + "Azure.Core": { + "type": "Transitive", + "resolved": "1.47.3", + "contentHash": "u/uCNtUWT+Q/Is7/PAMy3KP9kq5vY5klRnyAvRxO/kEa5OnV3/X5lHlCajNANC7vmej6jAqceqLBJNO/VyCKzg==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "System.ClientModel": "1.6.1", + "System.Memory.Data": "8.0.1" + } + }, + "Azure.Core.Amqp": { + "type": "Transitive", + "resolved": "1.3.1", + "contentHash": "AY1ZM4WwLBb9L2WwQoWs7wS2XKYg83tp3yVVdgySdebGN0FuIszuEqCy3Nhv6qHpbkjx/NGuOTsUbF/oNGBgwA==", + "dependencies": { + "Microsoft.Azure.Amqp": "2.6.7", + "System.Memory.Data": "1.0.2" + } + }, + "Azure.Data.Tables": { + "type": "Transitive", + "resolved": "12.11.0", + "contentHash": "MabH2HegMvZA1ocaMhEfW/idyTa3CoH64s43/V9/KFRGdVqEj0EETvd3ItDe6Bbs2teiR40KE9Kz9NLDc5DJJw==", + "dependencies": { + "Azure.Core": "1.44.1" + } + }, + "Azure.Extensions.AspNetCore.DataProtection.Blobs": { + "type": "Transitive", + "resolved": "1.3.4", + "contentHash": "zS+x0MpUMSbvZD598lwAoax+ohIeSAvGlXpT71iP7FFmMZ+Tjz/8hx+jZH/RbV2cJYTYbux8XFDll7LMPuz46g==", + "dependencies": { + "Azure.Core": "1.38.0", + "Azure.Storage.Blobs": "12.16.0", + "Microsoft.AspNetCore.DataProtection": "3.1.32" + } + }, + "Azure.Identity": { + "type": "Transitive", + "resolved": "1.11.4", + "contentHash": "Sf4BoE6Q3jTgFkgBkx7qztYOFELBCo+wQgpYDwal/qJ1unBH73ywPztIJKXBXORRzAeNijsuxhk94h0TIMvfYg==", + "dependencies": { + "Azure.Core": "1.38.0", + "Microsoft.Identity.Client": "4.61.3", + "Microsoft.Identity.Client.Extensions.Msal": "4.61.3", + "System.Security.Cryptography.ProtectedData": "4.7.0" + } + }, + "Azure.Messaging.ServiceBus": { + "type": "Transitive", + "resolved": "7.20.1", + "contentHash": "DxCkedWPQuiXrIyFcriOhsQcZmDZW+j9d55Ev4nnK3yjMUFjlVe4Hj37fuZTJlNhC3P+7EumqBTt33R6DfOxGA==", + "dependencies": { + "Azure.Core": "1.46.2", + "Azure.Core.Amqp": "1.3.1", + "Microsoft.Azure.Amqp": "2.7.0" + } + }, + "Azure.Storage.Blobs": { + "type": "Transitive", + "resolved": "12.26.0", + "contentHash": "EBRSHmI0eNzdufcIS1Rf7Ez9M8V1Jl7pMV4UWDERDMCv513KtAVsgz2ez2FQP9Qnwg7uEQrP+Uc7vBtumlr7sQ==", + "dependencies": { + "Azure.Core": "1.47.3", + "Azure.Storage.Common": "12.25.0" + } + }, + "Azure.Storage.Blobs.Batch": { + "type": "Transitive", + "resolved": "12.23.0", + "contentHash": "1Cj2/OEPoNpcwjQZ/vtng4ImrwuDlOZhYd3mKCxQXzUe50dl0lM5AWX8KE8GGKd5pLuRKYMNmn3mRvWpv/Me+A==", + "dependencies": { + "Azure.Core": "1.47.3", + "Azure.Storage.Blobs": "12.26.0", + "Azure.Storage.Common": "12.25.0" + } + }, + "Azure.Storage.Common": { + "type": "Transitive", + "resolved": "12.25.0", + "contentHash": "MHGWp4aLHRo0BdLj25U2qYdYK//Zz21k4bs3SVyNQEmJbBl3qZ8GuOmTSXJ+Zad93HnFXfvD8kyMr0gjA8Ftpw==", + "dependencies": { + "Azure.Core": "1.47.3", + "System.IO.Hashing": "8.0.0" + } + }, + "Azure.Storage.Queues": { + "type": "Transitive", + "resolved": "12.24.0", + "contentHash": "YSR051EMu421JZNCOyOB2JpVyA4bSW8CnbTYmYlwxsYIUJuwiMy2toSXIoq9RKG9PuBtnT5dS9M6QCYNGaswAw==", + "dependencies": { + "Azure.Core": "1.47.3", + "Azure.Storage.Common": "12.25.0" + } + }, + "BitPay.Light": { + "type": "Transitive", + "resolved": "1.0.1907", + "contentHash": "QTTIgXakHrRNQPxNyH7bZ7frm0bI8N6gRDtiqVyKG/QYQ+KfjN70xt0zQ0kO0zf8UBaKuwcV5B7vvpXtzR9ijg==", + "dependencies": { + "Newtonsoft.Json": "12.0.2" + } + }, + "Bitwarden.Server.Sdk.Environment": { + "type": "Transitive", + "resolved": "0.1.0", + "contentHash": "yLK3ik/+zQ4w41iDObvv4vq2QwWPaVMuyKFpzlgsukClOOuZUxJAivwnnZZDMXbp2wipWgaW4yeEY+yLdLVaVQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.9", + "Microsoft.Extensions.Hosting.Abstractions": "10.0.9", + "Microsoft.Extensions.Logging.Abstractions": "10.0.9", + "Microsoft.Extensions.Options": "10.0.9" + } + }, + "Bitwarden.Server.Sdk.Features": { + "type": "Transitive", + "resolved": "1.4.0", + "contentHash": "74Ir68CSZSUvZvVkb2CaUNHSAZcFMtZY5pReHz+K1eQX6+Am29iWS1i8DbQWq9F6KmCAEbqcGDyfAo4gRCurbg==", + "dependencies": { + "Bitwarden.Server.Sdk.Environment": "0.1.0", + "LaunchDarkly.ServerSdk": "8.14.1" + } + }, + "BouncyCastle.Cryptography": { + "type": "Transitive", + "resolved": "2.6.2", + "contentHash": "7oWOcvnntmMKNzDLsdxAYqApt+AjpRpP2CShjMfIa3umZ42UQMvH0tl1qAliYPNYO6vTdcGMqnRrCPmsfzTI1w==" + }, + "Braintree": { + "type": "Transitive", + "resolved": "5.36.0", + "contentHash": "K43RjhEU5qXoYYxo0C0o54msQxbdRjVP+hDMZwSXsei4fLBHA2xwS1NCooZ9girCQNjoWOM8bygkHTVGgN+sag==", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "System.Xml.XPath.XmlDocument": "4.3.0" + } + }, + "CsvHelper": { + "type": "Transitive", + "resolved": "33.1.0", + "contentHash": "kqfTOZGrn7NarNeXgjh86JcpTHUoeQDMB8t9NVa/ZtlSYiV1rxfRnQ49WaJsob4AiGrbK0XDzpyKkBwai4F8eg==" + }, + "dbup-core": { + "type": "Transitive", + "resolved": "6.1.1", + "contentHash": "kgpuyJVEFJHoIj/slnc994Go88aoeZqNDfGHDBr4sh7CsEWwJhOTCt/FJqO4ziUImL5L0NEY0kxxOiNgPKI2Fw==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "8.0.0" + } + }, + "dbup-sqlserver": { + "type": "Transitive", + "resolved": "7.2.0", + "contentHash": "1xhdu2ZoQEi2nNrirBfkkfn+AbHWQvy8CGilb+5dIjghFJrsMKFM17DiI5Nz+ofWg9N1lqz5WorujzuGvc/+fQ==", + "dependencies": { + "Microsoft.Data.SqlClient": "6.1.4", + "dbup-core": "6.1.1" + } + }, + "DnsClient": { + "type": "Transitive", + "resolved": "1.8.0", + "contentHash": "RRwtaCXkXWsx0mmsReGDqCbRLtItfUbkRJlet1FpdciVhyMGKcPd57T1+8Jki9ojHlq9fntVhXQroOOgRak8DQ==" + }, + "Duende.IdentityModel": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "8i+Tv4c38LgwoTRKbD0+MqtnNNDSVA83G6JkjGHgC4/7jH0nxZBP0RBhH8xTsvNQ5Pv9zrg+TR8rmtWK9HDOPg==" + }, + "Duende.IdentityServer": { + "type": "Transitive", + "resolved": "7.4.6", + "contentHash": "Zvri5e+SrOWLz0wmJry0ZaU8gVygv966jzP/CbMSCtV0K/nqK7abL9gQr9aKKmjt5DsONauUMT2E0cK/GbXJAg==", + "dependencies": { + "Duende.IdentityServer.Storage": "7.4.6", + "Microsoft.AspNetCore.Authentication.OpenIdConnect": "10.0.0" + } + }, + "Duende.IdentityServer.Storage": { + "type": "Transitive", + "resolved": "7.4.6", + "contentHash": "qPNsoj5H1TaT5gYptA/Z5LZE/UT4PFsgDen8K1DLj4W9O8i1PuEfFiba9CbmwLPs/TUS2xikCbxfiUgBUqn8GQ==", + "dependencies": { + "Duende.IdentityModel": "8.0.0", + "Microsoft.AspNetCore.DataProtection.Abstractions": "10.0.0" + } + }, + "DuoUniversal": { + "type": "Transitive", + "resolved": "1.3.1", + "contentHash": "BZUJplORCBO1PVDFT5v7HDYAlpgHAkay5N9vzRpJ/sBm+GU44pxNlo7v95Ym0tvUeKy0WWWv/iE4FjErYoZUHQ==", + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "6.34.0" + } + }, + "Fido2": { + "type": "Transitive", + "resolved": "3.0.1", + "contentHash": "S0Bz1vfcKlO4Jase3AWp5XnQ746psf4oGx5kL+D2A10j1SsjoAOAIIpanSwfi0cEepDHgk1bClcOKY5TjOzGdA==", + "dependencies": { + "Fido2.Models": "3.0.1", + "Microsoft.Extensions.Http": "6.0.0", + "NSec.Cryptography": "22.4.0", + "System.Formats.Cbor": "6.0.0", + "System.IdentityModel.Tokens.Jwt": "6.17.0" + } + }, + "Fido2.AspNet": { + "type": "Transitive", + "resolved": "3.0.1", + "contentHash": "5n5shEXD7RFUyTesjUHGDjkpgES7j4KotQo1GwUcS08k+fx+1tl/zCFHJ9RFDuUwO+S681ZILT2PyA67IPYpaA==", + "dependencies": { + "Fido2": "3.0.1", + "Fido2.Models": "3.0.1" + } + }, + "Fido2.Models": { + "type": "Transitive", + "resolved": "3.0.1", + "contentHash": "mgjcuGETuYSCUEaZG+jQeeuuEMkDLc4GDJHBvKDdOz6oSOWp5adPdWP4btZx7Pi+9fu4szN3JIjJmby67MaILw==" + }, + "Handlebars.Net": { + "type": "Transitive", + "resolved": "2.1.6", + "contentHash": "WsYWCEXsIM6hEOSOSRHtIYLjC8BnbT5MVmqhNKRqUI7qiv0t8x3nJiBTEv0ZZfvUAMAFnadGIzSsS/U2anVG1Q==" + }, + "LaunchDarkly.Cache": { + "type": "Transitive", + "resolved": "1.0.2", + "contentHash": "0bEnUVFVeW1TTDXb/bW6kS3FLQTLeGtw7Xh8yt6WNO56utVmtgcrMLvcnF6yeTn+N4FXrKfW09KkLNmK8YYQvw==" + }, + "LaunchDarkly.CommonSdk": { + "type": "Transitive", + "resolved": "7.2.0", + "contentHash": "YLT9rl0ooxHVNWtSsKBjtqdBt8Ysg99sXHAO1G8dcSH4B6yv3qR0lyCo6GEb9EQpUuGdneGqO7Bs7K2B8F+lTg==", + "dependencies": { + "LaunchDarkly.Logging": "2.0.0" + } + }, + "LaunchDarkly.EventSource": { + "type": "Transitive", + "resolved": "5.3.1", + "contentHash": "bVXethnjYnjC+hYSHYhn+1QFZhwtD0NYy1MJjtfOfC6CBW9h1pzR0hEAf16DQYl/LJtMi7fwOJbQhq8lFlFrSw==", + "dependencies": { + "LaunchDarkly.Logging": "[2.0.0, 3.0.0)" + } + }, + "LaunchDarkly.InternalSdk": { + "type": "Transitive", + "resolved": "3.6.1", + "contentHash": "qkbqHzz3AruAPW5PfbwQEM883p2ArHG3xun8IONmBT/QdiAhLFqh/5vxMCUsT1GfPyyly4S0HxYx3GP01Gc3Pg==", + "dependencies": { + "LaunchDarkly.CommonSdk": "[7.2.0, 8.0.0)", + "LaunchDarkly.Logging": "[2.0.0, 3.0.0)" + } + }, + "LaunchDarkly.Logging": { + "type": "Transitive", + "resolved": "2.0.0", + "contentHash": "lsLKNqAZ7HIlkdTIrf4FetfRA1SUDE3WlaZQn79aSVkLjYWEhUhkDDK7hORGh4JoA3V2gXN+cIvJQax2uR/ijA==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "6.0.0" + } + }, + "LaunchDarkly.ServerSdk": { + "type": "Transitive", + "resolved": "8.14.1", + "contentHash": "ufdAP+8OYpLEnDJanErS7wXj9xRYKCY1ZXmxaYuQwTB0qik3DviMRy5ml6Ehjd8kGgWZzOnur5EwqTKM+wW/AQ==", + "dependencies": { + "LaunchDarkly.Cache": "1.0.2", + "LaunchDarkly.CommonSdk": "7.2.0", + "LaunchDarkly.EventSource": "5.3.1", + "LaunchDarkly.InternalSdk": "3.6.1", + "LaunchDarkly.Logging": "2.0.0" + } + }, + "libsodium": { + "type": "Transitive", + "resolved": "1.0.18.2", + "contentHash": "flArHoVdscSzyV8ZdPV+bqqY2TTFlaN+xZf/vIqsmHI51KVcD/mOdUPaK3n/k/wGKz8dppiktXUqSmf3AXFgig==" + }, + "MailKit": { + "type": "Transitive", + "resolved": "4.17.0", + "contentHash": "1nUAVLxM9fhT/78we6/AGsCesnpn5dRNLLeRqOfr52Wnk87pzVwo5YMTMyqnmoXrYc7piGhmayiMA/OgDluIjg==", + "dependencies": { + "MimeKit": "4.17.0" + } + }, + "Microsoft.ApplicationInsights": { + "type": "Transitive", + "resolved": "2.23.0", + "contentHash": "nWArUZTdU7iqZLycLKWe0TDms48KKGE6pONH2terYNa8REXiqixrMOkf1sk5DHGMaUTqONU2YkS4SAXBhLStgw==" + }, + "Microsoft.AspNetCore.Authentication.JwtBearer": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "oGnE+X/SN6jdqao9WOkOIfyZ5+a0AtluJWy1Mxndq+kcWG6sx5k6l6tucu8/wJ7o9fHfLgVCzm/c4v/KVgVk6w==", + "dependencies": { + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "8.0.1" + } + }, + "Microsoft.AspNetCore.Authentication.OpenIdConnect": { + "type": "Transitive", + "resolved": "10.0.0", + "contentHash": "6ATONu+5A2oh/vzmoFhf3cuQcclMaWGHrb1kvjVsYtml+gzuWD48MmbsItM4xAUQkJZ2t8XFmbGp8pZLPxKneA==", + "dependencies": { + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "8.0.1" + } + }, + "Microsoft.AspNetCore.Cryptography.Internal": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "R0TKX26vPlw4kfyaLECwxn5GUIUAv6B+5s8kiEku9cl9VVCrDQDslPuhUUhN6oI/TvLj1lMFkz6AhHIpbPC3Lg==" + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "eKKLdOmdyr8TrzvD9eKdcvh8OlfomZiN6FwZNlK+F8fihZJBRgNVReqt3evYvZMHK3N/0Ui6P14cubllt1cFUg==", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "10.0.8" + } + }, + "Microsoft.AspNetCore.DataProtection": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "Rlbrr3XSGB4dwnUY/pA70TpVyrQhelDAUkIiGfJ2Tm32mscTYxrRnk9Ooy1rRhGZ1g7rliJPuNzhyMMKmRH5pw==", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "10.0.8", + "Microsoft.AspNetCore.DataProtection.Abstractions": "10.0.8", + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", + "Microsoft.Extensions.Hosting.Abstractions": "10.0.8", + "Microsoft.Extensions.Logging.Abstractions": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8", + "System.Security.Cryptography.Xml": "10.0.8" + } + }, + "Microsoft.AspNetCore.DataProtection.Abstractions": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "NYxEmhe2tDPwwGgl0kNraUOJdOqaIYJpnZ1Lf7OlqWRf3aLagniVxMl8JSVmy0jiRtElsPYq8lTvLlbvRSwCLA==" + }, + "Microsoft.Azure.Amqp": { + "type": "Transitive", + "resolved": "2.7.0", + "contentHash": "gm/AEakujttMzrDhZ5QpRz3fICVkYDn/oDG9SmxDP+J7R8JDBXYU9WWG7hr6wQy40mY+wjUF0yUGXDPRDRNJwQ==" + }, + "Microsoft.Azure.Cosmos": { + "type": "Transitive", + "resolved": "3.52.0", + "contentHash": "NEjNpaO19gvJrXowqHFcYPSpro5+TNjHO/JpU4VXP37by2aU2RVnmgpZsWL1GUl5wCPZ4VIOUsP1lrHpfW8ADQ==", + "dependencies": { + "Azure.Core": "1.44.1", + "Microsoft.Bcl.AsyncInterfaces": "6.0.0", + "Microsoft.Bcl.HashCode": "1.1.0", + "System.Configuration.ConfigurationManager": "6.0.0" + } + }, + "Microsoft.Azure.NotificationHubs": { + "type": "Transitive", + "resolved": "4.2.0", + "contentHash": "LOCxFB/sB1frfuXjecdDRDKEHkH+I1qKRatS5NyWIgYhpKhIcAlPNIJajcwLgQBShckdc3hMG9E+75CnL3qDhQ==", + "dependencies": { + "Microsoft.Extensions.Caching.Memory": "6.0.1", + "Newtonsoft.Json": "13.0.1" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==" + }, + "Microsoft.Bcl.Cryptography": { + "type": "Transitive", + "resolved": "9.0.13", + "contentHash": "5T+bH3Lb1nEe8Hf/ixMxLmhlrx5wRi53wv7OhVwG2F1ZviW1ejFRS1NHur3uqPpJRGtkQwUchtY6zhVK2R+v+w==" + }, + "Microsoft.Bcl.HashCode": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "J2G1k+u5unBV+aYcwxo94ip16Rkp65pgWFb0R6zwJipzWNMgvqlWeuI7/+R+e8bob66LnSG+llLJ+z8wI94cHg==" + }, + "Microsoft.Bot.Builder": { + "type": "Transitive", + "resolved": "4.23.0", + "contentHash": "bLTrp/tfSNWDAIJ90TqyZ8JtpjCvNO7kgvhW0R5eSu72tAifwEIi2uxhFS+c8alsa2DM4EW3JSemoDgn0r6Hog==", + "dependencies": { + "Microsoft.Bot.Connector": "4.23.0", + "Microsoft.Bot.Connector.Streaming": "4.23.0", + "Microsoft.Bot.Streaming": "4.23.0", + "Microsoft.Extensions.DependencyInjection": "8.0.0", + "Microsoft.Extensions.Logging": "8.0.0" + } + }, + "Microsoft.Bot.Builder.Integration.AspNet.Core": { + "type": "Transitive", + "resolved": "4.23.0", + "contentHash": "p6xghjJfg3Vh/q2NSd77TtuvCykuEakzMaELHctf3Cw4eTILsXWIgEJ0QxyelMnJGJjgfBwFS9ZeC2hWUFYzBA==", + "dependencies": { + "Microsoft.Bot.Builder": "4.23.0", + "Microsoft.Bot.Configuration": "4.23.0", + "Microsoft.Bot.Connector.Streaming": "4.23.0", + "Microsoft.Bot.Streaming": "4.23.0", + "Microsoft.Extensions.Configuration.Binder": "8.0.2", + "Newtonsoft.Json": "13.0.3" + } + }, + "Microsoft.Bot.Configuration": { + "type": "Transitive", + "resolved": "4.23.0", + "contentHash": "yCzxNU5QAEQ6zy7VBNuz3GwOY8OZcDkNYOmPw/QuVzViozxuJI200BMl+a5jhY9Nd7j6bGxO7Y3mmHy4Tu7Teg==", + "dependencies": { + "Newtonsoft.Json": "13.0.3" + } + }, + "Microsoft.Bot.Connector": { + "type": "Transitive", + "resolved": "4.23.0", + "contentHash": "/vgAQ8LonwAnyu6CzYYElU4k65k+9V2ncwztpZtBM+IuwkhDe3iAO2ycObqcyhMMWYUV81IOb0JZYcabjiZ4NQ==", + "dependencies": { + "Microsoft.Bot.Schema": "4.23.0", + "Microsoft.Extensions.Http": "8.0.0", + "Microsoft.Extensions.Logging": "8.0.0", + "Microsoft.Identity.Client": "4.66.1", + "Microsoft.Identity.Web.Certificateless": "3.3.0", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "8.1.2", + "Microsoft.Rest.ClientRuntime": "2.3.24", + "Newtonsoft.Json": "13.0.3" + } + }, + "Microsoft.Bot.Connector.Streaming": { + "type": "Transitive", + "resolved": "4.23.0", + "contentHash": "Yz6PcySgtje88IGEJXj6agzya48pBL34/A5Zs3/xqmHvEQlI2ypMNc3OBOo2TRGxykklCSwc60PN2k95d4pbFw==", + "dependencies": { + "Microsoft.Bot.Schema": "4.23.0", + "Microsoft.Bot.Streaming": "4.23.0", + "Microsoft.Extensions.Logging": "8.0.0", + "Newtonsoft.Json": "13.0.3" + } + }, + "Microsoft.Bot.Schema": { + "type": "Transitive", + "resolved": "4.23.0", + "contentHash": "HZeEXg/PuniNRIUU8ioSx/LrOXcbTZCZ1hUIqDdc6akWwhjrC2sTv7TaBpD0FlY4hDyUvj3GLyurPI/YChGPzA==", + "dependencies": { + "AdaptiveCards": "3.1.0", + "Newtonsoft.Json": "13.0.3" + } + }, + "Microsoft.Bot.Streaming": { + "type": "Transitive", + "resolved": "4.23.0", + "contentHash": "gYudjsFAVjwZBRU5irJh7sdsD7gNRFfZEUwWTqkNp1eGaR1t+4sJY+YyqYL3PyCMSgLrKE46bt/JWuDi3CjRfA==", + "dependencies": { + "Microsoft.Extensions.Logging": "8.0.0", + "Newtonsoft.Json": "13.0.3" + } + }, + "Microsoft.CodeCoverage": { + "type": "Transitive", + "resolved": "18.7.0", + "contentHash": "+wFfx9s7D9wegM0RziXMj2kvYDT4qcqXXtyjiQwSZOGQ2wwcOAJQcD6eQXk02jt0MvRNawtp8TJxTrV+wD8X1g==" + }, + "Microsoft.Data.SqlClient": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "/oolEwtHuDtpLKU8OItOTTxVJalgPtIkcNBwzXJ3YGyrkOAvLYqMtin9Z1jxqryJpds3PjuZBF5iKIYVVYVSvQ==", + "dependencies": { + "Microsoft.Bcl.Cryptography": "9.0.13", + "Microsoft.Data.SqlClient.Extensions.Abstractions": "1.0.0", + "Microsoft.Data.SqlClient.Internal.Logging": "1.0.0", + "Microsoft.Data.SqlClient.SNI.runtime": "6.0.2", + "Microsoft.Extensions.Caching.Memory": "9.0.13", + "Microsoft.IdentityModel.JsonWebTokens": "8.16.0", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "8.16.0", + "Microsoft.SqlServer.Server": "1.0.0", + "System.Configuration.ConfigurationManager": "9.0.13", + "System.Security.Cryptography.Pkcs": "9.0.13" + } + }, + "Microsoft.Data.SqlClient.Extensions.Abstractions": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "rlnxc0KfwDSbE8ZHntFnl8SCgOa9QtJZblMv2zXLhRwl1Je7fsdsVzxSjzzC4JMsfAK+jXJWyezRB8SxUY4BdA==", + "dependencies": { + "Microsoft.Data.SqlClient.Internal.Logging": "1.0.0" + } + }, + "Microsoft.Data.SqlClient.Internal.Logging": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "Kue/7CF8KNT9zozfr30C94dMZVZml3atqWZvQemSXvTau76tRdypzeKiBKXadqgbOME0UiQIyVTNo5WxCRNVNg==" + }, + "Microsoft.Data.SqlClient.SNI.runtime": { + "type": "Transitive", + "resolved": "6.0.2", + "contentHash": "f+pRODTWX7Y67jXO3T5S2dIPZ9qMJNySjlZT/TKmWVNWe19N8jcWmHaqHnnchaq3gxEKv1SWVY5EFzOD06l41w==" + }, + "Microsoft.Extensions.Caching.Abstractions": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "EoK2TwVR1daxmfXUPnvIYZSk5XQjHe45sGekox4kvMt88KQZQhDVzYW5Na5+oNwTuRpE48hipyGJg12F1Tm70w==", + "dependencies": { + "Microsoft.Extensions.Primitives": "10.0.8" + } + }, + "Microsoft.Extensions.Caching.Cosmos": { + "type": "Transitive", + "resolved": "1.8.0", + "contentHash": "8UI41/U5yla1z48klbtRdXxxloAChRzhAm592bitBNzTlXBq87zeO6Lbdvuh5d6oLNCU0I01kw6ovTD9Z6y05g==", + "dependencies": { + "Microsoft.Azure.Cosmos": "3.47.0", + "Microsoft.Extensions.Caching.Abstractions": "6.0.0", + "Microsoft.Extensions.Options": "6.0.0", + "Newtonsoft.Json": "13.0.3" + } + }, + "Microsoft.Extensions.Caching.Memory": { + "type": "Transitive", + "resolved": "9.0.13", + "contentHash": "OdQmN8LYcUEu20Fxii9mk68nHJGL+JPXF3w0+hxenf0oDDdDBA+ZV/S92FmIgAWAElowIiFA/g0x+8YB1g80Hg==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "9.0.13", + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.13", + "Microsoft.Extensions.Logging.Abstractions": "9.0.13", + "Microsoft.Extensions.Options": "9.0.13", + "Microsoft.Extensions.Primitives": "9.0.13" + } + }, + "Microsoft.Extensions.Caching.SqlServer": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "GSP1UIw/VFiLOWBOCQYwLHsLnkqqqqEC9sc8IqCXpbSkwz03EZ9u4jcFORTE4TJ/gkKXKP6L3AO+ZFZ5MFX4Gg==", + "dependencies": { + "Azure.Identity": "1.11.4", + "Microsoft.Data.SqlClient": "5.2.2", + "Microsoft.Extensions.Caching.Abstractions": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8" + } + }, + "Microsoft.Extensions.Caching.StackExchangeRedis": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "fle9ns3q2kk63vt/wHFtLw1U9kiEbM42vTk2Sar8VBjiGJFkXAgm0QEKFx15YMHkJIPRVdknWaovpvgGEgn10g==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "10.0.8", + "Microsoft.Extensions.Logging.Abstractions": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8", + "StackExchange.Redis": "2.7.27" + } + }, + "Microsoft.Extensions.Configuration": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "ehZcoPbjzWzS4XFvuz7R3V55SmpdkyMqFURLH3yXaN9NtXd9tR6CGB7pd49HYtCkenl+G7ctXSFLhNI08xLfRg==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.Primitives": "10.0.8" + } + }, + "Microsoft.Extensions.Configuration.Abstractions": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "qGhRPd3VxfLV9UqatVOiD9mAeUbj2KiMwGFYC5uXlzExiZQoe4X/hdmzGIU7BQjNLTqCnnbTHVyBglG3668/HA==", + "dependencies": { + "Microsoft.Extensions.Primitives": "10.0.9" + } + }, + "Microsoft.Extensions.Configuration.Binder": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "R3NN1X+kVu14uoxLEW6sBSQyhogDSbaOQzILnCtuXxBN4hx22AgjWPwZX6v/suERFkEDgU1lk12AglHTrUxhlw==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8" + } + }, + "Microsoft.Extensions.Configuration.EnvironmentVariables": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "bVGqctAfPGfTxJvNp8pMshtvpsUj6r6JkeiCNVIGVYO5gBxuxdN0Lbr25kEvE/zXdctkEc44g8HssnPgDnFGVA==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8" + } + }, + "Microsoft.Extensions.Configuration.FileExtensions": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "1g9mzuu8gIHkjYb0jLxOTQVl/QDG5nn0b0JzgT/gbgNKr6gXZzxOHRAsdYRc1eDApB7LdHR8uK5vQrNjIQdRrQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8", + "Microsoft.Extensions.FileProviders.Physical": "10.0.8", + "Microsoft.Extensions.Primitives": "10.0.8" + } + }, + "Microsoft.Extensions.Configuration.Json": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "KLtAZ6A38s1pIfCO2ns6aG14NNGMYNZ4PBYfFK4M+R4A+xuSc6oklhqDcpHZxvDpyBWeFtR5C8iQBw2ng8tUHQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.Configuration.FileExtensions": "10.0.8", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8" + } + }, + "Microsoft.Extensions.Configuration.UserSecrets": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "6XTfFOnf27WY8kEeZkTZ4YNn0t+imgvdQ0YaAdR4vgURKATo9bCaVJ1KB71IOJAQtJP7Elb53VHlTNXg2CtSsA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.Configuration.Json": "10.0.8", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8", + "Microsoft.Extensions.FileProviders.Physical": "10.0.8" + } + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "daf62xHIrq8pnE709hgaZZN9tSam9TGGepWe1+bE6V3GEuVwJiMs6ib+38lfMCyAJAHiX0vapxBhsuMSV7U+cg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "g41l/30G3K4B/d/L8kjux0+30e27c8D0FVQ/PFCpbekgfDpj9mnDhieP67EqXWvl1EWNeZh2rpR4F5B/jcDOHA==" + }, + "Microsoft.Extensions.Diagnostics": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "uduyw9d3Fi+sbredO5drA1S44AQS2FRNFyn72UmB2vmQIO1qaXprpp1U/2lYhYi8yFdVERfY9sy/pxw/qPOU9w==", + "dependencies": { + "Microsoft.Extensions.Configuration": "10.0.8", + "Microsoft.Extensions.Diagnostics.Abstractions": "10.0.8", + "Microsoft.Extensions.Options.ConfigurationExtensions": "10.0.8" + } + }, + "Microsoft.Extensions.Diagnostics.Abstractions": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "86RgyFsmVslW4Nu28IXgt8tLglynGQrwjk/xhGZaTe8j6YIeR1Ywoc42hSHsBSl920CQdfqq2dBohZiGm3AkUA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.9", + "Microsoft.Extensions.Options": "10.0.9" + } + }, + "Microsoft.Extensions.FileProviders.Abstractions": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "Oxn4vqDk+EwceTMpZxVm7L/UZEAM1qIQlNP1+7tBZckD+P4SKrm/5X4gMTPCTdpnau/xY8Sb4/0d6onomSg4ZA==", + "dependencies": { + "Microsoft.Extensions.Primitives": "10.0.9" + } + }, + "Microsoft.Extensions.FileProviders.Physical": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "GkPvQe6IdidLu6Q3Lw6+B8NJpW8feW8czZ5mBKt5rXM/x8MvZfEp5WvAsjznzDGd23chIDrW0b2mmt+ScnEgiw==", + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.8", + "Microsoft.Extensions.FileSystemGlobbing": "10.0.8", + "Microsoft.Extensions.Primitives": "10.0.8" + } + }, + "Microsoft.Extensions.FileSystemGlobbing": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "IUQet3SY51xIFcFZKtAB6a54/Zdxs7T3SQ84kJtOD6yeXfZgiOMksACWD5qtTmXGQGFH4QYGBOT0KIO8Uy/dJw==" + }, + "Microsoft.Extensions.Hosting.Abstractions": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "Xd/2F+uWblTiUp+ssaDZN2ea4vmnHmW6PXugmqBHumyhqVkyeh6RJ3S2Zo/F+1bXIL/KuGqe2pKv6UiGOc1KeQ==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.9", + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.9", + "Microsoft.Extensions.Diagnostics.Abstractions": "10.0.9", + "Microsoft.Extensions.FileProviders.Abstractions": "10.0.9", + "Microsoft.Extensions.Logging.Abstractions": "10.0.9" + } + }, + "Microsoft.Extensions.Http": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", + "Microsoft.Extensions.Diagnostics": "8.0.0", + "Microsoft.Extensions.Logging": "8.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.Extensions.Options": "8.0.0" + } + }, + "Microsoft.Extensions.Identity.Core": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "ZOuH3nlDslon9a0kJSRBTWnHNCKoiOoaurc3H1F4D6xLT+4UDvBNAqlLkEFyQdcxZFyUvYdwgc1+D/EjsD+RXA==", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "10.0.8", + "Microsoft.Extensions.Diagnostics": "10.0.8", + "Microsoft.Extensions.Logging": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8" + } + }, + "Microsoft.Extensions.Identity.Stores": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "xVbg4qLWyjKSJVxtL56PQPlHu/URpWPKufhfOj61+tkCmNs6DIgnGxG8BAO/fAfacoBDDYg+p1zBjFzzj/EQog==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "10.0.8", + "Microsoft.Extensions.Identity.Core": "10.0.8", + "Microsoft.Extensions.Logging": "10.0.8" + } + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "K60JhWC2hN/Gi7TP68tBxSzk5ACWOs7lkmPzsfA8Bcf/IXTajujt2ORMf9rSMk1bsng6Lv4Y3fuxp3bm1+15ug==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "10.0.8", + "Microsoft.Extensions.Logging.Abstractions": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "9S/DFt4cohlMPpzIxjG6kk0L8MuN2vDm9pbMCulxtJzzk82oJHVLBd8vuQxaPskaYQwKqmFmbannf5eoChgjYg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.9" + } + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "hyNdX4c2UwkRkzb9byw0H2DQkRzwBM3mzY2sCM9egwzTyg8dvQJmp5noQHGEaaCORQrNK3DD2gREBsc2DlXS4A==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.9", + "Microsoft.Extensions.Primitives": "10.0.9" + } + }, + "Microsoft.Extensions.Options.ConfigurationExtensions": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "VOapXeO3lhBH0zYoyAH7tjapuo4V5pTHlevPpiSHueEquAajqd5nF0mttm+h/uE/exwAEuM5s26SzOJtletE3w==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.8", + "Microsoft.Extensions.Configuration.Binder": "10.0.8", + "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.8", + "Microsoft.Extensions.Options": "10.0.8", + "Microsoft.Extensions.Primitives": "10.0.8" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "fmEbAUFsaIKirgLt/lYhuFRBwhcSJN31jjHgCdbQxJiWOum6EdLjkbgGuukSP9z/a+9LibaxII/kF+GwOXgC4g==" + }, + "Microsoft.Identity.Client": { + "type": "Transitive", + "resolved": "4.66.1", + "contentHash": "mE+m3pZ7zSKocSubKXxwZcUrCzLflC86IdLxrVjS8tialy0b1L+aECBqRBC/ykcPlB4y7skg49TaTiA+O2UfDw==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "6.35.0" + } + }, + "Microsoft.Identity.Client.Extensions.Msal": { + "type": "Transitive", + "resolved": "4.61.3", + "contentHash": "PWnJcznrSGr25MN8ajlc2XIDW4zCFu0U6FkpaNLEWLgd1NgFCp5uDY3mqLDgM8zCN8hqj8yo5wHYfLB2HjcdGw==", + "dependencies": { + "Microsoft.Identity.Client": "4.61.3", + "System.Security.Cryptography.ProtectedData": "4.5.0" + } + }, + "Microsoft.Identity.Web.Certificateless": { + "type": "Transitive", + "resolved": "3.3.0", + "contentHash": "ybEVPCLeJFuTCDVTtt3OlD5n+CYQgUAzmn0YZw+Z4NR5XwB4iGQ/zMqQ+ruJfgoKGWe6BTl0vCfsv1O4XPqCvg==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "2.1.0", + "Microsoft.Identity.Client": "4.66.1", + "Microsoft.IdentityModel.JsonWebTokens": "8.1.2" + } + }, + "Microsoft.IdentityModel.Abstractions": { + "type": "Transitive", + "resolved": "8.16.0", + "contentHash": "gSxKLWRZzBpIsEoeUPkxfywNCCvRvl7hkq146XHPk5vOQc9izSf1I+uL1vh4y2U19QPxd9Z8K/8AdWyxYz2lSg==" + }, + "Microsoft.IdentityModel.JsonWebTokens": { + "type": "Transitive", + "resolved": "8.16.0", + "contentHash": "prBU72cIP4V8E9fhN+o/YdskTsLeIcnKPbhZf0X6mD7fdxoZqnS/NdEkSr+9Zp+2q7OZBOMfNBKGbTbhXODO4w==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "8.16.0" + } + }, + "Microsoft.IdentityModel.Logging": { + "type": "Transitive", + "resolved": "8.16.0", + "contentHash": "MTzXmETkNQPACR7/XCXM1OGM6oU9RkyibqeJRtO9Ndew2LnGjMf9Atqj2VSf4XC27X0FQycUAlzxxEgQMWn2xQ==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "8.16.0" + } + }, + "Microsoft.IdentityModel.Protocols": { + "type": "Transitive", + "resolved": "8.16.0", + "contentHash": "UFrU7d46UTsPQTa2HIEIpB9H1uJe1BW9FLw5uhEJ2ZuKdur8bcUA/bO5caq5dlBt5gNJeRIB3QQXYNs5fCQCZA==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "8.16.0" + } + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect": { + "type": "Transitive", + "resolved": "8.16.0", + "contentHash": "h4yVXyJsEBBX5lg2G5ftMsi5JzcNEGAzrNphA6DQ6eOd8P0s+cDCOyPwVTYLePZvJL5unbPvYIvzrbTXzFjXnQ==", + "dependencies": { + "Microsoft.IdentityModel.Protocols": "8.16.0", + "System.IdentityModel.Tokens.Jwt": "8.16.0" + } + }, + "Microsoft.IdentityModel.Tokens": { + "type": "Transitive", + "resolved": "8.16.0", + "contentHash": "rtViGJcGsN7WcfUNErwNeQgjuU5cJNl6FDQsfi9TncwO+Epzn0FTfBsg3YuFW1Q0Ch/KPxaVdjLw3/+5Z5ceFQ==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "10.0.0", + "Microsoft.IdentityModel.Logging": "8.16.0" + } + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + }, + "Microsoft.Rest.ClientRuntime": { + "type": "Transitive", + "resolved": "2.3.24", + "contentHash": "hZH7XgM3eV2jFrnq7Yf0nBD4WVXQzDrer2gEY7HMNiwio2hwDsTHO6LWuueNQAfRpNp4W7mKxcXpwXUiuVIlYw==", + "dependencies": { + "Newtonsoft.Json": "10.0.3" + } + }, + "Microsoft.SqlServer.Server": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "N4KeF3cpcm1PUHym1RmakkzfkEv3GRMyofVv40uXsQhCQeglr2OHNcUk2WOG51AKpGO8ynGpo9M/kFXSzghwug==" + }, + "Microsoft.Testing.Extensions.Telemetry": { + "type": "Transitive", + "resolved": "1.9.1", + "contentHash": "No5AudZMmSb+uNXjlgL2y3/stHD2IT4uxqc5yHwkE+/nNux9jbKcaJMvcp9SwgP4DVD8L9/P3OUz8mmmcvEIdQ==", + "dependencies": { + "Microsoft.ApplicationInsights": "2.23.0", + "Microsoft.Testing.Platform": "1.9.1" + } + }, + "Microsoft.Testing.Extensions.TrxReport.Abstractions": { + "type": "Transitive", + "resolved": "1.9.1", + "contentHash": "AL46Xe1WBi85Ntd4mNPvat5ZSsZ2uejiVqoKCypr8J3wK0elA5xJ3AN4G/Q4GIwzUFnggZoH/DBjnr9J18IO/g==", + "dependencies": { + "Microsoft.Testing.Platform": "1.9.1" + } + }, + "Microsoft.Testing.Platform": { + "type": "Transitive", + "resolved": "1.9.1", + "contentHash": "QafNtNSmEI0zazdebnsIkDKmFtTSpmx/5PLOjURWwozcPb3tvRxzosQSL8xwYNM1iPhhKiBksXZyRSE2COisrA==" + }, + "Microsoft.Testing.Platform.MSBuild": { + "type": "Transitive", + "resolved": "1.9.1", + "contentHash": "oTUtyR4X/s9ytuiNA29FGsNCCH0rNmY5Wdm14NCKLjTM1cT9edVSlA+rGS/mVmusPqcP0l/x9qOnMXg16v87RQ==", + "dependencies": { + "Microsoft.Testing.Platform": "1.9.1" + } + }, + "Microsoft.TestPlatform.ObjectModel": { + "type": "Transitive", + "resolved": "18.7.0", + "contentHash": "6rmgU4q3/WOpOPcncI0YW0Q/QpcQtwR2TTEXDR5+4TfSimPBAk6Z/BgKLeGgp1SOun0ROVUCCafXhRLwsHaPpA==" + }, + "Microsoft.TestPlatform.TestHost": { + "type": "Transitive", + "resolved": "18.7.0", + "contentHash": "kYwfmebCs8992zaxEDkvG7S+YEouTeKfYVKUFEkwh1W2dIoOaevBt80XSKVXCUFEhusjOIm1sFfHBnoJgygrRA==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "18.7.0", + "Newtonsoft.Json": "13.0.3" + } + }, + "Microsoft.Win32.Registry": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==" + }, + "MimeKit": { + "type": "Transitive", + "resolved": "4.17.0", + "contentHash": "h/KXsCreJf8RpR/PSAtlbvYtZFndp9N8Wn1Bs248AL7ITyhn+AiIY5bLTvt60tbN2mu6g8KadtBNWygTji2lqg==", + "dependencies": { + "BouncyCastle.Cryptography": "2.6.2", + "System.Security.Cryptography.Pkcs": "10.0.0" + } + }, + "NETStandard.Library": { + "type": "Transitive", + "resolved": "1.6.1", + "contentHash": "WcSp3+vP+yHNgS8EV5J7pZ9IRpeDuARBPN28by8zqff1wJQXm26PVU8L3/fYLBJVU7BtDyqNVWq2KlCVvSSR4A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.3", + "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==" + }, + "NSec.Cryptography": { + "type": "Transitive", + "resolved": "22.4.0", + "contentHash": "lEntcPYd7h3aZ8xxi/y/4TML7o8w0GEGqd+w4L1omqFLbdCBmhxJAeO2YBmv/fXbJKgKCQLm7+TD4bR605PEUQ==", + "dependencies": { + "libsodium": "[1.0.18.2, 1.0.19)" + } + }, + "OneOf": { + "type": "Transitive", + "resolved": "3.0.271", + "contentHash": "pqpqeK8xQGggExhr4tesVgJkjdn+9HQAO0QgrYV2hFjE3y90okzk1kQMntMiUOGfV7FrCUfKPaVvPBD4IANqKg==" + }, + "Otp.NET": { + "type": "Transitive", + "resolved": "1.4.0", + "contentHash": "Fk1NKc0lWmlo6LAFYpFJInRgFKt72knRNEvxndDYoQHFwYOPXav+WEUBvQA0k4lxq5xt0SymrZ+oi0F/G40bPQ==" + }, + "Pipelines.Sockets.Unofficial": { + "type": "Transitive", + "resolved": "2.2.8", + "contentHash": "zG2FApP5zxSx6OcdJQLbZDk2AVlN2BNQD6MorwIfV6gVj0RRxWPEp2LXAxqDGZqeNV1Zp0BNPcNaey/GXmTdvQ==" + }, + "Quartz": { + "type": "Transitive", + "resolved": "3.15.1", + "contentHash": "XIbhzUAKSm3xdl1ORLPnK7mc5XANP3cuvYQhCtuX/8888IN41e9OXJak4R9OlmAGRnyAMqHE40yojVa89NS1wg==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "2.1.1" + } + }, + "Quartz.Extensions.DependencyInjection": { + "type": "Transitive", + "resolved": "3.15.1", + "contentHash": "LinB9z54aPn49C/DGM1v3OflX2nosrEo4zNz10vfYqcCndFJ8MNU9k++Ap9T7vxeZc355WStPDggpX60TYj1Lg==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "9.0.0", + "Microsoft.Extensions.Options": "9.0.0", + "Quartz": "3.15.1" + } + }, + "Quartz.Extensions.Hosting": { + "type": "Transitive", + "resolved": "3.15.1", + "contentHash": "svqLTEnVLb0VPUcNCd/khRqagwxM/yybUZ2sEOd7HFdPO+5dAOttL+ARtXSyBeaGWPWAaxY4VvU7pJTZzYhORw==", + "dependencies": { + "Microsoft.Extensions.Hosting.Abstractions": "9.0.0", + "Quartz.Extensions.DependencyInjection": "3.15.1" + } + }, + "RabbitMQ.Client": { + "type": "Transitive", + "resolved": "7.1.2", + "contentHash": "y3c6ulgULScWthHw5PLM1ShHRLhxg0vCtzX/hh61gRgNecL3ZC3WoBW2HYHoXOVRqTl99Br9E7CZEytGZEsCyQ==", + "dependencies": { + "System.Threading.RateLimiting": "8.0.0" + } + }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.29.3", + "contentHash": "nb/zHePecN9U4/Bmct+O+lpgK994JklbCCNMIgGPOone/DngjQoMCHeTvkl+m0Nglvm0dqMEshmvB4fO8eF3dA==", + "dependencies": { + "Newtonsoft.Json": "13.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, + "Serilog": { + "type": "Transitive", + "resolved": "2.10.0", + "contentHash": "+QX0hmf37a0/OZLxM3wL7V6/ADvC1XihXN4Kq/p6d8lCPfgkRdiuhbWlMaFjR9Av0dy5F0+MBeDmDdRZN/YwQA==" + }, + "Serilog.Extensions.Logging": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "IWfem7wfrFbB3iw1OikqPFNPEzfayvDuN4WP7Ue1AVFskalMByeWk3QbtUXQR34SBkv1EbZ3AySHda/ErDgpcg==", + "dependencies": { + "Microsoft.Extensions.Logging": "2.0.0", + "Serilog": "2.9.0" + } + }, + "Serilog.Extensions.Logging.File": { + "type": "Transitive", + "resolved": "3.0.0", + "contentHash": "bUYjMHn7NhpK+/8HDftG7+G5hpWzD49XTSvLoUFZGgappDa6FoseqFOsLrjLRjwe1zM+igH5mySFJv3ntb+qcg==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", + "Microsoft.Extensions.Configuration.Binder": "6.0.0", + "Serilog": "2.10.0", + "Serilog.Extensions.Logging": "3.1.0", + "Serilog.Formatting.Compact": "1.1.0", + "Serilog.Sinks.Async": "1.5.0", + "Serilog.Sinks.RollingFile": "3.3.0" + } + }, + "Serilog.Formatting.Compact": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "pNroKVjo+rDqlxNG5PXkRLpfSCuDOBY0ri6jp9PLe505ljqwhwZz8ospy2vWhQlFu5GkIesh3FcDs4n7sWZODA==", + "dependencies": { + "Serilog": "2.8.0" + } + }, + "Serilog.Sinks.Async": { + "type": "Transitive", + "resolved": "1.5.0", + "contentHash": "csHYIqAwI4Gy9oAhXYRwxGrQEAtBg3Ep7WaCzsnA1cZuBZjVAU0n7hWaJhItjO7hbLHh/9gRVxALCUB4Dv+gZw==", + "dependencies": { + "Serilog": "2.9.0" + } + }, + "Serilog.Sinks.File": { + "type": "Transitive", + "resolved": "3.2.0", + "contentHash": "VHbo68pMg5hwSWrzLEdZv5b/rYmIgHIRhd4d5rl8GnC5/a8Fr+RShT5kWyeJOXax1el6mNJ+dmHDOVgnNUQxaw==", + "dependencies": { + "Serilog": "2.3.0" + } + }, + "Serilog.Sinks.RollingFile": { + "type": "Transitive", + "resolved": "3.3.0", + "contentHash": "2lT5X1r3GH4P0bRWJfhA7etGl8Q2Ipw9AACvtAHWRUSpYZ42NGVyHoVs2ALBZ/cAkkS+tA4jl80Zie144eLQPg==", + "dependencies": { + "Serilog.Sinks.File": "3.2.0" + } + }, + "StackExchange.Redis": { + "type": "Transitive", + "resolved": "2.8.31", + "contentHash": "RCHVQa9Zke8k0oBgJn1Yl6BuYy8i6kv+sdMObiH60nOwD6QvWAjxdDwOm+LO78E8WsGiPqgOuItkz98fPS6haQ==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "6.0.0", + "Pipelines.Sockets.Unofficial": "2.2.8" + } + }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, + "Stripe.net": { + "type": "Transitive", + "resolved": "48.5.0", + "contentHash": "wOAZYR0EnrLMok/ScfVOpTxjci+n3vFP0A7w/BE63yJdkRSDwZVCJIhlOjeJvgyQnMX8ZbwDAHMaxaiDa0Z5TA==", + "dependencies": { + "Newtonsoft.Json": "13.0.3", + "System.Configuration.ConfigurationManager": "8.0.0" + } + }, + "System.ClientModel": { + "type": "Transitive", + "resolved": "1.6.1", + "contentHash": "xcHHhDqB5MnOOY8yIn64Vzp6gtBEs6k5J1hluG04CrShSvQNXOx4PSDs7wJiXLDidlY/FZJmxJdKTKskyJwjvw==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "8.0.3", + "System.Memory.Data": "8.0.1" + } + }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "9.0.13", + "contentHash": "GbBrJq9S/gYpHzm7Pxx6Y5tDyfSfyxW6tlP5oiKJV38uf19Wp+GIIAnWfyL1zmNiz1+EjwVapw2WkBFvvqKQzg==", + "dependencies": { + "System.Diagnostics.EventLog": "9.0.13", + "System.Security.Cryptography.ProtectedData": "9.0.13" + } + }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "9.0.13", + "contentHash": "675Rk4RwaVrWo09wrR2rpDVKixtgtnhd5NhPrn6O21uj92JvE61KTGupn76M2N6Ff/xJjY3SHSfSg0MIanEzGw==" + }, + "System.Formats.Cbor": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "mGaLOoiw7KurJagOOcIsWUoCT5ACIiGxKlCcbYQASefBGXjnCcKTq5Hdjb94eEAKg38zXKlHw4c6EjzgBl9dIw==" + }, + "System.IdentityModel.Tokens.Jwt": { + "type": "Transitive", + "resolved": "8.16.0", + "contentHash": "rrs2u7DRMXQG2yh0oVyF/vLwosfRv20Ld2iEpYcKwQWXHjfV+gFXNQsQ9p008kR9Ou4pxBs68Q6/9zC8Gi1wjg==", + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "8.16.0", + "Microsoft.IdentityModel.Tokens": "8.16.0" + } + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "ne1843evDugl0md7Fjzy6QjJrzsjh46ZKbhf8GwBXb5f/gw97J4bxMs0NQKifDuThh/f0bZ0e62NPl1jzTuRqA==" + }, + "System.Memory.Data": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "BVYuec3jV23EMRDeR7Dr1/qhx7369dZzJ9IWy2xylvb4YfXsrUxspWc4UWYid/tj4zZK58uGZqn2WQiaDMhmAg==" + }, + "System.Security.Cryptography.Pkcs": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "2wOycCqMyg9Tu+SDP03FFwDEWBni/3xOKgt0bRXplOvyeIcUJmWO7m3gTCF2mIdtQLROLtOP5VwWRT8YBwP/bA==" + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "9.0.13", + "contentHash": "t8S9IDpjJKsLpLkeBdW8cWtcPyYqrGu93Dej1RO6WwuL/lkFSqWlan3rMJfortqz1mRIh+sys2AFsSA6jWJ3Jg==" + }, + "System.Security.Cryptography.Xml": { + "type": "Transitive", + "resolved": "10.0.8", + "contentHash": "Fb+L55vEJaf8RCOzrzN564sfyCL8SZEfce9z6XkuhHg+294SBfyS4fIoLU3EljofDCkp+EKDeleI8ug5WO2NtA==", + "dependencies": { + "System.Security.Cryptography.Pkcs": "10.0.8" + } + }, + "System.Threading.RateLimiting": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "7mu9v0QDv66ar3DpGSZHg9NuNcxDaaAcnMULuZlaTpP9+hwXhrxNGsF5GmLkSHxFdb5bBc1TzeujsRgTrPWi+Q==" + }, + "System.Xml.XPath.XmlDocument": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "A/uxsWi/Ifzkmd4ArTLISMbfFs6XpRPsXZonrIqyTY70xi8t+mDtvSM5Os0RqyRDobjMBwIDHDL4NOIbkDwf7A==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.26.0", + "contentHash": "YrWZOfuU1Scg4iGizAlMNALOxVS+HPSVilfscNDEJAyrTIVdF4c+8o+Aerw2RYnrJxafj/F56YkJOKCURUWQmA==" + }, + "xunit.v3.assert": { + "type": "Transitive", + "resolved": "3.2.1", + "contentHash": "7hGxs+sfgPCiHg7CbWL8Vsmg8WS4vBfipZ7rfE+FEyS7ksU4+0vcV08TQvLIXLPAfinT06zVoK83YjRcMXcXLw==" + }, + "xunit.v3.common": { + "type": "Transitive", + "resolved": "3.2.1", + "contentHash": "NUh3pPTC3Py4XTnjoCCCIEzvdKTQ9apu0ikDNCrUETBtfHHXcoUmIl5bOfJLQQu7awhu8eaZHjJnG7rx9lUZpg==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "xunit.v3.core.mtp-v1": { + "type": "Transitive", + "resolved": "3.2.1", + "contentHash": "PeClKsdYS8TN7q8UxcIKgMVEf1xjqa5XWaizzt+WfLp8+85ZKT+LAQ2/ct+eYqazFzaGSJCAj96+1Z2USkWV6A==", + "dependencies": { + "Microsoft.Testing.Extensions.Telemetry": "1.9.1", + "Microsoft.Testing.Extensions.TrxReport.Abstractions": "1.9.1", + "Microsoft.Testing.Platform": "1.9.1", + "Microsoft.Testing.Platform.MSBuild": "1.9.1", + "xunit.v3.extensibility.core": "[3.2.1]", + "xunit.v3.runner.inproc.console": "[3.2.1]" + } + }, + "xunit.v3.extensibility.core": { + "type": "Transitive", + "resolved": "3.2.1", + "contentHash": "soZuThF5CwB/ZZ2HY/ivdinyM/6MvmjsHTG0vNw3fRd1ZKcmLzfxVb3fB6R3G5yoaN4Bh+aWzFGjOvYO05OzkA==", + "dependencies": { + "xunit.v3.common": "[3.2.1]" + } + }, + "xunit.v3.mtp-v1": { + "type": "Transitive", + "resolved": "3.2.1", + "contentHash": "lREcN7+kZmHqLmivhfzN+BHBYf3nQzMEojX5390qDplnXjaHYUxH49XmrWEbCx+va3ZTiIR2vVWPJWCs2UFBFQ==", + "dependencies": { + "xunit.analyzers": "1.26.0", + "xunit.v3.assert": "[3.2.1]", + "xunit.v3.core.mtp-v1": "[3.2.1]" + } + }, + "xunit.v3.runner.common": { + "type": "Transitive", + "resolved": "3.2.1", + "contentHash": "oF0jwl0xH45/RWjDcaCPOeeI6HCoyiEXIT8yvByd37rhJorjL/Ri8S9A/Vql8DBPjCfQWd6Url5JRmeiQ55isA==", + "dependencies": { + "Microsoft.Win32.Registry": "[5.0.0]", + "xunit.v3.common": "[3.2.1]" + } + }, + "xunit.v3.runner.inproc.console": { + "type": "Transitive", + "resolved": "3.2.1", + "contentHash": "EC/VLj1E9BPWfmzdEMQEqouxh0rWAdX6SXuiiDRf0yXXsQo3E2PNLKCyJ9V8hmkGH/nBvM7pHLFbuCf00vCynw==", + "dependencies": { + "xunit.v3.extensibility.core": "[3.2.1]", + "xunit.v3.runner.common": "[3.2.1]" + } + }, + "YubicoDotNetClient": { + "type": "Transitive", + "resolved": "1.2.0", + "contentHash": "uP5F3Ko1gqZi3lwS2R/jAAwhBxXs/6PKDpS6FdQjsBA5qmF0hQmbtfxM6QHTXOMoWbUtfetG7+LtgmG8T5zDIg==", + "dependencies": { + "NETStandard.Library": "1.6.1" + } + }, + "ZiggyCreatures.FusionCache": { + "type": "Transitive", + "resolved": "2.0.2", + "contentHash": "nO6ysiVP/1S1zVZMzsK0xASeSUay27iIlK8GjeyTpIAmq5P4/0KOzV9AqlabZYFgzeQDAu5IcB39ela2w/HCwQ==", + "dependencies": { + "Microsoft.Extensions.Caching.Memory": "8.0.1" + } + }, + "ZiggyCreatures.FusionCache.Backplane.StackExchangeRedis": { + "type": "Transitive", + "resolved": "2.0.2", + "contentHash": "E9KfGnhY+xcy8bmxoB/jJbfYwBlQwDD6c0v0P/Qr3IxGyJXyncza/45vFo5nI+5CggqczQ1GwQeEJqk0Lg8Q5g==", + "dependencies": { + "StackExchange.Redis": "2.8.31", + "ZiggyCreatures.FusionCache": "2.0.2" + } + }, + "ZiggyCreatures.FusionCache.Serialization.SystemTextJson": { + "type": "Transitive", + "resolved": "2.0.2", + "contentHash": "gt5ia5PHpCxhnI0hr51Y6L/acrrU17OuBqiU3vJPFXZxS3R1pIj2hr6WGB5fzW64VZDVdHTYsD5gTr2Pu8I+QQ==", + "dependencies": { + "ZiggyCreatures.FusionCache": "2.0.2" + } + }, + "core": { + "type": "Project", + "dependencies": { + "AWSSDK.SQS": "[4.0.2.5, 4.0.2.5]", + "AWSSDK.SimpleEmail": "[4.0.2.5, 4.0.2.5]", + "AspNetCoreRateLimit": "[5.0.0, 5.0.0]", + "AspNetCoreRateLimit.Redis": "[2.0.0, 2.0.0]", + "Azure.Data.Tables": "[12.11.0, 12.11.0]", + "Azure.Extensions.AspNetCore.DataProtection.Blobs": "[1.3.4, 1.3.4]", + "Azure.Messaging.ServiceBus": "[7.20.1, 7.20.1]", + "Azure.Storage.Blobs": "[12.26.0, 12.26.0]", + "Azure.Storage.Blobs.Batch": "[12.23.0, 12.23.0]", + "Azure.Storage.Queues": "[12.24.0, 12.24.0]", + "BitPay.Light": "[1.0.1907, 1.0.1907]", + "Bitwarden.Server.Sdk.Environment": "[0.1.0, )", + "Bitwarden.Server.Sdk.Features": "[1.4.0, )", + "Braintree": "[5.36.0, 5.36.0]", + "CsvHelper": "[33.1.0, 33.1.0]", + "Data": "[0.0.1, )", + "DnsClient": "[1.8.0, 1.8.0]", + "Duende.IdentityServer": "[7.4.6, 7.4.6]", + "DuoUniversal": "[1.3.1, 1.3.1]", + "ExceptionHandling": "[0.0.1, )", + "Fido2.AspNet": "[3.0.1, 3.0.1]", + "Handlebars.Net": "[2.1.6, 2.1.6]", + "MailKit": "[4.17.0, 4.17.0]", + "Microsoft.AspNetCore.Authentication.JwtBearer": "[10.0.8, 10.0.8]", + "Microsoft.AspNetCore.DataProtection": "[10.0.8, 10.0.8]", + "Microsoft.Azure.Cosmos": "[3.52.0, 3.52.0]", + "Microsoft.Azure.NotificationHubs": "[4.2.0, 4.2.0]", + "Microsoft.Bot.Builder": "[4.23.0, 4.23.0]", + "Microsoft.Bot.Builder.Integration.AspNet.Core": "[4.23.0, 4.23.0]", + "Microsoft.Bot.Connector": "[4.23.0, 4.23.0]", + "Microsoft.Data.SqlClient": "[7.0.0, 7.0.0]", + "Microsoft.Extensions.Caching.Cosmos": "[1.8.0, 1.8.0]", + "Microsoft.Extensions.Caching.SqlServer": "[10.0.8, 10.0.8]", + "Microsoft.Extensions.Caching.StackExchangeRedis": "[10.0.8, 10.0.8]", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "[10.0.8, 10.0.8]", + "Microsoft.Extensions.Configuration.UserSecrets": "[10.0.8, 10.0.8]", + "Microsoft.Extensions.Identity.Stores": "[10.0.8, 10.0.8]", + "Newtonsoft.Json": "[13.0.3, 13.0.3]", + "OneOf": "[3.0.271, 3.0.271]", + "Otp.NET": "[1.4.0, 1.4.0]", + "Quartz": "[3.15.1, 3.15.1]", + "Quartz.Extensions.DependencyInjection": "[3.15.1, 3.15.1]", + "Quartz.Extensions.Hosting": "[3.15.1, 3.15.1]", + "RabbitMQ.Client": "[7.1.2, 7.1.2]", + "SendGrid": "[9.29.3, 9.29.3]", + "Serilog.Extensions.Logging.File": "[3.0.0, 3.0.0]", + "SsrfProtection": "[0.0.1, )", + "Stripe.net": "[48.5.0, 48.5.0]", + "YubicoDotNetClient": "[1.2.0, 1.2.0]", + "ZiggyCreatures.FusionCache": "[2.0.2, 2.0.2]", + "ZiggyCreatures.FusionCache.Backplane.StackExchangeRedis": "[2.0.2, 2.0.2]", + "ZiggyCreatures.FusionCache.Serialization.SystemTextJson": "[2.0.2, 2.0.2]" + } + }, + "data": { + "type": "Project" + }, + "exceptionhandling": { + "type": "Project", + "dependencies": { + "HttpExtensions": "[2026.7.2, )" + } + }, + "httpextensions": { + "type": "Project" + }, + "migrator": { + "type": "Project", + "dependencies": { + "Core": "[2026.7.2, )", + "Microsoft.Extensions.Logging": "[10.0.8, 10.0.8]", + "dbup-sqlserver": "[7.2.0, 7.2.0]" + } + }, + "ssrfprotection": { + "type": "Project" + } + } + } +} \ No newline at end of file diff --git a/test/Migrator.Test/xunit.runner.json b/test/Migrator.Test/xunit.runner.json new file mode 100644 index 000000000000..86c7ea05b16c --- /dev/null +++ b/test/Migrator.Test/xunit.runner.json @@ -0,0 +1,3 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json" +} diff --git a/util/Migrator/DbMigrator.cs b/util/Migrator/DbMigrator.cs index 9345a72fc2cc..a81d9c0a830e 100644 --- a/util/Migrator/DbMigrator.cs +++ b/util/Migrator/DbMigrator.cs @@ -18,14 +18,17 @@ public class DbMigrator private readonly ILogger _logger; private readonly bool _skipDatabasePreparation; private readonly bool _noTransactionMigration; + private readonly int? _executionTimeoutSeconds; public DbMigrator(string connectionString, ILogger logger = null, - bool skipDatabasePreparation = false, bool noTransactionMigration = false) + bool skipDatabasePreparation = false, bool noTransactionMigration = false, + int? executionTimeoutSeconds = null) { _connectionString = connectionString; _logger = logger ?? CreateLogger(); _skipDatabasePreparation = skipDatabasePreparation; _noTransactionMigration = noTransactionMigration; + _executionTimeoutSeconds = executionTimeoutSeconds; } public bool MigrateMsSqlDatabaseWithRetries(bool enableLogging = true, @@ -128,12 +131,14 @@ private bool MigrateDatabase(bool enableLogging = true, .SqlDatabase(_connectionString) .WithScriptsAndCodeEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s.Contains($".{folderName}.") && !s.Contains(".Archive.")) - .WithExecutionTimeout(TimeSpan.FromMinutes(5)); + .WithExecutionTimeout(ResolveExecutionTimeout(_executionTimeoutSeconds, + MigratorConstants.DefaultExecutionTimeoutMinutes)); if (_noTransactionMigration) { builder = builder.WithoutTransaction() - .WithExecutionTimeout(TimeSpan.FromMinutes(60)); + .WithExecutionTimeout(ResolveExecutionTimeout(_executionTimeoutSeconds, + MigratorConstants.NoTransactionExecutionTimeoutMinutes)); } else { @@ -188,6 +193,18 @@ private bool MigrateDatabase(bool enableLogging = true, return result.Successful; } + // zero is passed through as a command timeout of zero, which means no limit + internal static TimeSpan ResolveExecutionTimeout(int? executionTimeoutSeconds, int defaultMinutes) + { + // a negative command timeout throws when assigned, so fall back to the default + if (executionTimeoutSeconds is null or < 0) + { + return TimeSpan.FromMinutes(defaultMinutes); + } + + return TimeSpan.FromSeconds(executionTimeoutSeconds.Value); + } + private ILogger CreateLogger() { var loggerFactory = LoggerFactory.Create(builder => diff --git a/util/Migrator/Migrator.csproj b/util/Migrator/Migrator.csproj index 771c799f7156..6df9bc89a5d8 100644 --- a/util/Migrator/Migrator.csproj +++ b/util/Migrator/Migrator.csproj @@ -5,6 +5,10 @@ $(WarningsNotAsErrors);CA1305 + + + + diff --git a/util/Migrator/MigratorConstants.cs b/util/Migrator/MigratorConstants.cs index bf1bccb6c26d..0ca659267808 100644 --- a/util/Migrator/MigratorConstants.cs +++ b/util/Migrator/MigratorConstants.cs @@ -5,4 +5,6 @@ public static class MigratorConstants public const string SqlTableJournalName = "Migration"; public const string DefaultMigrationsFolderName = "DbScripts"; public const string TransitionMigrationsFolderName = "DbScripts_transition"; + public const int DefaultExecutionTimeoutMinutes = 5; + public const int NoTransactionExecutionTimeoutMinutes = 60; } diff --git a/util/Migrator/SqlServerDbMigrator.cs b/util/Migrator/SqlServerDbMigrator.cs index d76b26cfb75b..d0b3947feccc 100644 --- a/util/Migrator/SqlServerDbMigrator.cs +++ b/util/Migrator/SqlServerDbMigrator.cs @@ -11,7 +11,8 @@ public class SqlServerDbMigrator : IDbMigrator public SqlServerDbMigrator(GlobalSettings globalSettings, ILogger logger) { _migrator = new DbMigrator(globalSettings.SqlServer.ConnectionString, logger, - globalSettings.SqlServer.SkipDatabasePreparation); + globalSettings.SqlServer.SkipDatabasePreparation, + executionTimeoutSeconds: globalSettings.SqlServer.MigrationExecutionTimeoutSeconds); } public bool MigrateDatabase(bool enableLogging = true, diff --git a/util/MsSqlMigratorUtility/Program.cs b/util/MsSqlMigratorUtility/Program.cs index c9f984b6de16..d5925d085e27 100644 --- a/util/MsSqlMigratorUtility/Program.cs +++ b/util/MsSqlMigratorUtility/Program.cs @@ -19,17 +19,22 @@ public int Execute( [Option('d', "dry-run", Description = "Print the scripts that will be applied without actually executing them")] bool dryRun = false, [Option("no-transaction", Description = "Run without adding transaction per script or all scripts")] - bool noTransactionMigration = false + bool noTransactionMigration = false, + [Option('t', "timeout", Description = "Execution timeout in seconds for each script, or 0 for no limit")] + int? executionTimeoutSeconds = null ) { - return MigrateDatabase(databaseConnectionString, repeatable, folderName, dryRun, noTransactionMigration) ? 0 : -1; + return MigrateDatabase(databaseConnectionString, repeatable, folderName, dryRun, noTransactionMigration, + executionTimeoutSeconds) ? 0 : -1; } private static bool MigrateDatabase(string databaseConnectionString, - bool repeatable = false, string folderName = "", bool dryRun = false, bool noTransactionMigration = false) + bool repeatable = false, string folderName = "", bool dryRun = false, bool noTransactionMigration = false, + int? executionTimeoutSeconds = null) { - var migrator = new DbMigrator(databaseConnectionString, noTransactionMigration: noTransactionMigration); + var migrator = new DbMigrator(databaseConnectionString, noTransactionMigration: noTransactionMigration, + executionTimeoutSeconds: executionTimeoutSeconds); bool success; if (!string.IsNullOrWhiteSpace(folderName)) { diff --git a/util/Setup/EnvironmentFileBuilder.cs b/util/Setup/EnvironmentFileBuilder.cs index 79d98a90c251..4f25eacee22f 100644 --- a/util/Setup/EnvironmentFileBuilder.cs +++ b/util/Setup/EnvironmentFileBuilder.cs @@ -84,6 +84,7 @@ private void Init() ["globalSettings__baseServiceUri__vault"] = _context.Config.Url, ["globalSettings__baseServiceUri__cloudRegion"] = _context.Install?.CloudRegion.ToString(), ["globalSettings__sqlServer__connectionString"] = $"\"{dbConnectionString.Replace("\"", "\\\"")}\"", + ["globalSettings__sqlServer__migrationExecutionTimeoutSeconds"] = string.Empty, ["globalSettings__identityServer__certificatePassword"] = _context.Install?.IdentityCertPassword, ["globalSettings__internalIdentityKey"] = _context.Stub ? "RANDOM_IDENTITY_KEY" : Helpers.SecureRandomString(64, alpha: true, numeric: true), diff --git a/util/Setup/Program.cs b/util/Setup/Program.cs index ba30ae2f7f91..3ea92fe56c2f 100644 --- a/util/Setup/Program.cs +++ b/util/Setup/Program.cs @@ -279,7 +279,12 @@ private static void PrepareAndMigrateDatabase() { var vaultConnectionString = Helpers.GetValueFromEnvFile(_context.App, "global", "globalSettings__sqlServer__connectionString"); - var migrator = new DbMigrator(vaultConnectionString); + + var timeoutValue = Helpers.GetValueFromEnvFile(_context.App, "global", + "globalSettings__sqlServer__migrationExecutionTimeoutSeconds"); + int? executionTimeoutSeconds = int.TryParse(timeoutValue, out var parsedTimeout) ? parsedTimeout : null; + + var migrator = new DbMigrator(vaultConnectionString, executionTimeoutSeconds: executionTimeoutSeconds); var enableLogging = false; From e84b8a4e93772dae723ba638a40f5cf85a88ca54 Mon Sep 17 00:00:00 2001 From: Micaiah Martin Date: Tue, 4 Aug 2026 14:46:20 -0600 Subject: [PATCH 2/2] Surface ignored and applied migration timeout values --- util/Migrator/DbMigrator.cs | 6 ++++++ util/Setup/Program.cs | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/util/Migrator/DbMigrator.cs b/util/Migrator/DbMigrator.cs index a81d9c0a830e..292158a4948b 100644 --- a/util/Migrator/DbMigrator.cs +++ b/util/Migrator/DbMigrator.cs @@ -29,6 +29,12 @@ public DbMigrator(string connectionString, ILogger logger = null, _skipDatabasePreparation = skipDatabasePreparation; _noTransactionMigration = noTransactionMigration; _executionTimeoutSeconds = executionTimeoutSeconds; + + if (executionTimeoutSeconds < 0) + { + _logger.LogWarning("Ignoring migration execution timeout of {Seconds} seconds because it is negative. " + + "Using the default.", executionTimeoutSeconds); + } } public bool MigrateMsSqlDatabaseWithRetries(bool enableLogging = true, diff --git a/util/Setup/Program.cs b/util/Setup/Program.cs index 3ea92fe56c2f..e7a112b79913 100644 --- a/util/Setup/Program.cs +++ b/util/Setup/Program.cs @@ -280,9 +280,24 @@ private static void PrepareAndMigrateDatabase() var vaultConnectionString = Helpers.GetValueFromEnvFile(_context.App, "global", "globalSettings__sqlServer__connectionString"); + // setup runs outside the app host, so read the setting from the env file var timeoutValue = Helpers.GetValueFromEnvFile(_context.App, "global", "globalSettings__sqlServer__migrationExecutionTimeoutSeconds"); - int? executionTimeoutSeconds = int.TryParse(timeoutValue, out var parsedTimeout) ? parsedTimeout : null; + + int? executionTimeoutSeconds = null; + if (!string.IsNullOrWhiteSpace(timeoutValue)) + { + if (int.TryParse(timeoutValue, out var parsedTimeout)) + { + executionTimeoutSeconds = parsedTimeout; + Helpers.WriteLine(_context, "Using a migration execution timeout of {0} seconds.", parsedTimeout); + } + else + { + Helpers.WriteLine(_context, "Ignoring migration execution timeout '{0}', which is not a whole " + + "number of seconds. Using the default.", timeoutValue); + } + } var migrator = new DbMigrator(vaultConnectionString, executionTimeoutSeconds: executionTimeoutSeconds);