sln build fix (again), tests fixes, audit work and doctors work

This commit is contained in:
master
2026-01-12 22:15:51 +02:00
parent 9873f80830
commit 9330c64349
812 changed files with 48051 additions and 3891 deletions

View File

@@ -0,0 +1,125 @@
using Microsoft.Extensions.Configuration;
using Npgsql;
using StellaOps.Doctor.Models;
using StellaOps.Doctor.Plugins;
namespace StellaOps.Doctor.Plugins.Database.Checks;
/// <summary>
/// Base class for database checks providing common functionality.
/// </summary>
public abstract class DatabaseCheckBase : IDoctorCheck
{
private const string DefaultConnectionStringKey = "ConnectionStrings:DefaultConnection";
private const string PluginId = "stellaops.doctor.database";
private const string CategoryName = "Database";
/// <inheritdoc />
public abstract string CheckId { get; }
/// <inheritdoc />
public abstract string Name { get; }
/// <inheritdoc />
public abstract string Description { get; }
/// <inheritdoc />
public virtual DoctorSeverity DefaultSeverity => DoctorSeverity.Fail;
/// <inheritdoc />
public abstract IReadOnlyList<string> Tags { get; }
/// <inheritdoc />
public virtual TimeSpan EstimatedDuration => TimeSpan.FromSeconds(2);
/// <inheritdoc />
public virtual bool CanRun(DoctorPluginContext context)
{
var connectionString = GetConnectionString(context);
return !string.IsNullOrEmpty(connectionString);
}
/// <inheritdoc />
public async Task<DoctorCheckResult> RunAsync(DoctorPluginContext context, CancellationToken ct)
{
var result = context.CreateResult(CheckId, PluginId, CategoryName);
var connectionString = GetConnectionString(context);
if (string.IsNullOrEmpty(connectionString))
{
return result
.Skip("No database connection string configured")
.WithEvidence("Configuration", e => e
.Add("ConnectionStringKey", DefaultConnectionStringKey)
.Add("Configured", "false"))
.Build();
}
try
{
return await ExecuteCheckAsync(context, connectionString, result, ct);
}
catch (NpgsqlException ex)
{
return result
.Fail($"Database error: {ex.Message}")
.WithEvidence("Error details", e => e
.Add("ExceptionType", ex.GetType().Name)
.Add("SqlState", ex.SqlState ?? "(none)")
.Add("Message", ex.Message))
.WithCauses(
"Database server unavailable",
"Authentication failed",
"Network connectivity issue")
.WithRemediation(r => r
.AddShellStep(1, "Test connection", "psql -h <host> -U <user> -d <database> -c 'SELECT 1'")
.AddManualStep(2, "Check credentials", "Verify database username and password in configuration"))
.WithVerification($"stella doctor --check {CheckId}")
.Build();
}
catch (Exception ex)
{
return result
.Fail($"Unexpected error: {ex.Message}")
.WithEvidence("Error details", e => e
.Add("ExceptionType", ex.GetType().Name)
.Add("Message", ex.Message))
.Build();
}
}
/// <summary>
/// Executes the specific check logic.
/// </summary>
protected abstract Task<DoctorCheckResult> ExecuteCheckAsync(
DoctorPluginContext context,
string connectionString,
Builders.CheckResultBuilder result,
CancellationToken ct);
/// <summary>
/// Gets the database connection string from configuration.
/// </summary>
protected static string? GetConnectionString(DoctorPluginContext context)
{
// Try plugin-specific connection string first
var pluginConnectionString = context.PluginConfig["ConnectionString"];
if (!string.IsNullOrEmpty(pluginConnectionString))
{
return pluginConnectionString;
}
// Fall back to default connection string
return context.Configuration[DefaultConnectionStringKey];
}
/// <summary>
/// Creates a new database connection.
/// </summary>
protected static async Task<NpgsqlConnection> CreateConnectionAsync(string connectionString, CancellationToken ct)
{
var connection = new NpgsqlConnection(connectionString);
await connection.OpenAsync(ct);
return connection;
}
}