Doctor plugin checks: implement health check classes and documentation

Implement remediation-aware health checks across all Doctor plugin modules
(Agent, Attestor, Auth, BinaryAnalysis, Compliance, Crypto, Environment,
EvidenceLocker, Notify, Observability, Operations, Policy, Postgres, Release,
Scanner, Storage, Vex) and their backing library counterparts (AI, Attestation,
Authority, Core, Cryptography, Database, Docker, Integration, Notify,
Observability, Security, ServiceGraph, Sources, Verification).

Each check now emits structured remediation metadata (severity, category,
runbook links, and fix suggestions) consumed by the Doctor dashboard
remediation panel.

Also adds:
- docs/doctor/articles/ knowledge base for check explanations
- Advisory AI search seed and allowlist updates for doctor content
- Sprint plan for doctor checks documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-03-27 12:28:00 +02:00
parent fbd24e71de
commit c58a236d70
326 changed files with 18500 additions and 463 deletions

View File

@@ -127,7 +127,8 @@ public sealed class ApiKeySecurityCheck : IDoctorCheck
.WithRemediation(r => r
.AddManualStep(1, "Set minimum length", "Configure ApiKey:MinLength to at least 32")
.AddManualStep(2, "Disable query string", "Set ApiKey:AllowInQueryString to false")
.AddManualStep(3, "Enable rate limiting", "Set ApiKey:RateLimitPerKey to true"))
.AddManualStep(3, "Enable rate limiting", "Set ApiKey:RateLimitPerKey to true")
.WithRunbookUrl("docs/doctor/articles/security/security-apikey.md"))
.WithVerification("stella doctor --check check.security.apikey")
.Build());
}

View File

@@ -67,7 +67,8 @@ public sealed class AuditLoggingCheck : IDoctorCheck
})
.WithCauses("Audit logging disabled in configuration")
.WithRemediation(r => r
.AddManualStep(1, "Enable audit logging", "Set Audit:Enabled to true"))
.AddManualStep(1, "Enable audit logging", "Set Audit:Enabled to true")
.WithRunbookUrl("docs/doctor/articles/security/security-audit-logging.md"))
.WithVerification("stella doctor --check check.security.audit.logging")
.Build());
}
@@ -108,7 +109,8 @@ public sealed class AuditLoggingCheck : IDoctorCheck
.WithRemediation(r => r
.AddManualStep(1, "Enable audit logging", "Set Audit:Enabled to true")
.AddManualStep(2, "Configure events", "Enable logging for auth, access, and admin events")
.AddManualStep(3, "Set destination", "Configure audit log destination"))
.AddManualStep(3, "Set destination", "Configure audit log destination")
.WithRunbookUrl("docs/doctor/articles/security/security-audit-logging.md"))
.WithVerification("stella doctor --check check.security.audit.logging")
.Build());
}

View File

@@ -101,7 +101,8 @@ public sealed class CorsConfigurationCheck : IDoctorCheck
.WithCauses(issues.ToArray())
.WithRemediation(r => r
.AddManualStep(1, "Specify origins", "Configure explicit allowed origins in Cors:AllowedOrigins")
.AddManualStep(2, "Use HTTPS", "Ensure all allowed origins use HTTPS"))
.AddManualStep(2, "Use HTTPS", "Ensure all allowed origins use HTTPS")
.WithRunbookUrl("docs/doctor/articles/security/security-cors.md"))
.WithVerification("stella doctor --check check.security.cors")
.Build());
}

View File

@@ -97,7 +97,8 @@ public sealed class EncryptionKeyCheck : IDoctorCheck
.WithCauses(issues.ToArray())
.WithRemediation(r => r
.AddManualStep(1, "Use strong algorithm", "Configure AES-256 or stronger")
.AddManualStep(2, "Set key rotation", "Configure Encryption:KeyRotationDays"))
.AddManualStep(2, "Set key rotation", "Configure Encryption:KeyRotationDays")
.WithRunbookUrl("docs/doctor/articles/security/security-encryption.md"))
.WithVerification("stella doctor --check check.security.encryption")
.Build());
}

View File

@@ -77,7 +77,8 @@ public sealed class EvidenceIntegrityCheck : IDoctorCheck
.WithCauses("Evidence locker has not been initialized", "Path is incorrect")
.WithRemediation(r => r
.AddManualStep(1, "Create directory", $"mkdir -p {evidenceLockerPath}")
.AddManualStep(2, "Check configuration", "Verify EvidenceLocker:LocalPath setting"))
.AddManualStep(2, "Check configuration", "Verify EvidenceLocker:LocalPath setting")
.WithRunbookUrl("docs/doctor/articles/security/security-evidence-integrity.md"))
.WithVerification("stella doctor --check check.security.evidence.integrity")
.Build();
}
@@ -162,7 +163,8 @@ public sealed class EvidenceIntegrityCheck : IDoctorCheck
.WithRemediation(r => r
.AddManualStep(1, "Review issues", "Examine the invalid files listed above")
.AddManualStep(2, "Re-generate evidence", "Re-scan and re-sign affected evidence bundles")
.AddManualStep(3, "Check Rekor", "Verify transparency log entries are valid"))
.AddManualStep(3, "Check Rekor", "Verify transparency log entries are valid")
.WithRunbookUrl("docs/doctor/articles/security/security-evidence-integrity.md"))
.WithVerification("stella doctor --check check.security.evidence.integrity")
.Build();
}

View File

@@ -115,7 +115,8 @@ public sealed class JwtConfigurationCheck : IDoctorCheck
.WithRemediation(r => r
.AddManualStep(1, "Configure JWT settings", "Set Jwt:SigningKey, Jwt:Issuer, and Jwt:Audience")
.AddManualStep(2, "Use strong key", "Ensure signing key is at least 32 characters")
.AddManualStep(3, "Consider RS256", "Use asymmetric algorithms for production"))
.AddManualStep(3, "Consider RS256", "Use asymmetric algorithms for production")
.WithRunbookUrl("docs/doctor/articles/security/security-jwt-config.md"))
.WithVerification("stella doctor --check check.security.jwt.config")
.Build());
}

View File

@@ -132,7 +132,8 @@ public sealed class PasswordPolicyCheck : IDoctorCheck
.WithCauses(issues.ToArray())
.WithRemediation(r => r
.AddManualStep(1, "Increase minimum length", "Set Identity:Password:RequiredLength to at least 12")
.AddManualStep(2, "Enable complexity", "Require digits, uppercase, lowercase, and special characters"))
.AddManualStep(2, "Enable complexity", "Require digits, uppercase, lowercase, and special characters")
.WithRunbookUrl("docs/doctor/articles/security/security-password-policy.md"))
.WithVerification("stella doctor --check check.security.password.policy")
.Build());
}

View File

@@ -63,7 +63,8 @@ public sealed class RateLimitingCheck : IDoctorCheck
})
.WithCauses("Rate limiting explicitly disabled in configuration")
.WithRemediation(r => r
.AddManualStep(1, "Enable rate limiting", "Set RateLimiting:Enabled to true"))
.AddManualStep(1, "Enable rate limiting", "Set RateLimiting:Enabled to true")
.WithRunbookUrl("docs/doctor/articles/security/security-ratelimit.md"))
.WithVerification("stella doctor --check check.security.ratelimit")
.Build());
}

View File

@@ -37,10 +37,11 @@ public sealed class SecretsConfigurationCheck : IDoctorCheck
var issues = new List<string>();
// Only check actual secret values (keys, passwords, tokens).
// Connection strings are NOT secrets — they are DSNs that contain host/port/db
// and are expected in configuration for all deployment modes.
var sensitiveKeys = new[]
{
"ConnectionStrings:Default",
"Database:ConnectionString",
"Jwt:SigningKey",
"Jwt:Secret",
"ApiKey",
@@ -77,7 +78,8 @@ public sealed class SecretsConfigurationCheck : IDoctorCheck
if (!useSecretManager && issues.Count > 0)
{
issues.Add("No secrets management provider configured");
// Only flag missing secrets manager if actual plaintext secrets were found
issues.Add("Consider configuring a secrets management provider (Vault, Azure Key Vault, or dotnet user-secrets)");
}
if (issues.Count > 0)
@@ -94,7 +96,8 @@ public sealed class SecretsConfigurationCheck : IDoctorCheck
.WithRemediation(r => r
.AddManualStep(1, "Use secrets manager", "Configure a secrets provider like HashiCorp Vault or Azure Key Vault")
.AddManualStep(2, "Use environment variables", "Move secrets to environment variables")
.AddManualStep(3, "Use user secrets", "Use dotnet user-secrets for development"))
.AddManualStep(3, "Use user secrets", "Use dotnet user-secrets for development")
.WithRunbookUrl("docs/doctor/articles/security/security-secrets.md"))
.WithVerification("stella doctor --check check.security.secrets")
.Build());
}

View File

@@ -97,7 +97,8 @@ public sealed class SecurityHeadersCheck : IDoctorCheck
.WithRemediation(r => r
.AddManualStep(1, "Enable HSTS", "Set Security:Headers:Hsts:Enabled to true")
.AddManualStep(2, "Set X-Frame-Options", "Configure as DENY or SAMEORIGIN")
.AddManualStep(3, "Configure CSP", "Set a Content-Security-Policy appropriate for your app"))
.AddManualStep(3, "Configure CSP", "Set a Content-Security-Policy appropriate for your app")
.WithRunbookUrl("docs/doctor/articles/security/security-headers.md"))
.WithVerification("stella doctor --check check.security.headers")
.Build());
}

View File

@@ -66,7 +66,8 @@ public sealed class TlsCertificateCheck : IDoctorCheck
.WithCauses("Certificate file path is incorrect", "Certificate file was deleted")
.WithRemediation(r => r
.AddManualStep(1, "Verify path", "Check Tls:CertificatePath configuration")
.AddManualStep(2, "Generate certificate", "Generate or obtain a valid TLS certificate"))
.AddManualStep(2, "Generate certificate", "Generate or obtain a valid TLS certificate")
.WithRunbookUrl("docs/doctor/articles/security/security-tls-certificate.md"))
.WithVerification("stella doctor --check check.security.tls.certificate")
.Build());
}
@@ -112,7 +113,8 @@ public sealed class TlsCertificateCheck : IDoctorCheck
.WithCauses("Certificate has exceeded its validity period")
.WithRemediation(r => r
.AddManualStep(1, "Renew certificate", "Obtain a new TLS certificate")
.AddManualStep(2, "Update configuration", "Update Tls:CertificatePath with new certificate"))
.AddManualStep(2, "Update configuration", "Update Tls:CertificatePath with new certificate")
.WithRunbookUrl("docs/doctor/articles/security/security-tls-certificate.md"))
.WithVerification("stella doctor --check check.security.tls.certificate")
.Build());
}
@@ -130,7 +132,8 @@ public sealed class TlsCertificateCheck : IDoctorCheck
})
.WithCauses("Certificate is approaching expiration")
.WithRemediation(r => r
.AddManualStep(1, "Plan renewal", "Schedule certificate renewal before expiration"))
.AddManualStep(1, "Plan renewal", "Schedule certificate renewal before expiration")
.WithRunbookUrl("docs/doctor/articles/security/security-tls-certificate.md"))
.Build());
}