forked from J0113/SCA_Scanner
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCsvReporter.cs
More file actions
106 lines (89 loc) · 3.91 KB
/
Copy pathCsvReporter.cs
File metadata and controls
106 lines (89 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
namespace SCAScanner;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
/// <summary>
/// Writes scan results as a CSV file. One row per check result.
/// Implements only <see cref="IPolicyReporter"/> and <see cref="ICheckReporter"/> —
/// all other output is irrelevant for CSV export.
/// </summary>
public sealed class CsvReporter : IPolicyReporter, ICheckReporter, IDisposable
{
private static readonly string[] Headers =
[
"Computer_Name", "Operating_System", "Standard", "Version",
"Last_Scan_Date", "Description", "Fix_Text", "Rule", "Rule_ID", "Status"
];
private readonly string _filePath;
private readonly string _computerName;
private readonly string _operatingSystem;
private readonly string _scanDate;
private string _standard = string.Empty;
private string _version = string.Empty;
private readonly List<string[]> _rows = new();
public CsvReporter(string filePath)
{
_filePath = filePath;
_computerName = TryGetFqdn();
_operatingSystem = RuntimeInformation.OSDescription;
_scanDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
// ── IPolicyReporter ───────────────────────────────────────────────────
public void PrintBanner() { }
public void PrintHelp() { }
public void PrintPolicyHeader(SCAPolicy policy, string platform)
{
_standard = policy.Policy.Name;
_version = policy.Policy.Id;
}
public void PrintRequirementsSection(Check requirementsCheck, PolicyVariables? variables, CheckResult requirementsResult) { }
// ── ICheckReporter ────────────────────────────────────────────────────
public void PrintCheckHeader(Check check) { }
public void PrintRuleExplanations(List<ParsedRule> parsedRules, Check check, PolicyVariables? variables) { }
public void PrintRuleResults(IReadOnlyList<RuleResult> ruleResults) { }
public void PrintCheckResult(Check check, CheckResult result, int totalPassed, int totalFailed)
{
_rows.Add(
[
_computerName,
_operatingSystem,
_standard,
_version,
_scanDate,
check.Description,
check.Remediation,
check.Title,
check.Id.ToString(),
result.Status.ToString()
]);
}
// ── IDisposable ───────────────────────────────────────────────────────
public void Dispose()
{
var sb = new StringBuilder();
sb.AppendLine(string.Join(",", Headers.Select(Escape)));
foreach (var row in _rows)
sb.AppendLine(string.Join(",", row.Select(Escape)));
try
{
File.WriteAllText(_filePath, sb.ToString(), Encoding.UTF8);
}
catch (Exception ex)
{
Console.Error.WriteLine($"CsvReporter: failed to write '{_filePath}': {ex.Message}");
}
}
// ── Helpers ───────────────────────────────────────────────────────────
/// <summary>RFC 4180 CSV escaping: wrap in quotes if value contains comma, quote, or newline.</summary>
private static string Escape(string value)
{
if (value.Contains(',') || value.Contains('"') || value.Contains('\n') || value.Contains('\r'))
return $"\"{value.Replace("\"", "\"\"")}\"";
return value;
}
private static string TryGetFqdn()
{
try { return Dns.GetHostEntry("").HostName; }
catch (Exception) { return Environment.MachineName; }
}
}