114 lines
4.0 KiB
C#
114 lines
4.0 KiB
C#
namespace OCSentinelCli;
|
|
|
|
internal sealed record ScanOptions
|
|
{
|
|
public const string Usage = """
|
|
Usage:
|
|
OCSentinelCli [--output <path>] [--lookback-days <n>] [--top <n>] [--config <path>] [--vulnerability-csv <path>] [--json-only] [--ninja-output] [--fail-on-attacks] [--fail-on-threshold] [--help]
|
|
|
|
Options:
|
|
--output <path> Write the JSON report to the given file.
|
|
--lookback-days <n> Only include events newer than now minus n days. Default: 30
|
|
--top <n> Number of aggregated source IPs to show. Default: 10
|
|
--config <path> Load thresholds, path overrides, and exclusions from JSON.
|
|
--vulnerability-csv <path>
|
|
Correlate local attack results with exported CVE data for this host.
|
|
--json-only Print only JSON to stdout.
|
|
--ninja-output Print extra key=value lines for RMM/Ninja-style parsing.
|
|
--fail-on-attacks Return exit code 1 when attacks are found.
|
|
--fail-on-threshold Return exit code 1 when status is warning or critical.
|
|
--help Show this message.
|
|
""";
|
|
|
|
public string? OutputPath { get; init; }
|
|
|
|
public int LookbackDays { get; init; } = 30;
|
|
|
|
public int TopCount { get; init; } = 10;
|
|
|
|
public bool JsonOnly { get; init; }
|
|
|
|
public bool NinjaOutput { get; init; }
|
|
|
|
public bool FailOnAttacks { get; init; }
|
|
|
|
public bool FailOnThreshold { get; init; }
|
|
|
|
public string? ConfigPath { get; init; }
|
|
|
|
public string? VulnerabilityCsvPath { get; init; }
|
|
|
|
public bool ShowHelp { get; init; }
|
|
|
|
public static ScanOptions Parse(string[] args)
|
|
{
|
|
var options = new ScanOptions();
|
|
|
|
for (int i = 0; i < args.Length; i++)
|
|
{
|
|
string arg = args[i];
|
|
switch (arg)
|
|
{
|
|
case "--help":
|
|
case "-h":
|
|
case "/?":
|
|
options = options with { ShowHelp = true };
|
|
break;
|
|
case "--json-only":
|
|
options = options with { JsonOnly = true };
|
|
break;
|
|
case "--ninja-output":
|
|
options = options with { NinjaOutput = true };
|
|
break;
|
|
case "--fail-on-attacks":
|
|
options = options with { FailOnAttacks = true };
|
|
break;
|
|
case "--fail-on-threshold":
|
|
options = options with { FailOnThreshold = true };
|
|
break;
|
|
case "--output":
|
|
options = options with { OutputPath = ReadValue(args, ref i, arg) };
|
|
break;
|
|
case "--config":
|
|
options = options with { ConfigPath = ReadValue(args, ref i, arg) };
|
|
break;
|
|
case "--vulnerability-csv":
|
|
options = options with { VulnerabilityCsvPath = ReadValue(args, ref i, arg) };
|
|
break;
|
|
case "--lookback-days":
|
|
options = options with { LookbackDays = ReadPositiveInt(args, ref i, arg) };
|
|
break;
|
|
case "--top":
|
|
options = options with { TopCount = ReadPositiveInt(args, ref i, arg) };
|
|
break;
|
|
default:
|
|
throw new ArgumentException($"Unknown argument: {arg}");
|
|
}
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
private static string ReadValue(string[] args, ref int index, string argName)
|
|
{
|
|
if (index + 1 >= args.Length)
|
|
{
|
|
throw new ArgumentException($"Missing value for {argName}");
|
|
}
|
|
|
|
index++;
|
|
return args[index];
|
|
}
|
|
|
|
private static int ReadPositiveInt(string[] args, ref int index, string argName)
|
|
{
|
|
string raw = ReadValue(args, ref index, argName);
|
|
if (!int.TryParse(raw, out int value) || value <= 0)
|
|
{
|
|
throw new ArgumentException($"{argName} must be a positive integer");
|
|
}
|
|
|
|
return value;
|
|
}
|
|
}
|