doctor: complete runtime check documentation sprint

Signed-off-by: master <>
This commit is contained in:
master
2026-03-31 23:26:24 +03:00
parent 404d50bcb7
commit 152c1b1357
54 changed files with 2210 additions and 258 deletions

View File

@@ -11,6 +11,8 @@ namespace StellaOps.Doctor.Plugins.Verification.Checks;
/// </summary>
public sealed class PolicyEngineCheck : VerificationCheckBase
{
private const string RunbookUrlValue = "docs/doctor/articles/verification/verification-policy-engine.md";
/// <inheritdoc />
public override string CheckId => "check.verification.policy.engine";
@@ -26,6 +28,9 @@ public sealed class PolicyEngineCheck : VerificationCheckBase
/// <inheritdoc />
public override TimeSpan EstimatedDuration => TimeSpan.FromSeconds(15);
/// <inheritdoc />
protected override string RunbookUrl => RunbookUrlValue;
/// <inheritdoc />
public override bool CanRun(DoctorPluginContext context)
{
@@ -75,7 +80,7 @@ public sealed class PolicyEngineCheck : VerificationCheckBase
.Add("FileExists", "false"))
.WithRemediation(r => r
.AddShellStep(1, "Export bundle", "stella verification bundle export --include-policy --output " + bundlePath)
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.policy.engine")
.Build());
}
@@ -103,7 +108,7 @@ public sealed class PolicyEngineCheck : VerificationCheckBase
"Policy evaluation not run before export")
.WithRemediation(r => r
.AddShellStep(1, "Re-export with policy", "stella verification bundle export --include-policy --output " + bundlePath)
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.policy.engine")
.Build());
}
@@ -161,7 +166,7 @@ public sealed class PolicyEngineCheck : VerificationCheckBase
.WithRemediation(r => r
.AddManualStep(1, "Enable policy engine", "Set Policy:Engine:Enabled to true")
.AddManualStep(2, "Configure default policy", "Set Policy:DefaultPolicyRef to a policy reference")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.policy.engine")
.Build());
}
@@ -180,7 +185,7 @@ public sealed class PolicyEngineCheck : VerificationCheckBase
.WithRemediation(r => r
.AddManualStep(1, "Configure test policy", "Set Doctor:Plugins:Verification:PolicyTest:PolicyRef")
.AddManualStep(2, "Or set default", "Set Policy:DefaultPolicyRef for a default policy")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.policy.engine")
.Build());
}
@@ -203,7 +208,7 @@ public sealed class PolicyEngineCheck : VerificationCheckBase
.WithRemediation(r => r
.AddManualStep(1, "Enable VEX in policy", "Set Policy:VexAware to true")
.AddManualStep(2, "Update policy rules", "Ensure policy considers VEX justifications for vulnerabilities")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.policy.engine")
.Build());
}

View File

@@ -13,6 +13,8 @@ namespace StellaOps.Doctor.Plugins.Verification.Checks;
/// </summary>
public sealed class SbomValidationCheck : VerificationCheckBase
{
private const string RunbookUrlValue = "docs/doctor/articles/verification/verification-sbom-validation.md";
/// <inheritdoc />
public override string CheckId => "check.verification.sbom.validation";
@@ -28,6 +30,9 @@ public sealed class SbomValidationCheck : VerificationCheckBase
/// <inheritdoc />
public override TimeSpan EstimatedDuration => TimeSpan.FromSeconds(10);
/// <inheritdoc />
protected override string RunbookUrl => RunbookUrlValue;
/// <inheritdoc />
public override bool CanRun(DoctorPluginContext context)
{
@@ -77,7 +82,7 @@ public sealed class SbomValidationCheck : VerificationCheckBase
.Add("FileExists", "false"))
.WithRemediation(r => r
.AddShellStep(1, "Export bundle", "stella verification bundle export --include-sbom --output " + bundlePath)
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.sbom.validation")
.Build());
}
@@ -103,7 +108,7 @@ public sealed class SbomValidationCheck : VerificationCheckBase
.WithRemediation(r => r
.AddShellStep(1, "Re-export with SBOM", "stella verification bundle export --include-sbom --output " + bundlePath)
.AddManualStep(2, "Generate SBOM", "Enable SBOM generation in your build pipeline")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.sbom.validation")
.Build());
}
@@ -160,7 +165,7 @@ public sealed class SbomValidationCheck : VerificationCheckBase
.WithRemediation(r => r
.AddManualStep(1, "Enable SBOM generation", "Set Scanner:SbomGeneration:Enabled to true")
.AddManualStep(2, "Enable SBOM attestation", "Set Attestor:SbomAttestation:Enabled to true")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.sbom.validation")
.Build());
}

View File

@@ -12,6 +12,8 @@ namespace StellaOps.Doctor.Plugins.Verification.Checks;
/// </summary>
public sealed class SignatureVerificationCheck : VerificationCheckBase
{
private const string RunbookUrlValue = "docs/doctor/articles/verification/verification-signature.md";
/// <inheritdoc />
public override string CheckId => "check.verification.signature";
@@ -27,6 +29,9 @@ public sealed class SignatureVerificationCheck : VerificationCheckBase
/// <inheritdoc />
public override TimeSpan EstimatedDuration => TimeSpan.FromSeconds(10);
/// <inheritdoc />
protected override string RunbookUrl => RunbookUrlValue;
/// <inheritdoc />
public override bool CanRun(DoctorPluginContext context)
{
@@ -76,7 +81,7 @@ public sealed class SignatureVerificationCheck : VerificationCheckBase
.Add("FileExists", "false"))
.WithRemediation(r => r
.AddShellStep(1, "Export bundle", "stella verification bundle export --output " + bundlePath)
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.signature")
.Build());
}
@@ -104,7 +109,7 @@ public sealed class SignatureVerificationCheck : VerificationCheckBase
.Add("Note", "Bundle should contain DSSE signatures for verification"))
.WithRemediation(r => r
.AddShellStep(1, "Re-export with signatures", "stella verification bundle export --include-signatures --output " + bundlePath)
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.signature")
.Build());
}
@@ -157,7 +162,7 @@ public sealed class SignatureVerificationCheck : VerificationCheckBase
.WithRemediation(r => r
.AddManualStep(1, "Enable Sigstore", "Set Sigstore:Enabled to true")
.AddManualStep(2, "Configure signing", "Set up signing keys or keyless mode")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.Build();
}
@@ -184,7 +189,7 @@ public sealed class SignatureVerificationCheck : VerificationCheckBase
.WithRemediation(r => r
.AddShellStep(1, "Test Rekor", $"curl -I {rekorHealthUrl}")
.AddManualStep(2, "Or use offline mode", "Configure offline verification bundle")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.signature")
.Build();
}
@@ -213,7 +218,7 @@ public sealed class SignatureVerificationCheck : VerificationCheckBase
.WithRemediation(r => r
.AddManualStep(1, "Check network", "Verify connectivity to Rekor")
.AddManualStep(2, "Use offline mode", "Configure offline verification bundle")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.signature")
.Build();
}

View File

@@ -12,6 +12,8 @@ namespace StellaOps.Doctor.Plugins.Verification.Checks;
/// </summary>
public sealed class TestArtifactPullCheck : VerificationCheckBase
{
private const string RunbookUrlValue = "docs/doctor/articles/verification/verification-artifact-pull.md";
/// <inheritdoc />
public override string CheckId => "check.verification.artifact.pull";
@@ -27,6 +29,9 @@ public sealed class TestArtifactPullCheck : VerificationCheckBase
/// <inheritdoc />
public override TimeSpan EstimatedDuration => TimeSpan.FromSeconds(15);
/// <inheritdoc />
protected override string RunbookUrl => RunbookUrlValue;
/// <inheritdoc />
public override bool CanRun(DoctorPluginContext context)
{
@@ -79,7 +84,7 @@ public sealed class TestArtifactPullCheck : VerificationCheckBase
.WithRemediation(r => r
.AddShellStep(1, "Verify file exists", $"ls -la {bundlePath}")
.AddShellStep(2, "Export bundle from online system", "stella verification bundle export --output " + bundlePath)
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.artifact.pull")
.Build());
}
@@ -115,7 +120,7 @@ public sealed class TestArtifactPullCheck : VerificationCheckBase
.WithCauses("Reference format is incorrect")
.WithRemediation(r => r
.AddManualStep(1, "Fix reference format", "Use format: oci://registry/repository@sha256:digest or registry/repository@sha256:digest")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.artifact.pull")
.Build();
}
@@ -154,7 +159,7 @@ public sealed class TestArtifactPullCheck : VerificationCheckBase
.AddShellStep(1, "Test with crane", $"crane manifest {reference}")
.AddManualStep(2, "Check registry credentials", "Ensure registry credentials are configured")
.AddManualStep(3, "Verify artifact exists", "Confirm the test artifact has been pushed to the registry")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.artifact.pull")
.Build();
}
@@ -182,7 +187,7 @@ public sealed class TestArtifactPullCheck : VerificationCheckBase
.WithRemediation(r => r
.AddManualStep(1, "Update expected digest", $"Set Doctor:Plugins:Verification:TestArtifact:ExpectedDigest to {responseDigest}")
.AddManualStep(2, "Or use digest in reference", "Use @sha256:... in the reference instead of :tag")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.artifact.pull")
.Build();
}
@@ -213,7 +218,7 @@ public sealed class TestArtifactPullCheck : VerificationCheckBase
.WithRemediation(r => r
.AddShellStep(1, "Test registry connectivity", $"curl -I https://{registry}/v2/")
.AddManualStep(2, "Check network configuration", "Ensure HTTPS traffic to the registry is allowed")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.artifact.pull")
.Build();
}

View File

@@ -35,6 +35,11 @@ public abstract class VerificationCheckBase : IDoctorCheck
/// <inheritdoc />
public abstract IReadOnlyList<string> Tags { get; }
/// <summary>
/// Gets the runbook URL for the concrete check.
/// </summary>
protected abstract string RunbookUrl { get; }
/// <inheritdoc />
public virtual TimeSpan EstimatedDuration => TimeSpan.FromSeconds(10);
@@ -78,7 +83,8 @@ public abstract class VerificationCheckBase : IDoctorCheck
"Authentication failure")
.WithRemediation(r => r
.AddManualStep(1, "Check network connectivity", "Verify the endpoint is reachable")
.AddManualStep(2, "Check credentials", "Verify authentication is configured correctly"))
.AddManualStep(2, "Check credentials", "Verify authentication is configured correctly")
.WithRunbookUrl(RunbookUrl))
.WithVerification($"stella doctor --check {CheckId}")
.Build();
}
@@ -94,7 +100,8 @@ public abstract class VerificationCheckBase : IDoctorCheck
"Network latency is high",
"Large artifact size")
.WithRemediation(r => r
.AddManualStep(1, "Increase timeout", "Set Doctor:Plugins:Verification:HttpTimeoutSeconds to a higher value"))
.AddManualStep(1, "Increase timeout", "Set Doctor__Plugins__Verification__HttpTimeoutSeconds to a higher value")
.WithRunbookUrl(RunbookUrl))
.WithVerification($"stella doctor --check {CheckId}")
.Build();
}
@@ -141,7 +148,7 @@ public abstract class VerificationCheckBase : IDoctorCheck
/// <summary>
/// Gets a skip result for when test artifact is not configured.
/// </summary>
protected static DoctorCheckResult GetNoTestArtifactConfiguredResult(CheckResultBuilder result, string checkId)
protected DoctorCheckResult GetNoTestArtifactConfiguredResult(CheckResultBuilder result, string checkId)
{
return result
.Skip("Test artifact not configured")
@@ -150,8 +157,9 @@ public abstract class VerificationCheckBase : IDoctorCheck
.Add("OfflineBundlePath", "(not set)")
.Add("Note", "Configure a test artifact to enable verification pipeline checks"))
.WithRemediation(r => r
.AddManualStep(1, "Configure test artifact", "Set Doctor:Plugins:Verification:TestArtifact:Reference to an OCI reference")
.AddManualStep(2, "Or use offline bundle", "Set Doctor:Plugins:Verification:TestArtifact:OfflineBundlePath for air-gap environments"))
.AddManualStep(1, "Configure test artifact", "Set Doctor__Plugins__Verification__TestArtifact__Reference to an OCI reference")
.AddManualStep(2, "Or use offline bundle", "Set Doctor__Plugins__Verification__TestArtifact__OfflineBundlePath for air-gap environments")
.WithRunbookUrl(RunbookUrl))
.Build();
}
}

View File

@@ -13,6 +13,8 @@ namespace StellaOps.Doctor.Plugins.Verification.Checks;
/// </summary>
public sealed class VexValidationCheck : VerificationCheckBase
{
private const string RunbookUrlValue = "docs/doctor/articles/verification/verification-vex-validation.md";
/// <inheritdoc />
public override string CheckId => "check.verification.vex.validation";
@@ -28,6 +30,9 @@ public sealed class VexValidationCheck : VerificationCheckBase
/// <inheritdoc />
public override TimeSpan EstimatedDuration => TimeSpan.FromSeconds(10);
/// <inheritdoc />
protected override string RunbookUrl => RunbookUrlValue;
/// <inheritdoc />
public override bool CanRun(DoctorPluginContext context)
{
@@ -77,7 +82,7 @@ public sealed class VexValidationCheck : VerificationCheckBase
.Add("FileExists", "false"))
.WithRemediation(r => r
.AddShellStep(1, "Export bundle", "stella verification bundle export --include-vex --output " + bundlePath)
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.vex.validation")
.Build());
}
@@ -105,7 +110,7 @@ public sealed class VexValidationCheck : VerificationCheckBase
.WithRemediation(r => r
.AddShellStep(1, "Re-export with VEX", "stella verification bundle export --include-vex --output " + bundlePath)
.AddManualStep(2, "This may be expected", "VEX documents are only needed when vulnerabilities exist")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.vex.validation")
.Build());
}
@@ -157,7 +162,7 @@ public sealed class VexValidationCheck : VerificationCheckBase
.WithRemediation(r => r
.AddManualStep(1, "Enable VEX collection", "Set VexHub:Collection:Enabled to true")
.AddManualStep(2, "Configure VEX feeds", "Add vendor VEX feeds to VexHub:Feeds")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.Build());
}
@@ -174,7 +179,7 @@ public sealed class VexValidationCheck : VerificationCheckBase
.WithCauses("No VEX feed URLs configured")
.WithRemediation(r => r
.AddManualStep(1, "Configure VEX feeds", "Add vendor VEX feeds to VexHub:Feeds array")
.WithRunbookUrl(""))
.WithRunbookUrl(RunbookUrlValue))
.WithVerification($"stella doctor --check check.verification.vex.validation")
.Build());
}