Gaps fill up, fixes, ui restructuring
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
namespace StellaOps.Remediation.Core.Abstractions;
|
||||
|
||||
public interface IContributorTrustScorer
|
||||
{
|
||||
double CalculateTrustScore(int verifiedFixes, int totalSubmissions, int rejectedSubmissions);
|
||||
string GetTrustTier(double score);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using StellaOps.Remediation.Core.Models;
|
||||
|
||||
namespace StellaOps.Remediation.Core.Abstractions;
|
||||
|
||||
public interface IRemediationMatcher
|
||||
{
|
||||
Task<IReadOnlyList<FixTemplate>> FindMatchesAsync(string cveId, string? purl = null, string? version = null, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using StellaOps.Remediation.Core.Models;
|
||||
|
||||
namespace StellaOps.Remediation.Core.Abstractions;
|
||||
|
||||
public interface IRemediationRegistry
|
||||
{
|
||||
Task<IReadOnlyList<FixTemplate>> ListTemplatesAsync(string? cveId = null, string? purl = null, int limit = 50, int offset = 0, CancellationToken ct = default);
|
||||
Task<FixTemplate?> GetTemplateAsync(Guid id, CancellationToken ct = default);
|
||||
Task<FixTemplate> CreateTemplateAsync(FixTemplate template, CancellationToken ct = default);
|
||||
Task<IReadOnlyList<PrSubmission>> ListSubmissionsAsync(string? cveId = null, string? status = null, int limit = 50, int offset = 0, CancellationToken ct = default);
|
||||
Task<PrSubmission?> GetSubmissionAsync(Guid id, CancellationToken ct = default);
|
||||
Task<PrSubmission> CreateSubmissionAsync(PrSubmission submission, CancellationToken ct = default);
|
||||
Task UpdateSubmissionStatusAsync(Guid id, string status, string? verdict = null, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace StellaOps.Remediation.Core.Models;
|
||||
|
||||
public sealed record Contributor
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public string Username { get; init; } = string.Empty;
|
||||
public string? DisplayName { get; init; }
|
||||
public int VerifiedFixes { get; init; }
|
||||
public int TotalSubmissions { get; init; }
|
||||
public int RejectedSubmissions { get; init; }
|
||||
public double TrustScore { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public DateTimeOffset? LastActiveAt { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace StellaOps.Remediation.Core.Models;
|
||||
|
||||
public sealed record FixTemplate
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public string CveId { get; init; } = string.Empty;
|
||||
public string Purl { get; init; } = string.Empty;
|
||||
public string VersionRange { get; init; } = string.Empty;
|
||||
public string PatchContent { get; init; } = string.Empty;
|
||||
public string? Description { get; init; }
|
||||
public Guid? ContributorId { get; init; }
|
||||
public Guid? SourceId { get; init; }
|
||||
public string Status { get; init; } = "pending";
|
||||
public double TrustScore { get; init; }
|
||||
public string? DsseDigest { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public DateTimeOffset? VerifiedAt { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace StellaOps.Remediation.Core.Models;
|
||||
|
||||
public sealed record MarketplaceSource
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public string Key { get; init; } = string.Empty;
|
||||
public string Name { get; init; } = string.Empty;
|
||||
public string? Url { get; init; }
|
||||
public string SourceType { get; init; } = "community";
|
||||
public bool Enabled { get; init; } = true;
|
||||
public double TrustScore { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public DateTimeOffset? LastSyncAt { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace StellaOps.Remediation.Core.Models;
|
||||
|
||||
public sealed record PrSubmission
|
||||
{
|
||||
public Guid Id { get; init; }
|
||||
public Guid? FixTemplateId { get; init; }
|
||||
public string PrUrl { get; init; } = string.Empty;
|
||||
public string RepositoryUrl { get; init; } = string.Empty;
|
||||
public string SourceBranch { get; init; } = string.Empty;
|
||||
public string TargetBranch { get; init; } = string.Empty;
|
||||
public string CveId { get; init; } = string.Empty;
|
||||
public string Status { get; init; } = "opened";
|
||||
public string? PreScanDigest { get; init; }
|
||||
public string? PostScanDigest { get; init; }
|
||||
public string? ReachabilityDeltaDigest { get; init; }
|
||||
public string? FixChainDsseDigest { get; init; }
|
||||
public string? Verdict { get; init; }
|
||||
public Guid? ContributorId { get; init; }
|
||||
public DateTimeOffset CreatedAt { get; init; }
|
||||
public DateTimeOffset? MergedAt { get; init; }
|
||||
public DateTimeOffset? VerifiedAt { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using StellaOps.Remediation.Core.Abstractions;
|
||||
|
||||
namespace StellaOps.Remediation.Core.Services;
|
||||
|
||||
public sealed class ContributorTrustScorer : IContributorTrustScorer
|
||||
{
|
||||
public double CalculateTrustScore(int verifiedFixes, int totalSubmissions, int rejectedSubmissions)
|
||||
{
|
||||
var denominator = Math.Max(totalSubmissions, 1);
|
||||
var raw = (verifiedFixes * 1.0 - rejectedSubmissions * 0.5) / denominator;
|
||||
return Math.Clamp(raw, 0.0, 1.0);
|
||||
}
|
||||
|
||||
public string GetTrustTier(double score) => score switch
|
||||
{
|
||||
> 0.8 => "trusted",
|
||||
> 0.5 => "established",
|
||||
> 0.2 => "new",
|
||||
_ => "untrusted"
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using StellaOps.Remediation.Core.Models;
|
||||
|
||||
namespace StellaOps.Remediation.Core.Services;
|
||||
|
||||
public interface IRemediationVerifier
|
||||
{
|
||||
Task<VerificationResult> VerifyAsync(PrSubmission submission, CancellationToken ct = default);
|
||||
}
|
||||
|
||||
public sealed record VerificationResult(
|
||||
string Verdict,
|
||||
string? ReachabilityDeltaDigest,
|
||||
string? FixChainDsseDigest,
|
||||
IReadOnlyList<string> AffectedPaths,
|
||||
DateTimeOffset VerifiedAt);
|
||||
@@ -0,0 +1,42 @@
|
||||
using StellaOps.Remediation.Core.Models;
|
||||
|
||||
namespace StellaOps.Remediation.Core.Services;
|
||||
|
||||
public sealed class RemediationVerifier : IRemediationVerifier
|
||||
{
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public RemediationVerifier(TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public Task<VerificationResult> VerifyAsync(PrSubmission submission, CancellationToken ct = default)
|
||||
{
|
||||
// Stub: real implementation will integrate with scan service and reachability delta
|
||||
var verdict = DetermineVerdict(submission);
|
||||
var result = new VerificationResult(
|
||||
Verdict: verdict,
|
||||
ReachabilityDeltaDigest: submission.ReachabilityDeltaDigest,
|
||||
FixChainDsseDigest: submission.FixChainDsseDigest,
|
||||
AffectedPaths: Array.Empty<string>(),
|
||||
VerifiedAt: _timeProvider.GetUtcNow());
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
private static string DetermineVerdict(PrSubmission submission)
|
||||
{
|
||||
if (string.IsNullOrEmpty(submission.PreScanDigest) || string.IsNullOrEmpty(submission.PostScanDigest))
|
||||
{
|
||||
return "inconclusive";
|
||||
}
|
||||
|
||||
if (submission.PreScanDigest == submission.PostScanDigest)
|
||||
{
|
||||
return "not_fixed";
|
||||
}
|
||||
|
||||
return "fixed";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user