audit, advisories and doctors/setup work
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
// <copyright file="NullRemediationPlanner.cs" company="StellaOps">
|
||||
// Copyright (c) StellaOps. Licensed under the AGPL-3.0-or-later.
|
||||
// </copyright>
|
||||
using System.Collections.Concurrent;
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace StellaOps.AdvisoryAI.Remediation;
|
||||
|
||||
/// <summary>
|
||||
/// Deterministic stub planner used when remediation services are not configured.
|
||||
/// </summary>
|
||||
public sealed class NullRemediationPlanner : IRemediationPlanner
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, RemediationPlan> _plans = new(StringComparer.Ordinal);
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public NullRemediationPlanner(TimeProvider timeProvider)
|
||||
{
|
||||
_timeProvider = timeProvider ?? throw new ArgumentNullException(nameof(timeProvider));
|
||||
}
|
||||
|
||||
public Task<RemediationPlan> GeneratePlanAsync(
|
||||
RemediationPlanRequest request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
var inputHash = ComputeHash(JsonSerializer.Serialize(request));
|
||||
var planId = $"plan:stub:{inputHash[..12]}";
|
||||
|
||||
var plan = new RemediationPlan
|
||||
{
|
||||
PlanId = planId,
|
||||
Request = request,
|
||||
Steps =
|
||||
[
|
||||
new RemediationStep
|
||||
{
|
||||
Order = 1,
|
||||
ActionType = "review_remediation",
|
||||
FilePath = "N/A",
|
||||
Description = "Remediation planner is not configured.",
|
||||
Risk = RemediationRisk.Unknown
|
||||
}
|
||||
],
|
||||
ExpectedDelta = new ExpectedSbomDelta
|
||||
{
|
||||
Added = Array.Empty<string>(),
|
||||
Removed = Array.Empty<string>(),
|
||||
Upgraded = new Dictionary<string, string>(),
|
||||
NetVulnerabilityChange = 0
|
||||
},
|
||||
RiskAssessment = RemediationRisk.Unknown,
|
||||
TestRequirements = new RemediationTestRequirements
|
||||
{
|
||||
TestSuites = Array.Empty<string>(),
|
||||
MinCoverage = 0,
|
||||
RequireAllPass = false,
|
||||
Timeout = TimeSpan.Zero
|
||||
},
|
||||
Authority = RemediationAuthority.Suggestion,
|
||||
PrReady = false,
|
||||
NotReadyReason = "Remediation planner is not configured.",
|
||||
ConfidenceScore = 0.0,
|
||||
ModelId = "stub-remediation:v0",
|
||||
GeneratedAt = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture),
|
||||
InputHashes = new[] { inputHash },
|
||||
EvidenceRefs = new[] { request.ComponentPurl, request.VulnerabilityId }
|
||||
};
|
||||
|
||||
_plans[planId] = plan;
|
||||
return Task.FromResult(plan);
|
||||
}
|
||||
|
||||
public Task<bool> ValidatePlanAsync(
|
||||
string planId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(planId);
|
||||
return Task.FromResult(_plans.ContainsKey(planId));
|
||||
}
|
||||
|
||||
public Task<RemediationPlan?> GetPlanAsync(
|
||||
string planId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(planId);
|
||||
_plans.TryGetValue(planId, out var plan);
|
||||
return Task.FromResult(plan);
|
||||
}
|
||||
|
||||
private static string ComputeHash(string content)
|
||||
{
|
||||
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(content));
|
||||
return Convert.ToHexStringLower(bytes);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user