using System.ComponentModel.DataAnnotations; using StellaOps.AdvisoryAI.Remediation; namespace StellaOps.AdvisoryAI.WebService.Contracts; /// /// API request for generating a remediation plan. /// Sprint: SPRINT_20251226_016_AI_remedy_autopilot /// Task: REMEDY-19 /// public sealed record RemediationPlanApiRequest { [Required] public required string FindingId { get; init; } [Required] public required string ArtifactDigest { get; init; } [Required] public required string VulnerabilityId { get; init; } [Required] public required string ComponentPurl { get; init; } public string RemediationType { get; init; } = "auto"; public string? RepositoryUrl { get; init; } public string TargetBranch { get; init; } = "main"; public bool AutoCreatePr { get; init; } public string? CorrelationId { get; init; } public RemediationPlanRequest ToDomain() { if (!Enum.TryParse(RemediationType, ignoreCase: true, out var type)) { type = Remediation.RemediationType.Auto; } return new RemediationPlanRequest { FindingId = FindingId, ArtifactDigest = ArtifactDigest, VulnerabilityId = VulnerabilityId, ComponentPurl = ComponentPurl, RemediationType = type, RepositoryUrl = RepositoryUrl, TargetBranch = TargetBranch, AutoCreatePr = AutoCreatePr, CorrelationId = CorrelationId }; } } /// /// API response for remediation plan. /// public sealed record RemediationPlanApiResponse { public required string PlanId { get; init; } public required IReadOnlyList Steps { get; init; } public required ExpectedDeltaResponse ExpectedDelta { get; init; } public required string RiskAssessment { get; init; } public required string Authority { get; init; } public required bool PrReady { get; init; } public string? NotReadyReason { get; init; } public required double ConfidenceScore { get; init; } public required string ModelId { get; init; } public required string GeneratedAt { get; init; } public static RemediationPlanApiResponse FromDomain(RemediationPlan plan) { return new RemediationPlanApiResponse { PlanId = plan.PlanId, Steps = plan.Steps.Select(s => new RemediationStepResponse { Order = s.Order, ActionType = s.ActionType, FilePath = s.FilePath, Description = s.Description, PreviousValue = s.PreviousValue, NewValue = s.NewValue, Optional = s.Optional, Risk = s.Risk.ToString() }).ToList(), ExpectedDelta = new ExpectedDeltaResponse { Added = plan.ExpectedDelta.Added, Removed = plan.ExpectedDelta.Removed, Upgraded = plan.ExpectedDelta.Upgraded, NetVulnerabilityChange = plan.ExpectedDelta.NetVulnerabilityChange }, RiskAssessment = plan.RiskAssessment.ToString(), Authority = plan.Authority.ToString(), PrReady = plan.PrReady, NotReadyReason = plan.NotReadyReason, ConfidenceScore = plan.ConfidenceScore, ModelId = plan.ModelId, GeneratedAt = plan.GeneratedAt }; } } public sealed record RemediationStepResponse { public required int Order { get; init; } public required string ActionType { get; init; } public required string FilePath { get; init; } public required string Description { get; init; } public string? PreviousValue { get; init; } public string? NewValue { get; init; } public bool Optional { get; init; } public required string Risk { get; init; } } public sealed record ExpectedDeltaResponse { public required IReadOnlyList Added { get; init; } public required IReadOnlyList Removed { get; init; } public required IReadOnlyDictionary Upgraded { get; init; } public required int NetVulnerabilityChange { get; init; } } /// /// API request for applying remediation (creating PR). /// Task: REMEDY-20 /// public sealed record ApplyRemediationRequest { [Required] public required string PlanId { get; init; } public string ScmType { get; init; } = "github"; } /// /// API response for PR creation. /// public sealed record PullRequestApiResponse { public required string PrId { get; init; } public required int PrNumber { get; init; } public required string Url { get; init; } public required string BranchName { get; init; } public required string Status { get; init; } public string? StatusMessage { get; init; } public BuildResultResponse? BuildResult { get; init; } public TestResultResponse? TestResult { get; init; } public DeltaVerdictResponse? DeltaVerdict { get; init; } public required string CreatedAt { get; init; } public required string UpdatedAt { get; init; } public static PullRequestApiResponse FromDomain(PullRequestResult result) { return new PullRequestApiResponse { PrId = result.PrId, PrNumber = result.PrNumber, Url = result.Url, BranchName = result.BranchName, Status = result.Status.ToString(), StatusMessage = result.StatusMessage, BuildResult = result.BuildResult != null ? new BuildResultResponse { Success = result.BuildResult.Success, BuildId = result.BuildResult.BuildId, BuildUrl = result.BuildResult.BuildUrl, ErrorMessage = result.BuildResult.ErrorMessage, CompletedAt = result.BuildResult.CompletedAt } : null, TestResult = result.TestResult != null ? new TestResultResponse { AllPassed = result.TestResult.AllPassed, TotalTests = result.TestResult.TotalTests, PassedTests = result.TestResult.PassedTests, FailedTests = result.TestResult.FailedTests, SkippedTests = result.TestResult.SkippedTests, Coverage = result.TestResult.Coverage, FailedTestNames = result.TestResult.FailedTestNames, CompletedAt = result.TestResult.CompletedAt } : null, DeltaVerdict = result.DeltaVerdict != null ? new DeltaVerdictResponse { Improved = result.DeltaVerdict.Improved, VulnerabilitiesFixed = result.DeltaVerdict.VulnerabilitiesFixed, VulnerabilitiesIntroduced = result.DeltaVerdict.VulnerabilitiesIntroduced, VerdictId = result.DeltaVerdict.VerdictId, SignatureId = result.DeltaVerdict.SignatureId, ComputedAt = result.DeltaVerdict.ComputedAt } : null, CreatedAt = result.CreatedAt, UpdatedAt = result.UpdatedAt }; } } public sealed record BuildResultResponse { public required bool Success { get; init; } public required string BuildId { get; init; } public string? BuildUrl { get; init; } public string? ErrorMessage { get; init; } public required string CompletedAt { get; init; } } public sealed record TestResultResponse { public required bool AllPassed { get; init; } public required int TotalTests { get; init; } public required int PassedTests { get; init; } public required int FailedTests { get; init; } public required int SkippedTests { get; init; } public double Coverage { get; init; } public IReadOnlyList FailedTestNames { get; init; } = Array.Empty(); public required string CompletedAt { get; init; } } public sealed record DeltaVerdictResponse { public required bool Improved { get; init; } public required int VulnerabilitiesFixed { get; init; } public required int VulnerabilitiesIntroduced { get; init; } public required string VerdictId { get; init; } public string? SignatureId { get; init; } public required string ComputedAt { get; init; } }