audit, advisories and doctors/setup work

This commit is contained in:
master
2026-01-13 18:53:39 +02:00
parent 9ca7cb183e
commit d7be6ba34b
811 changed files with 54242 additions and 4056 deletions

48
src/Doctor/AGENTS.md Normal file
View File

@@ -0,0 +1,48 @@
# AGENTS - StellaOps Doctor
## Roles
- Backend engineer: Doctor engine, pack loader, checks, and evidence output.
- QA engineer: unit/integration tests for Doctor engine and web service.
- Docs/PM: keep sprint status in `docs/implplan/SPRINT_*` aligned and update Doctor docs.
## Working directory
- Primary: `src/Doctor/**` (web service, plugins, tests).
- Allowed shared libraries:
- `src/__Libraries/StellaOps.Doctor/**`
- `src/__Libraries/StellaOps.Doctor.Plugins.*/**`
- `src/__Libraries/__Tests/StellaOps.Doctor.*.Tests/**`
- Do not edit other modules unless the sprint explicitly allows cross-module edits.
## Required reading (treat as read before DOING)
- `docs/README.md`
- `docs/technical/architecture/07_HIGH_LEVEL_ARCHITECTURE.md`
- `docs/modules/platform/architecture-overview.md`
- `docs/doctor/doctor-capabilities.md`
- `docs/doctor/cli-reference.md`
- `docs/doctor/README.md`
- Sprint file under `docs/implplan/`
## Coding standards
- Target .NET 10 with preview features as configured.
- Determinism: stable ordering, UTC timestamps, invariant culture, fixed JSON options.
- Never call `DateTime.UtcNow`, `Guid.NewGuid()`, or `Random.Shared` directly; use injected providers.
- DSSE PAE and JSON canonicalization must use shared helpers; do not reimplement.
- Remediation commands must be non-destructive; destructive steps are manual guidance only.
## Evidence and remediation
- Every check emits evidence and `how_to_fix` alias for agent/CLI/UI consumption.
- Evidence logs are JSONL with deterministic ordering and include `doctor_command`.
- DSSE summaries assume operator execution and include the same command note.
## Testing
- Doctor engine tests: `src/__Libraries/__Tests/StellaOps.Doctor.Tests`
- Plugin tests: `src/__Libraries/__Tests/StellaOps.Doctor.Plugins.*.Tests`
- Web service tests: `src/Doctor/__Tests/StellaOps.Doctor.WebService.Tests`
- Tests must be offline-safe and deterministic (no network access, fixed inputs).
## Sprint/status discipline
- Mirror task state in the relevant `SPRINT_*` doc (TODO -> DOING -> DONE/BLOCKED).
- If a decision is needed, mark the task BLOCKED in the sprint and continue with other tasks.
## Contacts/ownership
- Module owner: Doctor Guild

View File

@@ -45,6 +45,7 @@ public sealed class DoctorRunService
public Task<string> StartRunAsync(RunDoctorRequest request, CancellationToken ct)
{
var runMode = Enum.Parse<DoctorRunMode>(request.Mode, ignoreCase: true);
var runId = GenerateRunId();
var options = new DoctorRunOptions
{
Mode = runMode,
@@ -54,10 +55,11 @@ public sealed class DoctorRunService
Timeout = TimeSpan.FromMilliseconds(request.TimeoutMs),
Parallelism = request.Parallelism,
IncludeRemediation = request.IncludeRemediation,
TenantId = request.TenantId
TenantId = request.TenantId,
RunId = runId,
DoctorCommand = "POST /api/v1/doctor/run"
};
var runId = GenerateRunId();
var state = new DoctorRunState
{
RunId = runId,

View File

@@ -84,7 +84,7 @@ public sealed class LogRotationCheck : IDoctorCheck
CommandType.Shell)
.AddStep(2, "Adjust rotation threshold",
"Edit Logging:RollingPolicy in configuration",
CommandType.Config))
CommandType.FileEdit))
.Build());
}
@@ -115,7 +115,7 @@ public sealed class LogRotationCheck : IDoctorCheck
.WithRemediation(rb => rb
.AddStep(1, "Enable application-level log rotation",
"Set Logging:RollingPolicy to 'Size' or 'Date' in appsettings.json",
CommandType.Config)
CommandType.FileEdit)
.AddStep(2, "Or configure system-level rotation",
RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? "Use Windows Event Log or configure log cleanup task"
@@ -179,3 +179,4 @@ public sealed class LogRotationCheck : IDoctorCheck
return "/var/log/stellaops";
}
}

View File

@@ -83,7 +83,7 @@ public sealed class PrometheusScrapeCheck : IDoctorCheck
.WithRemediation(rb => rb
.AddStep(1, "Enable metrics endpoint",
"Set Metrics:Enabled=true in appsettings.json",
CommandType.Config)
CommandType.FileEdit)
.AddStep(2, "Verify metrics configuration",
"stella config get Metrics",
CommandType.Shell))
@@ -133,3 +133,4 @@ public sealed class PrometheusScrapeCheck : IDoctorCheck
.Count(line => !line.StartsWith('#') && line.Contains(' '));
}
}

View File

@@ -10,18 +10,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Moq" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="coverlet.collector">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>

View File

@@ -4,11 +4,14 @@
using System.Collections.Immutable;
using FluentAssertions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
using StellaOps.Doctor.Engine;
using StellaOps.Doctor.Models;
using StellaOps.Doctor.Output;
using StellaOps.Doctor.Packs;
using StellaOps.Doctor.Plugins;
using StellaOps.Doctor.WebService.Contracts;
using StellaOps.Doctor.WebService.Options;
@@ -36,18 +39,34 @@ public sealed class DoctorRunServiceTests
private static DoctorEngine CreateMockEngine()
{
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Doctor:Evidence:Enabled"] = "false"
})
.Build();
var packLoader = new DoctorPackLoader(
new Mock<IDoctorPackCommandRunner>().Object,
NullLogger<DoctorPackLoader>.Instance);
var registry = new CheckRegistry(
Enumerable.Empty<IDoctorPlugin>(),
packLoader,
NullLogger<CheckRegistry>.Instance);
var executor = new CheckExecutor(NullLogger<CheckExecutor>.Instance, TimeProvider.System);
var evidenceWriter = new DoctorEvidenceLogWriter(
configuration,
NullLogger<DoctorEvidenceLogWriter>.Instance);
return new DoctorEngine(
registry,
executor,
new Mock<IServiceProvider>().Object,
new Mock<Microsoft.Extensions.Configuration.IConfiguration>().Object,
configuration,
TimeProvider.System,
evidenceWriter,
NullLogger<DoctorEngine>.Instance);
}
@@ -105,8 +124,7 @@ public sealed class DoctorRunServiceTests
var result = await service.GetRunResultAsync(runId, CancellationToken.None);
result.Should().NotBeNull();
// Note: RunId may differ between running/completed states due to engine having its own runId
result!.RunId.Should().StartWith("dr_");
result!.RunId.Should().Be(runId);
result.Status.Should().BeOneOf("running", "completed");
}