Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,14 @@ public static WebApplication EnsureDatabaseAvailable(this WebApplication app)
var maxRetryAttempts = app.Configuration.GetValue<int?>("DatabaseRetry:MaxAttempts") ?? 5;
var baseSeconds = app.Configuration.GetValue<int?>("DatabaseRetry:BaseSeconds") ?? 2;

// Get redacted connection string for logging (password never stored)
var connPreview = GetRedactedConnectionString(app.Configuration);

var policy = Policy.Handle<Exception>()
.WaitAndRetry(maxRetryAttempts, retryAttempt =>
{
var jitter = TimeSpan.FromMilliseconds(new Random().Next(0, 1000));
return TimeSpan.FromSeconds(Math.Pow(baseSeconds, retryAttempt)) + jitter;
}, (exception, timeSpan, retryCount, context) =>
{
logger?.LogWarning(exception, "Database connectivity attempt {RetryCount} failed for {ConnectionPreview}. Next retry in {Delay}.", retryCount, connPreview, timeSpan);
logger?.LogWarning(exception, "Database connectivity attempt {RetryCount} failed. Next retry in {Delay}.", retryCount, timeSpan);
});

try
Expand All @@ -52,35 +49,9 @@ public static WebApplication EnsureDatabaseAvailable(this WebApplication app)
}
catch (Exception ex)
{
logger?.LogError(ex, "Database connectivity could not be established after {Attempts} attempts to {ConnectionPreview}. Verify the database is running and the connection settings (env/.env). Startup will continue; migrations may fail.", maxRetryAttempts, connPreview);
logger?.LogError(ex, "Database connectivity could not be established after {Attempts} attempts. Verify the database is running and the connection settings (env/.env). Startup will continue; migrations may fail.", maxRetryAttempts);
}

return app;
}

private static string GetRedactedConnectionString(IConfiguration configuration)
{
var conn = configuration.GetConnectionString("DefaultConnection");
return RedactPassword(conn ?? "(none)");
}

private static string RedactPassword(string connectionString)
{
if (string.IsNullOrWhiteSpace(connectionString))
return "(none)";

try
{
// Use regex to redact password value
return System.Text.RegularExpressions.Regex.Replace(
connectionString,
@"(Password|Pwd)\s*=\s*[^;]*",
"$1=***",
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
}
catch
{
return "(invalid)";
}
}
}
23 changes: 1 addition & 22 deletions src/server/services/dotnet/Reminders.MigrationsRunner/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,7 @@
migrationStatus = MigrationStatus.Running;
startTime = DateTime.UtcNow;

// Redact password from connection string for logging
var redactedConnectionString = RedactConnectionString(connectionString);
logger.LogInformation("Migration runner starting with provider: {Provider}, connection: {Connection}",
provider, redactedConnectionString);
logger.LogInformation("Migration runner starting with provider: {Provider}", provider);

using var scope = app.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<RemindersContext>();
Expand Down Expand Up @@ -207,24 +204,6 @@ await policy.ExecuteAsync(async () =>
// Exit with appropriate code
Environment.Exit(migrationStatus == MigrationStatus.Completed ? 0 : 1);

// Helper method to redact passwords from connection strings
static string RedactConnectionString(string connectionString)
{
var parts = connectionString.Split(';', StringSplitOptions.RemoveEmptyEntries);
var redacted = parts.Select(part =>
{
var keyValue = part.Split('=', 2);
if (keyValue.Length == 2 &&
(keyValue[0].Trim().Equals("Password", StringComparison.OrdinalIgnoreCase) ||
keyValue[0].Trim().Equals("Pwd", StringComparison.OrdinalIgnoreCase)))
{
return $"{keyValue[0]}=***";
}
return part;
});
return string.Join(";", redacted);
}

// MigrationStatus enum for tracking execution state
enum MigrationStatus
{
Expand Down