using SQLInsight.Core.Collection; using SQLInsight.Core.CustomRules; using SQLInsight.Core.Findings; using SQLInsight.Core.Instances; using SQLInsight.Rules.Engine; namespace SQLInsight.Rules.Custom; /// A rule defined as data (): every row its query returns is a finding. public sealed class DeclarativeRule(CustomRuleDefinition definition) : IRule { public CustomRuleDefinition Definition { get; } = definition ?? throw new ArgumentNullException(nameof(definition)); public string Id => Definition.Id; public string Title => Definition.Title; public IReadOnlyCollection RequiredCapabilities => []; public RuleEvaluation Evaluate(RuleContext context) { ArgumentNullException.ThrowIfNull(context); if (context.Instance.Version < Definition.MinimumSqlVersion) { return RuleEvaluation.NotApplicable($"Ikke relevant for {context.Instance.Release.DisplayName()}: reglen kræver SQL Server {Definition.MinimumVersion} eller nyere."); } var results = context.Data.Get(); if (!results.Results.TryGetValue(Definition.Id, out var result)) { throw new DataUnavailableException("Reglens forespørgsel er ikke kørt endnu."); } if (result.NotRelevant is { } notRelevant) { return RuleEvaluation.NotApplicable(notRelevant); } if (result.Error is { } error) { if (result.PermissionDenied) { return RuleEvaluation.NotMeasurable("Agentens login mangler rettigheder til reglens forespørgsel: " + error); } throw new InvalidOperationException("Reglens forespørgsel fejlede: " + error); } if (result.Rows.Count == 0) { return RuleEvaluation.Passed(); } var references = Definition.References.Select(r => new Reference(r.Title, r.Url)).ToArray(); var findings = result.Rows.Select(row => new Finding { RuleId = Definition.Id, Severity = Definition.Severity, Title = CustomRuleDefinition.Fill(Definition.FindingTitle, row), Subject = Definition.Subject is { } subject ? CustomRuleDefinition.Fill(subject, row) : row.Values.FirstOrDefault(), Explanation = CustomRuleDefinition.Fill(Definition.Explanation, row) + (Definition.Origin == "community" ? " (Community-regel" + (Definition.Author is { } a ? $" af {a}" : "") + ".)" : " (Lokal regel.)"), Recommendation = CustomRuleDefinition.Fill(Definition.Recommendation, row), Evidence = row .Where(c => Definition.Evidence is null || Definition.Evidence.Contains(c.Key, StringComparer.OrdinalIgnoreCase)) .Select(c => new Evidence(c.Key, c.Value ?? "(null)", Definition.SensitiveColumns.Contains(c.Key, StringComparer.OrdinalIgnoreCase))) .Concat(result.Truncated ? [new Evidence("Bemærk", $"Kun de første {CustomRuleDefinition.MaxRowsPerRule} rækker er medtaget.")] : []) .ToList(), References = references, }).ToArray(); return RuleEvaluation.Found(findings); } }