From f570887999a2a3fa3544b3d8cdd7bd4db26815ce Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Wed, 10 Dec 2025 17:01:07 -0600 Subject: [PATCH 01/11] feat: Add Aspire Apphost and ServiceDefault projects --- .aspire/settings.json | 3 + AppHost/AppHost.cs | 59 ++++++++ AppHost/AppHost.csproj | 29 ++++ AppHost/BuilderExtensions.cs | 156 ++++++++++++++++++++ AppHost/Properties/launchSettings.json | 29 ++++ AppHost/appsettings.Development.json | 8 + AppHost/appsettings.json | 9 ++ ServiceDefaults/Extensions.cs | 197 +++++++++++++++++++++++++ ServiceDefaults/ServiceDefaults.csproj | 22 +++ bitwarden-server.sln | 13 ++ dev/setup_secrets.ps1 | 1 + 11 files changed, 526 insertions(+) create mode 100644 .aspire/settings.json create mode 100644 AppHost/AppHost.cs create mode 100644 AppHost/AppHost.csproj create mode 100644 AppHost/BuilderExtensions.cs create mode 100644 AppHost/Properties/launchSettings.json create mode 100644 AppHost/appsettings.Development.json create mode 100644 AppHost/appsettings.json create mode 100644 ServiceDefaults/Extensions.cs create mode 100644 ServiceDefaults/ServiceDefaults.csproj diff --git a/.aspire/settings.json b/.aspire/settings.json new file mode 100644 index 000000000000..bbd7ab5c9b3e --- /dev/null +++ b/.aspire/settings.json @@ -0,0 +1,3 @@ +{ + "appHostPath": "../AppHost/AppHost.csproj" +} \ No newline at end of file diff --git a/AppHost/AppHost.cs b/AppHost/AppHost.cs new file mode 100644 index 000000000000..a0cc3990f2e1 --- /dev/null +++ b/AppHost/AppHost.cs @@ -0,0 +1,59 @@ +using Bit.AppHost; + +var builder = DistributedApplication.CreateBuilder(args); +var secretsSetup = builder.ConfigureSecrets(); +var isSelfHosted = builder.Configuration["globalSettings:selfHosted"]?.ToLowerInvariant() == "true"; + +// Add Pricing Service - use port from pricingUri in secrets +var pricingService = + builder + .AddProject("pricing-service", + builder.Configuration["pricingServiceRelativePath"] + ?? throw new ArgumentNullException("pricingServiceRelativePath", "Missing pricing service relative path")); + +// Add Database and run migrations +var db = builder.AddSqlServerDatabaseResource(isSelfHosted); +builder.ConfigureMigrations(isSelfHosted) + .WaitFor(db) + .ExcludeFromManifest() + .WaitForCompletion(secretsSetup); + +var azurite = builder.ConfigureAzurite(); + +// Add MailCatcher +var mail = builder + .AddContainer("mailcatcher", "sj26/mailcatcher:latest") + .WithLifetime(ContainerLifetime.Persistent) + .WithEndpoint(port: 10250, name: "smtp", targetPort: 1025) // SMTP port + .WithHttpEndpoint(port: 1080, name: "web", targetPort: 1080); + + +// Add Services +builder.AddBitwardenService(db, secretsSetup, mail, "admin"); +var api = builder.AddBitwardenService(db, secretsSetup, mail, "api") + .WithReference(pricingService) + .WaitFor(azurite); +var billing = builder.AddBitwardenService(db, secretsSetup, mail, "billing"); +builder.AddBitwardenService(db, secretsSetup, mail, "identity"); +builder.AddBitwardenService(db, secretsSetup, mail, "notifications") + .WaitFor(azurite); + +// Add Client Apps +builder.AddBitwardenNpmApp("web-frontend", "web", api) + .WithHttpsEndpoint(8080, 8080, "angular-http", isProxied: false) + .WithUrl("https://bitwarden.test:8080") + .WithExternalHttpEndpoints(); +builder.AddBitwardenNpmApp("desktop-frontend", "desktop", api, "start"); +builder.AddBitwardenNpmApp("browser-frontend", "browser", api, "build:bit:watch:chrome"); + +// Add Ngrok +builder.ConfigureNgrok((billing, "billing-http")); + +builder.Build().Run(); + + + + + + + diff --git a/AppHost/AppHost.csproj b/AppHost/AppHost.csproj new file mode 100644 index 000000000000..ea03a3bed14d --- /dev/null +++ b/AppHost/AppHost.csproj @@ -0,0 +1,29 @@ + + + + + + Exe + net8.0 + enable + enable + e0dba0c6-d131-43bd-9143-2260f11a14ad + + + + + + + + + + + + + + + + + + + diff --git a/AppHost/BuilderExtensions.cs b/AppHost/BuilderExtensions.cs new file mode 100644 index 000000000000..76239e7dc1aa --- /dev/null +++ b/AppHost/BuilderExtensions.cs @@ -0,0 +1,156 @@ +using Aspire.Hosting.Azure; +using Azure.Provisioning; +using Azure.Provisioning.Storage; + +namespace Bit.AppHost; + +public static class BuilderExtensions +{ + public static IResourceBuilder ConfigureSecrets(this IDistributedApplicationBuilder builder) + { + // Setup secrets before starting services + var secretsScript = builder.Configuration["scripts:secretsSetup"] ?? throw new ArgumentNullException("setupSecretsScriptPath", "Missing setup secrets script path"); + var pricingSecretsPath = builder.Configuration["pricingServiceSecretsPath"] ?? throw new ArgumentNullException("pricingServiceSecretsPath", "Missing secrets path"); + + //Pricing Secrets + builder + .AddExecutable("pricing-setup-secrets", "pwsh", pricingSecretsPath, "-File", secretsScript, "-clear") + .ExcludeFromManifest(); + return builder + .AddExecutable("setup-secrets", "pwsh", "../dev", "-File", secretsScript, "-clear") + .ExcludeFromManifest(); + } + + public static IResourceBuilder AddSqlServerDatabaseResource(this IDistributedApplicationBuilder builder, bool isSelfHosted = false) + { + var password = isSelfHosted + ? builder.Configuration["dev:selfHostOverride:globalSettings:sqlServer:password"] + : builder.Configuration["globalSettings:sqlServer:password"]; + + // Add MSSQL - retrieve password from connection string in secrets + var dbpassword = builder.AddParameter("dbPassword", password!, secret: true); + return builder + .AddSqlServer("mssql", password: dbpassword, 1433) + .WithImage("mssql/server:2022-latest") + .WithLifetime(ContainerLifetime.Persistent) + .WithDataVolume() + .AddDatabase("vault", isSelfHosted ? "self_host_dev" : "vault_dev"); + } + + public static IResourceBuilder ConfigureAzurite(this IDistributedApplicationBuilder builder) + { + + // https://github.com/dotnet/aspire/discussions/5552 + var azurite = builder + .AddAzureStorage("azurite").ConfigureInfrastructure(c => + { + var blobStorage = c.GetProvisionableResources().OfType().Single(); + blobStorage.CorsRules.Add(new BicepValue(new StorageCorsRule + { + AllowedOrigins = [new BicepValue("*")], + AllowedMethods = [CorsRuleAllowedMethod.Get, CorsRuleAllowedMethod.Put], + AllowedHeaders = [new BicepValue("*")], + ExposedHeaders = [new BicepValue("*")], + MaxAgeInSeconds = new BicepValue("30") + })); + }) + .RunAsEmulator(c => + { + c.WithBlobPort(10000). + WithQueuePort(10001). + WithTablePort(10002); + }); + + var workingDirectory = builder.Configuration["workingDirectory"] ?? throw new ArgumentNullException("workingDirectory", "Missing working directory"); + + //Run Azurite setup + var azuriteSetupScript = + builder + .Configuration["scripts:azuriteSetup"] + ?? throw new ArgumentNullException("azuriteSetupScriptPath", "Missing azurite setup script path"); + + builder + .AddExecutable("azurite-setup", "pwsh", workingDirectory, "-File", azuriteSetupScript) + .WaitFor(azurite) + .ExcludeFromManifest(); + return azurite; + } + + public static IResourceBuilder ConfigureNgrok(this IDistributedApplicationBuilder builder, (IResourceBuilder, string) tunnelResource) + { + var authToken = builder + .AddParameter("ngrok-auth-token", + builder.Configuration["ngrokAuthToken"] + ?? throw new ArgumentNullException("ngrokAuthToken", "Missing ngrok auth token"), + secret: true); + + return builder.AddNgrok("billing-webhook-ngrok-endpoint", endpointPort: 59600) + .WithAuthToken(authToken) + .WithTunnelEndpoint(tunnelResource.Item1, tunnelResource.Item2) + .WithExplicitStart(); + } + + public static IResourceBuilder ConfigureMigrations(this IDistributedApplicationBuilder builder, bool isSelfHosted) + { + var workingDirectory = builder.Configuration["workingDirectory"] ?? + throw new ArgumentNullException("workingDirectory", "Missing working directory"); + var migrationArgs = new List + { + "-File", + builder.Configuration["scripts:dbMigration"] + ?? throw new ArgumentNullException("migrationScriptPath", "Missing migration script path") + }; + if (isSelfHosted) + { + migrationArgs.Add("-self-hosted"); + } + + return builder + .AddExecutable("run-db-migrations", "pwsh", workingDirectory, migrationArgs.ToArray()); + } + + public static IResourceBuilder AddBitwardenService( + this IDistributedApplicationBuilder builder, IResourceBuilder db, + IResourceBuilder secretsSetup, IResourceBuilder mail, string name) + where TProject : IProjectMetadata, new() + { + var service = builder.AddProject(name) + .WithHttpEndpoint(port: builder.GetBitwardenServicePort(name), name: $"{name}-http") + .WithReference(db) + .WaitFor(db) + .WaitForCompletion(secretsSetup); + + if (name is "admin" or "identity" or "billing") + { + service.WithReference(mail.GetEndpoint("smtp")); + } + + return service; + } + + public static IResourceBuilder AddBitwardenNpmApp(this IDistributedApplicationBuilder builder, + string name, string path, IResourceBuilder api, string scriptName = "build:bit:watch") + { + var clientsRelativePath = builder.Configuration["clientsRelativePath"] ?? + throw new ArgumentNullException("clientsRelativePath", "Missing client relative path"); + + return builder + .AddNpmApp(name, $"{clientsRelativePath}/{path}", scriptName) + .WithReference(api) + .WaitFor(api) + .WithExplicitStart(); + } + + public static int GetBitwardenServicePort(this IDistributedApplicationBuilder builder, string serviceName) + { + var isSelfHosted = builder.Configuration["isSelfHosted"] == "true"; + var configKey = isSelfHosted + ? $"dev:selfHostOverride:globalSettings:baseServiceUri:{serviceName}" + : $"globalSettings:baseServiceUri:{serviceName}"; + + var uriString = builder.Configuration[configKey] + ?? throw new InvalidOperationException($"Configuration value for '{configKey}' not found."); + + return new Uri(uriString).Port; + } +} diff --git a/AppHost/Properties/launchSettings.json b/AppHost/Properties/launchSettings.json new file mode 100644 index 000000000000..14f58c388d18 --- /dev/null +++ b/AppHost/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:17271;http://localhost:15055", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21022", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22177" + } + }, + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:15055", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19147", + "ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20252" + } + } + } +} diff --git a/AppHost/appsettings.Development.json b/AppHost/appsettings.Development.json new file mode 100644 index 000000000000..0c208ae9181e --- /dev/null +++ b/AppHost/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/AppHost/appsettings.json b/AppHost/appsettings.json new file mode 100644 index 000000000000..31c092aa4501 --- /dev/null +++ b/AppHost/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Aspire.Hosting.Dcp": "Warning" + } + } +} diff --git a/ServiceDefaults/Extensions.cs b/ServiceDefaults/Extensions.cs new file mode 100644 index 000000000000..8e97f0c17840 --- /dev/null +++ b/ServiceDefaults/Extensions.cs @@ -0,0 +1,197 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace Bit.ServiceDefaults; + +// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry. +// This project should be referenced by each service project in your solution. +// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults +public static class Extensions +{ + private const string HealthEndpointPath = "/health"; + private const string AlivenessEndpointPath = "/alive"; + + public static TBuilder AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.ConfigureOpenTelemetry(); + + builder.AddDefaultHealthChecks(); + + builder.Services.AddServiceDiscovery(); + + builder.Services.ConfigureHttpClientDefaults(http => + { + // Turn on resilience by default + http.AddStandardResilienceHandler(); + + // Turn on service discovery by default + http.AddServiceDiscovery(); + }); + + // Uncomment the following to restrict the allowed schemes for service discovery. + // builder.Services.Configure(options => + // { + // options.AllowedSchemes = ["https"]; + // }); + + return builder; + } + + public static TBuilder ConfigureOpenTelemetry(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.Logging.AddOpenTelemetry(logging => + { + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + + builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddSource(builder.Environment.ApplicationName) + .AddAspNetCoreInstrumentation(tracing => + // Exclude health check requests from tracing + tracing.Filter = context => + !context.Request.Path.StartsWithSegments(HealthEndpointPath) + && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath) + ) + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + + builder.AddOpenTelemetryExporters(); + + return builder; + } + + private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + + if (useOtlpExporter) + { + builder.Services.AddOpenTelemetry().UseOtlpExporter(); + } + + // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) + //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + //{ + // builder.Services.AddOpenTelemetry() + // .UseAzureMonitor(); + //} + + return builder; + } + + public static TBuilder AddDefaultHealthChecks(this TBuilder builder) where TBuilder : IHostApplicationBuilder + { + builder.Services.AddHealthChecks() + // Add a default liveness check to ensure app is responsive + .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + return builder; + } + + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) + { + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks(HealthEndpointPath); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } + + return app; + } + + // Overload for IHostBuilder + public static IHostBuilder AddServiceDefaults(this IHostBuilder hostBuilder) + { + hostBuilder.ConfigureServices((context, services) => + { + if (context.HostingEnvironment.IsDevelopment()) + { + services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy(), new[] { "live" }); + } + + services.AddServiceDiscovery(); + services.ConfigureHttpClientDefaults(http => + { + http.AddStandardResilienceHandler(); + http.AddServiceDiscovery(); + }); + services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddSource(context.HostingEnvironment.ApplicationName) + .AddAspNetCoreInstrumentation(tracing => + tracing.Filter = context => + !context.Request.Path.StartsWithSegments(HealthEndpointPath) + && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath) + ) + .AddHttpClientInstrumentation(httpClient => + { + httpClient.EnrichWithHttpRequestMessage = (activity, message) => + { + if (context.HostingEnvironment.IsDevelopment()) + { + activity.SetTag("http.request_content_length", message.Content?.Headers.ContentLength); + activity.SetTag("http.request_method", message.Method.Method); + activity.SetTag("http.request_url", message.RequestUri?.ToString()); + activity.SetTag("http.request_message_headers", message.Headers.ToString()); + activity.SetTag("http.request_body", message.Content?.ReadAsStringAsync().Result); + } + }; + httpClient.EnrichWithHttpResponseMessage = (activity, message) => + { + if (context.HostingEnvironment.IsDevelopment()) + { + activity.SetTag("http.response_content_length", + message.Content.Headers.ContentLength); + activity.SetTag("http.response_status_code", (int)message.StatusCode); + activity.SetTag("http.response_status_text", message.ReasonPhrase); + activity.SetTag("http.response_content_type", + message.Content.Headers.ContentType?.MediaType); + activity.SetTag("http.response_message_headers", message.Headers.ToString()); + activity.SetTag("http.response_body", message.Content.ReadAsStringAsync().Result); + } + }; + }); + }); + var useOtlpExporter = !string.IsNullOrWhiteSpace(context.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + if (useOtlpExporter) + { + services.AddOpenTelemetry().UseOtlpExporter(); + } + }); + return hostBuilder; + } +} diff --git a/ServiceDefaults/ServiceDefaults.csproj b/ServiceDefaults/ServiceDefaults.csproj new file mode 100644 index 000000000000..12b4707e9c89 --- /dev/null +++ b/ServiceDefaults/ServiceDefaults.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + enable + true + + + + + + + + + + + + + + + diff --git a/bitwarden-server.sln b/bitwarden-server.sln index 6786ad610c24..ba5e838ae4dd 100644 --- a/bitwarden-server.sln +++ b/bitwarden-server.sln @@ -134,10 +134,15 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DbSeederUtility", "util\DbSeederUtility\DbSeederUtility.csproj", "{17A89266-260A-4A03-81AE-C0468C6EE06E}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RustSdk", "util\RustSdk\RustSdk.csproj", "{D1513D90-E4F5-44A9-9121-5E46E3E4A3F7}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedWeb.Test", "test\SharedWeb.Test\SharedWeb.Test.csproj", "{AD59537D-5259-4B7A-948F-0CF58E80B359}" 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}") = "AppHost", "AppHost\AppHost.csproj", "{B4CC25D0-BD09-459E-9885-DF9A56E304F6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceDefaults", "ServiceDefaults\ServiceDefaults.csproj", "{7D6F3351-9CA6-4B35-956F-1EE346330A41}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -354,6 +359,14 @@ Global {7D98784C-C253-43FB-9873-25B65C6250D6}.Debug|Any CPU.Build.0 = Debug|Any CPU {7D98784C-C253-43FB-9873-25B65C6250D6}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D98784C-C253-43FB-9873-25B65C6250D6}.Release|Any CPU.Build.0 = Release|Any CPU + {B4CC25D0-BD09-459E-9885-DF9A56E304F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4CC25D0-BD09-459E-9885-DF9A56E304F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B4CC25D0-BD09-459E-9885-DF9A56E304F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B4CC25D0-BD09-459E-9885-DF9A56E304F6}.Release|Any CPU.Build.0 = Release|Any CPU + {7D6F3351-9CA6-4B35-956F-1EE346330A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D6F3351-9CA6-4B35-956F-1EE346330A41}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D6F3351-9CA6-4B35-956F-1EE346330A41}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D6F3351-9CA6-4B35-956F-1EE346330A41}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/dev/setup_secrets.ps1 b/dev/setup_secrets.ps1 index 96dff0463211..d570a74e4619 100644 --- a/dev/setup_secrets.ps1 +++ b/dev/setup_secrets.ps1 @@ -27,6 +27,7 @@ $projects = @{ Sso = "../bitwarden_license/src/Sso" Scim = "../bitwarden_license/src/Scim" IntegrationTests = "../test/Infrastructure.IntegrationTest" + AppHost = "../AppHost" } foreach ($key in $projects.keys) { From 7597b4ea714c62008aa61adbcece21d235bc64ac Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Wed, 10 Dec 2025 17:02:41 -0600 Subject: [PATCH 02/11] feat: Add compiler conditional ServiceDefaults to included projects --- src/Admin/Admin.csproj | 1 + src/Admin/Program.cs | 15 +++++++++++---- src/Api/Api.csproj | 1 + src/Api/Program.cs | 15 +++++++++++---- src/Billing/Billing.csproj | 1 + src/Billing/Program.cs | 16 ++++++++++++---- src/Identity/Identity.csproj | 1 + src/Identity/Program.cs | 14 +++++++++++--- src/Notifications/Notifications.csproj | 1 + src/Notifications/Program.cs | 15 +++++++++++---- 10 files changed, 61 insertions(+), 19 deletions(-) diff --git a/src/Admin/Admin.csproj b/src/Admin/Admin.csproj index cd30e841b451..787e9996866d 100644 --- a/src/Admin/Admin.csproj +++ b/src/Admin/Admin.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Admin/Program.cs b/src/Admin/Program.cs index 006a8223b27f..6773cc0d06c2 100644 --- a/src/Admin/Program.cs +++ b/src/Admin/Program.cs @@ -1,4 +1,7 @@ using Bit.Core.Utilities; +#if DEBUG +using Bit.ServiceDefaults; +#endif namespace Bit.Admin; @@ -6,7 +9,7 @@ public class Program { public static void Main(string[] args) { - Host + var builder = Host .CreateDefaultBuilder(args) .ConfigureCustomAppConfiguration(args) .ConfigureWebHostDefaults(webBuilder => @@ -17,8 +20,12 @@ public static void Main(string[] args) }); webBuilder.UseStartup(); }) - .AddSerilogFileLogging() - .Build() - .Run(); + .AddSerilogFileLogging(); + +#if DEBUG + builder.AddServiceDefaults(); +#endif + + builder.Build().Run(); } } diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj index 48fedfc8c119..8c7dca29dc7a 100644 --- a/src/Api/Api.csproj +++ b/src/Api/Api.csproj @@ -17,6 +17,7 @@ + diff --git a/src/Api/Program.cs b/src/Api/Program.cs index bf924af47ff1..62b388f2bef8 100644 --- a/src/Api/Program.cs +++ b/src/Api/Program.cs @@ -1,4 +1,7 @@ using Bit.Core.Utilities; +#if DEBUG +using Bit.ServiceDefaults; +#endif namespace Bit.Api; @@ -6,15 +9,19 @@ public class Program { public static void Main(string[] args) { - Host + var builder = Host .CreateDefaultBuilder(args) .ConfigureCustomAppConfiguration(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) - .AddSerilogFileLogging() - .Build() - .Run(); + .AddSerilogFileLogging(); + +#if DEBUG + builder.AddServiceDefaults(); +#endif + + builder.Build().Run(); } } diff --git a/src/Billing/Billing.csproj b/src/Billing/Billing.csproj index 69999dc7958d..36ed5babb8df 100644 --- a/src/Billing/Billing.csproj +++ b/src/Billing/Billing.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Billing/Program.cs b/src/Billing/Program.cs index 334dc49368dc..78159cbe6963 100644 --- a/src/Billing/Program.cs +++ b/src/Billing/Program.cs @@ -1,4 +1,7 @@ using Bit.Core.Utilities; +#if DEBUG +using Bit.ServiceDefaults; +#endif namespace Bit.Billing; @@ -6,15 +9,20 @@ public class Program { public static void Main(string[] args) { - Host + var builder = Host .CreateDefaultBuilder(args) .UseBitwardenSdk() .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) - .AddSerilogFileLogging() - .Build() - .Run(); + .AddSerilogFileLogging(); + +#if DEBUG + builder.AddServiceDefaults(); +#endif + + builder.Build().Run(); } } + diff --git a/src/Identity/Identity.csproj b/src/Identity/Identity.csproj index bf5ab82166bd..e703fe55cdf9 100644 --- a/src/Identity/Identity.csproj +++ b/src/Identity/Identity.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Identity/Program.cs b/src/Identity/Program.cs index 238ad8ce3a9c..8662336b442a 100644 --- a/src/Identity/Program.cs +++ b/src/Identity/Program.cs @@ -1,4 +1,7 @@ using Bit.Core.Utilities; +#if DEBUG +using Bit.ServiceDefaults; +#endif namespace Bit.Identity; @@ -6,9 +9,14 @@ public class Program { public static void Main(string[] args) { - CreateHostBuilder(args) - .Build() - .Run(); + var builder = CreateHostBuilder(args); + +#if DEBUG + builder.AddServiceDefaults(); +#endif + + builder.Build().Run(); + } public static IHostBuilder CreateHostBuilder(string[] args) diff --git a/src/Notifications/Notifications.csproj b/src/Notifications/Notifications.csproj index 4d19f7faf990..1e8ad21b4f02 100644 --- a/src/Notifications/Notifications.csproj +++ b/src/Notifications/Notifications.csproj @@ -16,6 +16,7 @@ + diff --git a/src/Notifications/Program.cs b/src/Notifications/Program.cs index 2792391729a7..ce593bea1a17 100644 --- a/src/Notifications/Program.cs +++ b/src/Notifications/Program.cs @@ -1,4 +1,7 @@ using Bit.Core.Utilities; +#if DEBUG +using Bit.ServiceDefaults; +#endif namespace Bit.Notifications; @@ -6,15 +9,19 @@ public class Program { public static void Main(string[] args) { - Host + var builder = Host .CreateDefaultBuilder(args) .ConfigureCustomAppConfiguration(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) - .AddSerilogFileLogging() - .Build() - .Run(); + .AddSerilogFileLogging(); + +#if DEBUG + builder.AddServiceDefaults(); +#endif + + builder.Build().Run(); } } From 3e1ee8a57faedcdcebb272f990e46e4bf44bfcaa Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Mon, 19 Jan 2026 10:38:32 -0500 Subject: [PATCH 03/11] fix(billing): update otlexporter duplicate call --- ServiceDefaults/Extensions.cs | 14 +++++++++----- bitwarden-server.sln | 4 ++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/ServiceDefaults/Extensions.cs b/ServiceDefaults/Extensions.cs index 8e97f0c17840..352718b7d73f 100644 --- a/ServiceDefaults/Extensions.cs +++ b/ServiceDefaults/Extensions.cs @@ -3,10 +3,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using OpenTelemetry; -using OpenTelemetry.Metrics; -using OpenTelemetry.Trace; namespace Bit.ServiceDefaults; @@ -189,7 +185,15 @@ public static IHostBuilder AddServiceDefaults(this IHostBuilder hostBuilder) var useOtlpExporter = !string.IsNullOrWhiteSpace(context.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); if (useOtlpExporter) { - services.AddOpenTelemetry().UseOtlpExporter(); + // Check if OTLP exporter is already configured + var otlpExporterAlreadyRegistered = services.Any(sd => + sd.ServiceType.FullName?.Contains("OtlpExporter") == true || + sd.ImplementationType?.FullName?.Contains("OtlpExporter") == true); + + if (!otlpExporterAlreadyRegistered) + { + services.AddOpenTelemetry().UseOtlpExporter(); + } } }); return hostBuilder; diff --git a/bitwarden-server.sln b/bitwarden-server.sln index 2dacaf648952..c92e3de89c79 100644 --- a/bitwarden-server.sln +++ b/bitwarden-server.sln @@ -379,6 +379,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 + {B4CC25D0-BD09-459E-9885-DF9A56E304F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B4CC25D0-BD09-459E-9885-DF9A56E304F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D6F3351-9CA6-4B35-956F-1EE346330A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D6F3351-9CA6-4B35-956F-1EE346330A41}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From fe72d2c6cc6ed2c567148e19a00f6bfd30f7b771 Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Tue, 20 Jan 2026 14:35:00 -0500 Subject: [PATCH 04/11] fix(billing): update imports --- ServiceDefaults/Extensions.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ServiceDefaults/Extensions.cs b/ServiceDefaults/Extensions.cs index 352718b7d73f..63e1a0a1a4df 100644 --- a/ServiceDefaults/Extensions.cs +++ b/ServiceDefaults/Extensions.cs @@ -3,6 +3,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; namespace Bit.ServiceDefaults; From a069e72897240e5ab3e29e3ab39c62aad360cf0d Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Tue, 20 Jan 2026 15:04:38 -0500 Subject: [PATCH 05/11] fix(billing): revert unintended changes --- test/SeederApi.IntegrationTest/QueryControllerTest.cs | 1 + test/SeederApi.IntegrationTest/SeedControllerTest.cs | 1 + .../SeederApiApplicationFactory.cs | 3 ++- test/Server.IntegrationTest/Server.cs | 6 +++++- util/SeederApi/Commands/DestroySceneCommand.cs | 4 +++- util/SeederApi/Controllers/InfoController.cs | 3 ++- util/SeederApi/Program.cs | 4 +++- util/SeederApi/Queries/GetAllPlayIdsQuery.cs | 3 ++- util/SeederApi/Startup.cs | 1 + 9 files changed, 20 insertions(+), 6 deletions(-) diff --git a/test/SeederApi.IntegrationTest/QueryControllerTest.cs b/test/SeederApi.IntegrationTest/QueryControllerTest.cs index 0b8707c6ce65..571181e49fd4 100644 --- a/test/SeederApi.IntegrationTest/QueryControllerTest.cs +++ b/test/SeederApi.IntegrationTest/QueryControllerTest.cs @@ -1,5 +1,6 @@ using System.Net; using Bit.SeederApi.Models.Request; +using Xunit; namespace Bit.SeederApi.IntegrationTest; diff --git a/test/SeederApi.IntegrationTest/SeedControllerTest.cs b/test/SeederApi.IntegrationTest/SeedControllerTest.cs index 8766634ad020..1d081d019e92 100644 --- a/test/SeederApi.IntegrationTest/SeedControllerTest.cs +++ b/test/SeederApi.IntegrationTest/SeedControllerTest.cs @@ -1,6 +1,7 @@ using System.Net; using Bit.SeederApi.Models.Request; using Bit.SeederApi.Models.Response; +using Xunit; namespace Bit.SeederApi.IntegrationTest; diff --git a/test/SeederApi.IntegrationTest/SeederApiApplicationFactory.cs b/test/SeederApi.IntegrationTest/SeederApiApplicationFactory.cs index 3811c317538a..6d815b03eaa5 100644 --- a/test/SeederApi.IntegrationTest/SeederApiApplicationFactory.cs +++ b/test/SeederApi.IntegrationTest/SeederApiApplicationFactory.cs @@ -1,4 +1,5 @@ -using Bit.IntegrationTestCommon; +using Bit.Core.Services; +using Bit.IntegrationTestCommon; using Bit.IntegrationTestCommon.Factories; namespace Bit.SeederApi.IntegrationTest; diff --git a/test/Server.IntegrationTest/Server.cs b/test/Server.IntegrationTest/Server.cs index 75f88cbbe77d..073dbffb5a6c 100644 --- a/test/Server.IntegrationTest/Server.cs +++ b/test/Server.IntegrationTest/Server.cs @@ -1,4 +1,8 @@ -namespace Bit.Server.IntegrationTest; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.TestHost; + +namespace Bit.Server.IntegrationTest; public class Server : WebApplicationFactory { diff --git a/util/SeederApi/Commands/DestroySceneCommand.cs b/util/SeederApi/Commands/DestroySceneCommand.cs index 32294f26c111..0e0f4edd6d9b 100644 --- a/util/SeederApi/Commands/DestroySceneCommand.cs +++ b/util/SeederApi/Commands/DestroySceneCommand.cs @@ -1,4 +1,6 @@ -using Bit.SeederApi.Commands.Interfaces; +using Bit.Core.Repositories; +using Bit.Infrastructure.EntityFramework.Repositories; +using Bit.SeederApi.Commands.Interfaces; using Bit.SeederApi.Services; namespace Bit.SeederApi.Commands; diff --git a/util/SeederApi/Controllers/InfoController.cs b/util/SeederApi/Controllers/InfoController.cs index 100035de4d47..de4a264ddb1a 100644 --- a/util/SeederApi/Controllers/InfoController.cs +++ b/util/SeederApi/Controllers/InfoController.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Bit.Core.Utilities; +using Microsoft.AspNetCore.Mvc; namespace Bit.SeederApi.Controllers; diff --git a/util/SeederApi/Program.cs b/util/SeederApi/Program.cs index ef03d54d3b44..2067df307a09 100644 --- a/util/SeederApi/Program.cs +++ b/util/SeederApi/Program.cs @@ -1,4 +1,6 @@ -namespace Bit.SeederApi; +using Bit.Core.Utilities; + +namespace Bit.SeederApi; public class Program { diff --git a/util/SeederApi/Queries/GetAllPlayIdsQuery.cs b/util/SeederApi/Queries/GetAllPlayIdsQuery.cs index 477606162c11..7bc72e5b07f3 100644 --- a/util/SeederApi/Queries/GetAllPlayIdsQuery.cs +++ b/util/SeederApi/Queries/GetAllPlayIdsQuery.cs @@ -1,4 +1,5 @@ -using Bit.SeederApi.Queries.Interfaces; +using Bit.Infrastructure.EntityFramework.Repositories; +using Bit.SeederApi.Queries.Interfaces; namespace Bit.SeederApi.Queries; diff --git a/util/SeederApi/Startup.cs b/util/SeederApi/Startup.cs index 3d02ddb57f27..420078f5096f 100644 --- a/util/SeederApi/Startup.cs +++ b/util/SeederApi/Startup.cs @@ -1,4 +1,5 @@ using System.Globalization; +using Bit.Core.Settings; using Bit.Seeder; using Bit.Seeder.Factories; using Bit.SeederApi.Extensions; From 79fd6e08ed72d75430368c55eccfe94b96c45810 Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Tue, 20 Jan 2026 15:13:51 -0500 Subject: [PATCH 06/11] fix(billing): revert unintended changes --- .../Controllers/AccountControllerTests.cs | 12 ++++++++++++ .../Utilities/SsoTestDataBuilder.cs | 13 ++++++++++++- .../Utilities/SuccessfulAuthResult.cs | 2 ++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/bitwarden_license/test/Sso.IntegrationTest/Controllers/AccountControllerTests.cs b/bitwarden_license/test/Sso.IntegrationTest/Controllers/AccountControllerTests.cs index 4c5019530c8b..7a1c9f9628a4 100644 --- a/bitwarden_license/test/Sso.IntegrationTest/Controllers/AccountControllerTests.cs +++ b/bitwarden_license/test/Sso.IntegrationTest/Controllers/AccountControllerTests.cs @@ -1,9 +1,21 @@ using System.Net; +using Bit.Core; +using Bit.Core.AdminConsole.Entities; +using Bit.Core.Auth.Entities; +using Bit.Core.Auth.Models.Data; +using Bit.Core.Auth.Repositories; +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Repositories; +using Bit.Core.Services; using Bit.Sso.IntegrationTest.Utilities; using Bit.Test.Common.AutoFixture.Attributes; using Bitwarden.License.Test.Sso.IntegrationTest.Utilities; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc.Testing; +using NSubstitute; +using Xunit; using AuthenticationSchemes = Bit.Core.AuthenticationSchemes; namespace Bit.Sso.IntegrationTest.Controllers; diff --git a/bitwarden_license/test/Sso.IntegrationTest/Utilities/SsoTestDataBuilder.cs b/bitwarden_license/test/Sso.IntegrationTest/Utilities/SsoTestDataBuilder.cs index 22422586ac1f..95f2387af268 100644 --- a/bitwarden_license/test/Sso.IntegrationTest/Utilities/SsoTestDataBuilder.cs +++ b/bitwarden_license/test/Sso.IntegrationTest/Utilities/SsoTestDataBuilder.cs @@ -1,5 +1,16 @@ -using Bitwarden.License.Test.Sso.IntegrationTest.Utilities; +using Bit.Core.AdminConsole.Entities; +using Bit.Core.Auth.Entities; +using Bit.Core.Auth.Models.Data; +using Bit.Core.Auth.Repositories; +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Repositories; +using Bit.Core.Settings; +using Bitwarden.License.Test.Sso.IntegrationTest.Utilities; +using Duende.IdentityServer.Models; +using Duende.IdentityServer.Services; using Microsoft.AspNetCore.Authentication; +using NSubstitute; using AuthenticationSchemes = Bit.Core.AuthenticationSchemes; namespace Bit.Sso.IntegrationTest.Utilities; diff --git a/bitwarden_license/test/Sso.IntegrationTest/Utilities/SuccessfulAuthResult.cs b/bitwarden_license/test/Sso.IntegrationTest/Utilities/SuccessfulAuthResult.cs index 99a5000ab268..72f5738ad984 100644 --- a/bitwarden_license/test/Sso.IntegrationTest/Utilities/SuccessfulAuthResult.cs +++ b/bitwarden_license/test/Sso.IntegrationTest/Utilities/SuccessfulAuthResult.cs @@ -1,4 +1,6 @@ using System.Security.Claims; +using Bit.Core; +using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; namespace Bitwarden.License.Test.Sso.IntegrationTest.Utilities; From f7a80708f61a8255a6ea2cb81156d229ef273d46 Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Tue, 20 Jan 2026 15:28:35 -0500 Subject: [PATCH 07/11] fix(billing): fix unintended files --- bitwarden-server.sln | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/bitwarden-server.sln b/bitwarden-server.sln index c92e3de89c79..0598a2d6f632 100644 --- a/bitwarden-server.sln +++ b/bitwarden-server.sln @@ -147,10 +147,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sso.IntegrationTest", "bitw EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.IntegrationTest", "test\Server.IntegrationTest\Server.IntegrationTest.csproj", "{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppHost", "AppHost\AppHost.csproj", "{B4CC25D0-BD09-459E-9885-DF9A56E304F6}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceDefaults", "ServiceDefaults\ServiceDefaults.csproj", "{7D6F3351-9CA6-4B35-956F-1EE346330A41}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -379,10 +375,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 - {B4CC25D0-BD09-459E-9885-DF9A56E304F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B4CC25D0-BD09-459E-9885-DF9A56E304F6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7D6F3351-9CA6-4B35-956F-1EE346330A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7D6F3351-9CA6-4B35-956F-1EE346330A41}.Debug|Any CPU.Build.0 = Debug|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 From 471cb8d628d49e4e99edc8cd201f8cc524ce9847 Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Tue, 20 Jan 2026 16:12:24 -0500 Subject: [PATCH 08/11] fix(billing): add apphost and extension methods --- bitwarden-server.sln | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bitwarden-server.sln b/bitwarden-server.sln index 0598a2d6f632..e4aba333f008 100644 --- a/bitwarden-server.sln +++ b/bitwarden-server.sln @@ -147,6 +147,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sso.IntegrationTest", "bitw EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server.IntegrationTest", "test\Server.IntegrationTest\Server.IntegrationTest.csproj", "{E75E1F10-BC6F-4EB1-BA75-D897C45AEA0D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppHost", "AppHost\AppHost.csproj", "{0EEFA4FC-4EEC-4E3F-8ED7-28FD33201701}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceDefaults", "ServiceDefaults\ServiceDefaults.csproj", "{CDC04BCD-A115-456A-8F76-20CB522C5814}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -379,6 +383,14 @@ Global {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 + {0EEFA4FC-4EEC-4E3F-8ED7-28FD33201701}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0EEFA4FC-4EEC-4E3F-8ED7-28FD33201701}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0EEFA4FC-4EEC-4E3F-8ED7-28FD33201701}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0EEFA4FC-4EEC-4E3F-8ED7-28FD33201701}.Release|Any CPU.Build.0 = Release|Any CPU + {CDC04BCD-A115-456A-8F76-20CB522C5814}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CDC04BCD-A115-456A-8F76-20CB522C5814}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CDC04BCD-A115-456A-8F76-20CB522C5814}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CDC04BCD-A115-456A-8F76-20CB522C5814}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From f7414256161ab0c191338aab1ba9e127d518ede9 Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Tue, 20 Jan 2026 20:52:31 -0500 Subject: [PATCH 09/11] fix(billing): update aspire --- AppHost/AppHost.csproj | 16 +++++++--------- ServiceDefaults/ServiceDefaults.csproj | 16 ++++++++-------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/AppHost/AppHost.csproj b/AppHost/AppHost.csproj index ea03a3bed14d..c31cb35425a0 100644 --- a/AppHost/AppHost.csproj +++ b/AppHost/AppHost.csproj @@ -1,6 +1,4 @@ - - - + Exe @@ -11,12 +9,12 @@ - - - - - - + + + + + + diff --git a/ServiceDefaults/ServiceDefaults.csproj b/ServiceDefaults/ServiceDefaults.csproj index 12b4707e9c89..1487a63e10a0 100644 --- a/ServiceDefaults/ServiceDefaults.csproj +++ b/ServiceDefaults/ServiceDefaults.csproj @@ -8,15 +8,15 @@ - + - - - - - - - + + + + + + + From 9f6286fff60a794aa054559d94d33b5f9a39366c Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Tue, 20 Jan 2026 22:19:51 -0500 Subject: [PATCH 10/11] fix(billing): update references to match integration test configuration version --- ServiceDefaults/ServiceDefaults.csproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ServiceDefaults/ServiceDefaults.csproj b/ServiceDefaults/ServiceDefaults.csproj index 1487a63e10a0..bfaea3b9b8e2 100644 --- a/ServiceDefaults/ServiceDefaults.csproj +++ b/ServiceDefaults/ServiceDefaults.csproj @@ -10,13 +10,13 @@ - + - - - - - + + + + + From 35ca62a2ed6a9199325bc0ebc91bd533043b1d64 Mon Sep 17 00:00:00 2001 From: Stephon Brown Date: Wed, 21 Jan 2026 10:28:13 -0500 Subject: [PATCH 11/11] chore(billing): update secrets.json example --- dev/secrets.json.example | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/dev/secrets.json.example b/dev/secrets.json.example index 0d4213aec184..f20ab8b2257c 100644 --- a/dev/secrets.json.example +++ b/dev/secrets.json.example @@ -11,8 +11,24 @@ }, "globalSettings": { "selfHosted": true, + "launchDarkly": { + "flagValues": { + } + }, + "pricingUri": "", + "baseServiceUri": { + "cloudRegion": "", + "vault": "", + "api": "", + "identity": "", + "admin": "", + "notifications": "", + "sso": "", + "billing": "" + }, "sqlServer": { - "connectionString": "Server=localhost;Database=vault_dev;User Id=SA;Password=SET_A_PASSWORD_HERE_123;Encrypt=True;TrustServerCertificate=True" + "connectionString": "Server=localhost;Database=vault_dev;User Id=SA;Password=SET_A_PASSWORD_HERE_123;Encrypt=True;TrustServerCertificate=True", + "password": }, "postgreSql": { "connectionString": "Host=localhost;Username=postgres;Password=SET_A_PASSWORD_HERE_123;Database=vault_dev;Include Error Detail=true" @@ -40,5 +56,15 @@ "licenseDirectory": "", "enableNewDeviceVerification": true, "enableEmailVerification": true - } + }, + "ngrokAuthToken": "", + "workingDirectory": "../dev", + "clientsRelativePath": "", + "pricingServiceSecretsPath": "", + "pricingServiceRelativePath": "", + "scripts": { + "dbMigration": "migrate.ps1", + "azuriteSetup": "setup_azurite.ps1", + "secretsSetup": "setup_secrets.ps1" + }, }