Compare commits
6 Commits
v1.5.0-bet
...
v1.5.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
072a4257ed | ||
|
|
47fe9448b7 | ||
|
|
fd990b698f | ||
|
|
d1bbd8838f | ||
|
|
feeeeedcf1 | ||
|
|
ceefb7a5dc |
@@ -10,7 +10,7 @@
|
|||||||
"criticalSprayAccountCount": 10,
|
"criticalSprayAccountCount": 10,
|
||||||
"correlationWarningCveThreshold": 1,
|
"correlationWarningCveThreshold": 1,
|
||||||
"correlationCriticalCveThreshold": 1,
|
"correlationCriticalCveThreshold": 1,
|
||||||
"ransomwareBetaEnabled": false,
|
"ransomwareBetaEnabled": true,
|
||||||
"ransomwareBetaAlertingEnabled": false,
|
"ransomwareBetaAlertingEnabled": false,
|
||||||
"ransomwareLookbackMinutes": 15,
|
"ransomwareLookbackMinutes": 15,
|
||||||
"ransomwareWarningSignalCount": 2,
|
"ransomwareWarningSignalCount": 2,
|
||||||
|
|||||||
@@ -19,12 +19,19 @@ Die Stable-Aufgabe verwendet keinen Kanalwert oder den Wert `stable`.
|
|||||||
|
|
||||||
## Passive Ransomware-Beta
|
## Passive Ransomware-Beta
|
||||||
|
|
||||||
Die Beta ist nach der Installation weiterhin deaktiviert. Auf einem
|
Die Ransomware-Beta ist im Beta-Kanal standardmaessig aktiviert. Die Auswertung
|
||||||
Pilotgeraet wird in `C:\Program Files\OCSentinel\config\ocsentinel-settings.json`
|
bleibt passiv, solange `ransomwareBetaAlertingEnabled` auf `false` steht:
|
||||||
der Wert `ransomwareBetaEnabled` auf `true` gesetzt. Die Auswertung bleibt
|
Hinweise, Warnungen und kritische Beta-Signale erscheinen im JSON-Report und
|
||||||
passiv, solange `ransomwareBetaAlertingEnabled` auf `false` steht: Hinweise,
|
Dashboard, veraendern aber keine NinjaOne-Alarmfelder. Fuer eine lokale
|
||||||
Warnungen und kritische Beta-Signale erscheinen im JSON-Report und Dashboard,
|
Ausnahme kann `ransomwareBetaEnabled` in
|
||||||
veraendern aber keine NinjaOne-Alarmfelder.
|
`C:\Program Files\OCSentinel\config\ocsentinel-settings.json` auf `false`
|
||||||
|
gesetzt werden.
|
||||||
|
|
||||||
|
Jeder Beta-Report enthaelt zudem eine datensparsame Sensorabdeckung fuer
|
||||||
|
Security-Ereignis 4688, PowerShell 4104, Sysmon 1 und das optionale
|
||||||
|
Datei-Auditing 4663. Damit bedeutet ein Status `ok` nicht mehr stillschweigend,
|
||||||
|
dass alle Datenquellen vorhanden waren. Es werden nur Verfuegbarkeit,
|
||||||
|
technischer Zustand und gezaehlte Ereignisse uebertragen.
|
||||||
|
|
||||||
Der optionale Datei-Churn-Sensor wird nur mit
|
Der optionale Datei-Churn-Sensor wird nur mit
|
||||||
`ransomwareFileChurnEnabled: true` aktiviert. Er wertet ausschliesslich bereits
|
`ransomwareFileChurnEnabled: true` aktiviert. Er wertet ausschliesslich bereits
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ write access:
|
|||||||
| `ocsentinelqueuedreports` | Integer | Reports waiting for delivery |
|
| `ocsentinelqueuedreports` | Integer | Reports waiting for delivery |
|
||||||
| `ocsentinellastuploadutc` | Date/Time | Last successful upload time |
|
| `ocsentinellastuploadutc` | Date/Time | Last successful upload time |
|
||||||
| `ocsentinellasterror` | Text | Last upload error, if any |
|
| `ocsentinellasterror` | Text | Last upload error, if any |
|
||||||
| `ocsentinelclientversion` | Text | Installed client version |
|
|
||||||
|
|
||||||
## NinjaOne Tasks
|
## NinjaOne Tasks
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ Ein Pilot wird pausiert und zurueckgesetzt, wenn eines dieser Kriterien eintritt
|
|||||||
- Snapshot der SMB-Sitzungen und des Incident-Kontexts erst bei einer
|
- Snapshot der SMB-Sitzungen und des Incident-Kontexts erst bei einer
|
||||||
Auffaelligkeit.
|
Auffaelligkeit.
|
||||||
- Verdichtetes Ransomware-Incident-Protokoll fuer n8n und die Uebersicht.
|
- Verdichtetes Ransomware-Incident-Protokoll fuer n8n und die Uebersicht.
|
||||||
|
- Strukturierte Sensorabdeckung im Report, damit fehlende Audit- oder Sysmon-
|
||||||
|
Quellen von einem echten unauffaelligen Zeitraum unterscheidbar sind.
|
||||||
|
|
||||||
**Bewertung**
|
**Bewertung**
|
||||||
|
|
||||||
|
|||||||
@@ -149,7 +149,6 @@ function Publish-NinjaCustomFields {
|
|||||||
[pscustomobject]@{ Name = "ocsentinelqueuedreports"; Type = "Integer"; Value = $queuedReports }
|
[pscustomobject]@{ Name = "ocsentinelqueuedreports"; Type = "Integer"; Value = $queuedReports }
|
||||||
[pscustomobject]@{ Name = "ocsentinellastuploadutc"; Type = "DateTime"; Value = $lastUploadUtc }
|
[pscustomobject]@{ Name = "ocsentinellastuploadutc"; Type = "DateTime"; Value = $lastUploadUtc }
|
||||||
[pscustomobject]@{ Name = "ocsentinellasterror"; Type = "Text"; Value = $lastUploadError }
|
[pscustomobject]@{ Name = "ocsentinellasterror"; Type = "Text"; Value = $lastUploadError }
|
||||||
[pscustomobject]@{ Name = "ocsentinelclientversion"; Type = "Text"; Value = [string]$Report.ClientVersion }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
$updated = 0
|
$updated = 0
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"channel": "beta",
|
"channel": "beta",
|
||||||
"version": "1.5.0-beta.1",
|
"version": "1.5.0-beta.4",
|
||||||
"publishedAtUtc": "2026-07-29T23:07:54.7923320Z",
|
"publishedAtUtc": "2026-07-31T23:38:20.1674646Z",
|
||||||
"artifactUrl": "https://gitea.officecom.cloud/officecom/oc-sentinel/releases/download/v1.5.0-beta.1/OCSentinelClient-win-x64.zip",
|
"artifactUrl": "https://gitea.officecom.cloud/officecom/oc-sentinel/releases/download/v1.5.0-beta.4/OCSentinelClient-win-x64.zip",
|
||||||
"sha256": "a712ee820dee2f6786a8297d892b3ae8844548ddc7030dcbe01435fbc89d924a",
|
"sha256": "f8e8714a4ea1426674bca27a403c33e166a31b38f77f0c638cb4a6a51b8f3343",
|
||||||
"minUpdaterVersion": "1.0.0"
|
"minUpdaterVersion": "1.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,30 @@ function Get-OCSentinelArtifact {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Enable-OCSentinelBetaDefaults {
|
||||||
|
param([Parameter(Mandatory)][string]$SettingsPath)
|
||||||
|
|
||||||
|
if (-not (Test-Path -LiteralPath $SettingsPath)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings = Get-Content -LiteralPath $SettingsPath -Raw | ConvertFrom-Json
|
||||||
|
if ($null -ne $settings.PSObject.Properties["ransomwareBetaDefaultApplied"]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($null -eq $settings.PSObject.Properties["ransomwareBetaEnabled"]) {
|
||||||
|
$settings | Add-Member -NotePropertyName "ransomwareBetaEnabled" -NotePropertyValue $true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$settings.ransomwareBetaEnabled = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings | Add-Member -NotePropertyName "ransomwareBetaDefaultApplied" -NotePropertyValue "1.5.0-beta.4"
|
||||||
|
$settings | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath $SettingsPath -Encoding UTF8
|
||||||
|
Write-Host "Enabled passive ransomware beta defaults."
|
||||||
|
}
|
||||||
|
|
||||||
Initialize-OCSentinelTls
|
Initialize-OCSentinelTls
|
||||||
|
|
||||||
if ($ReleaseChannel -eq "stable" -and -not [string]::IsNullOrWhiteSpace($env:ReleaseChannel)) {
|
if ($ReleaseChannel -eq "stable" -and -not [string]::IsNullOrWhiteSpace($env:ReleaseChannel)) {
|
||||||
@@ -133,6 +157,7 @@ $updaterPath = Join-Path $installRoot "scripts\update-ocsentinel.ps1"
|
|||||||
$monitorPath = Join-Path $installRoot "scripts\run-ocsentinel-monitor.ps1"
|
$monitorPath = Join-Path $installRoot "scripts\run-ocsentinel-monitor.ps1"
|
||||||
$appPath = Join-Path $installRoot "app\OCSentinelCli.exe"
|
$appPath = Join-Path $installRoot "app\OCSentinelCli.exe"
|
||||||
$clientConfigPath = Join-Path $installRoot "config\ocsentinel-client.json"
|
$clientConfigPath = Join-Path $installRoot "config\ocsentinel-client.json"
|
||||||
|
$settingsPath = Join-Path $installRoot "config\ocsentinel-settings.json"
|
||||||
$secretScriptPath = Join-Path $installRoot "scripts\protect-ocsentinel-secret.ps1"
|
$secretScriptPath = Join-Path $installRoot "scripts\protect-ocsentinel-secret.ps1"
|
||||||
$secretPath = "C:\ProgramData\OCSentinel\secrets\ocsentinel-upload-secret.dat"
|
$secretPath = "C:\ProgramData\OCSentinel\secrets\ocsentinel-upload-secret.dat"
|
||||||
|
|
||||||
@@ -214,6 +239,10 @@ if (-not (Test-Path -LiteralPath $appPath)) {
|
|||||||
throw "OCSentinel installation completed, but the client executable was not found."
|
throw "OCSentinel installation completed, but the client executable was not found."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($ReleaseChannel -eq "beta") {
|
||||||
|
Enable-OCSentinelBetaDefaults -SettingsPath $settingsPath
|
||||||
|
}
|
||||||
|
|
||||||
if (-not [string]::IsNullOrWhiteSpace($WebhookUrl)) {
|
if (-not [string]::IsNullOrWhiteSpace($WebhookUrl)) {
|
||||||
if (-not (Test-Path -LiteralPath $clientConfigPath)) {
|
if (-not (Test-Path -LiteralPath $clientConfigPath)) {
|
||||||
throw "OCSentinel client configuration was not found: $clientConfigPath"
|
throw "OCSentinel client configuration was not found: $clientConfigPath"
|
||||||
|
|||||||
@@ -149,7 +149,6 @@ function Publish-NinjaCustomFields {
|
|||||||
[pscustomobject]@{ Name = "ocsentinelqueuedreports"; Type = "Integer"; Value = $queuedReports }
|
[pscustomobject]@{ Name = "ocsentinelqueuedreports"; Type = "Integer"; Value = $queuedReports }
|
||||||
[pscustomobject]@{ Name = "ocsentinellastuploadutc"; Type = "DateTime"; Value = $lastUploadUtc }
|
[pscustomobject]@{ Name = "ocsentinellastuploadutc"; Type = "DateTime"; Value = $lastUploadUtc }
|
||||||
[pscustomobject]@{ Name = "ocsentinellasterror"; Type = "Text"; Value = $lastUploadError }
|
[pscustomobject]@{ Name = "ocsentinellasterror"; Type = "Text"; Value = $lastUploadError }
|
||||||
[pscustomobject]@{ Name = "ocsentinelclientversion"; Type = "Text"; Value = [string]$Report.ClientVersion }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
$updated = 0
|
$updated = 0
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ internal sealed record ScannerConfiguration
|
|||||||
|
|
||||||
public int CorrelationCriticalCveThreshold { get; init; } = 1;
|
public int CorrelationCriticalCveThreshold { get; init; } = 1;
|
||||||
|
|
||||||
public bool RansomwareBetaEnabled { get; init; }
|
public bool RansomwareBetaEnabled { get; init; } = true;
|
||||||
|
|
||||||
public bool RansomwareBetaAlertingEnabled { get; init; }
|
public bool RansomwareBetaAlertingEnabled { get; init; }
|
||||||
|
|
||||||
|
|||||||
@@ -129,11 +129,26 @@ internal sealed record RansomwareBetaSummary
|
|||||||
|
|
||||||
public List<RansomwareSignal> Signals { get; init; } = [];
|
public List<RansomwareSignal> Signals { get; init; } = [];
|
||||||
|
|
||||||
|
public List<RansomwareSensorStatus> Sensors { get; init; } = [];
|
||||||
|
|
||||||
public List<RansomwareSmbSession> SmbSessions { get; init; } = [];
|
public List<RansomwareSmbSession> SmbSessions { get; init; } = [];
|
||||||
|
|
||||||
public RansomwareFileChurnSummary FileChurn { get; init; } = new();
|
public RansomwareFileChurnSummary FileChurn { get; init; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal sealed record RansomwareSensorStatus
|
||||||
|
{
|
||||||
|
public string Name { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
public bool Enabled { get; init; }
|
||||||
|
|
||||||
|
public bool Available { get; init; }
|
||||||
|
|
||||||
|
public string State { get; init; } = "unknown";
|
||||||
|
|
||||||
|
public int EventCount { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
internal sealed record RansomwareFileChurnSummary
|
internal sealed record RansomwareFileChurnSummary
|
||||||
{
|
{
|
||||||
public bool Enabled { get; init; }
|
public bool Enabled { get; init; }
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
<RootNamespace>OCSentinelCli</RootNamespace>
|
<RootNamespace>OCSentinelCli</RootNamespace>
|
||||||
<Product>OfficeCom Sentinel</Product>
|
<Product>OfficeCom Sentinel</Product>
|
||||||
<Company>OfficeCom</Company>
|
<Company>OfficeCom</Company>
|
||||||
<Version>1.5.0-beta.2</Version>
|
<Version>1.5.0-beta.5</Version>
|
||||||
<AssemblyVersion>1.5.0.0</AssemblyVersion>
|
<AssemblyVersion>1.5.0.0</AssemblyVersion>
|
||||||
<FileVersion>1.5.0.0</FileVersion>
|
<FileVersion>1.5.0.0</FileVersion>
|
||||||
<InformationalVersion>1.5.0-beta.2</InformationalVersion>
|
<InformationalVersion>1.5.0-beta.5</InformationalVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -18,11 +18,22 @@ internal static class RansomwareBetaDetector
|
|||||||
int lookbackMinutes = Math.Clamp(configuration.RansomwareLookbackMinutes, 1, 60);
|
int lookbackMinutes = Math.Clamp(configuration.RansomwareLookbackMinutes, 1, 60);
|
||||||
DateTimeOffset since = DateTimeOffset.UtcNow.AddMinutes(-lookbackMinutes);
|
DateTimeOffset since = DateTimeOffset.UtcNow.AddMinutes(-lookbackMinutes);
|
||||||
var signals = new List<RansomwareSignal>();
|
var signals = new List<RansomwareSignal>();
|
||||||
|
var sensors = new List<RansomwareSensorStatus>
|
||||||
|
{
|
||||||
|
ScanSecurityProcesses(signals, errors, since, configuration),
|
||||||
|
ScanPowerShellScriptBlocks(signals, errors, since, configuration),
|
||||||
|
ScanSysmonProcesses(signals, errors, since, configuration)
|
||||||
|
};
|
||||||
|
|
||||||
ScanSecurityProcesses(signals, errors, since, configuration);
|
|
||||||
ScanPowerShellScriptBlocks(signals, errors, since, configuration);
|
|
||||||
ScanSysmonProcesses(signals, errors, since, configuration);
|
|
||||||
RansomwareFileChurnSummary fileChurn = RansomwareFileChurnDetector.Scan(configuration, errors);
|
RansomwareFileChurnSummary fileChurn = RansomwareFileChurnDetector.Scan(configuration, errors);
|
||||||
|
sensors.Add(new RansomwareSensorStatus
|
||||||
|
{
|
||||||
|
Name = "security-file-audit-4663",
|
||||||
|
Enabled = fileChurn.Enabled,
|
||||||
|
Available = fileChurn.DataAvailable,
|
||||||
|
State = !fileChurn.Enabled ? "disabled" : fileChurn.IsTruncated ? "truncated" : fileChurn.DataAvailable ? "available" : "unavailable",
|
||||||
|
EventCount = fileChurn.FileOperationCount
|
||||||
|
});
|
||||||
RansomwareSignal? fileChurnSignal = RansomwareFileChurnDetector.CreateSignal(fileChurn, configuration);
|
RansomwareSignal? fileChurnSignal = RansomwareFileChurnDetector.CreateSignal(fileChurn, configuration);
|
||||||
if (fileChurnSignal is not null)
|
if (fileChurnSignal is not null)
|
||||||
{
|
{
|
||||||
@@ -61,24 +72,25 @@ internal static class RansomwareBetaDetector
|
|||||||
Reason = reason,
|
Reason = reason,
|
||||||
LookbackMinutes = lookbackMinutes,
|
LookbackMinutes = lookbackMinutes,
|
||||||
Signals = distinctSignals,
|
Signals = distinctSignals,
|
||||||
|
Sensors = sensors,
|
||||||
SmbSessions = smbSessions,
|
SmbSessions = smbSessions,
|
||||||
FileChurn = fileChurn
|
FileChurn = fileChurn
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ScanSecurityProcesses(List<RansomwareSignal> signals, List<string> errors, DateTimeOffset since, ScannerConfiguration configuration)
|
private static RansomwareSensorStatus ScanSecurityProcesses(List<RansomwareSignal> signals, List<string> errors, DateTimeOffset since, ScannerConfiguration configuration)
|
||||||
{
|
{
|
||||||
TryScan("Security", 4688, since, errors, record => AddSignal(signals, record, ReadProperty(record, 5), ReadProperty(record, 8), "Security", configuration));
|
return TryScan("security-process-4688", "Security", 4688, since, errors, record => AddSignal(signals, record, ReadProperty(record, 5), ReadProperty(record, 8), "Security", configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ScanPowerShellScriptBlocks(List<RansomwareSignal> signals, List<string> errors, DateTimeOffset since, ScannerConfiguration configuration)
|
private static RansomwareSensorStatus ScanPowerShellScriptBlocks(List<RansomwareSignal> signals, List<string> errors, DateTimeOffset since, ScannerConfiguration configuration)
|
||||||
{
|
{
|
||||||
TryScan("Microsoft-Windows-PowerShell/Operational", 4104, since, errors, record => AddSignal(signals, record, "powershell", FormatDescription(record), "PowerShell", configuration));
|
return TryScan("powershell-script-block-4104", "Microsoft-Windows-PowerShell/Operational", 4104, since, errors, record => AddSignal(signals, record, "powershell", FormatDescription(record), "PowerShell", configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ScanSysmonProcesses(List<RansomwareSignal> signals, List<string> errors, DateTimeOffset since, ScannerConfiguration configuration)
|
private static RansomwareSensorStatus ScanSysmonProcesses(List<RansomwareSignal> signals, List<string> errors, DateTimeOffset since, ScannerConfiguration configuration)
|
||||||
{
|
{
|
||||||
TryScan("Microsoft-Windows-Sysmon/Operational", 1, since, errors, record => AddSignal(signals, record, "sysmon-process", FormatDescription(record), "Sysmon", configuration));
|
return TryScan("sysmon-process-1", "Microsoft-Windows-Sysmon/Operational", 1, since, errors, record => AddSignal(signals, record, "sysmon-process", FormatDescription(record), "Sysmon", configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddSignal(List<RansomwareSignal> signals, EventRecord record, string process, string commandLine, string source, ScannerConfiguration configuration)
|
private static void AddSignal(List<RansomwareSignal> signals, EventRecord record, string process, string commandLine, string source, ScannerConfiguration configuration)
|
||||||
@@ -146,8 +158,9 @@ internal static class RansomwareBetaDetector
|
|||||||
|
|
||||||
private static bool ContainsAll(string value, params string[] needles) => needles.All(needle => value.Contains(needle, StringComparison.Ordinal));
|
private static bool ContainsAll(string value, params string[] needles) => needles.All(needle => value.Contains(needle, StringComparison.Ordinal));
|
||||||
|
|
||||||
private static void TryScan(string logName, int eventId, DateTimeOffset since, List<string> errors, Action<EventRecord> processRecord)
|
private static RansomwareSensorStatus TryScan(string sensorName, string logName, int eventId, DateTimeOffset since, List<string> errors, Action<EventRecord> processRecord)
|
||||||
{
|
{
|
||||||
|
int eventCount = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
long milliseconds = Math.Max(1, (long)(DateTimeOffset.UtcNow - since).TotalMilliseconds);
|
long milliseconds = Math.Max(1, (long)(DateTimeOffset.UtcNow - since).TotalMilliseconds);
|
||||||
@@ -157,16 +170,39 @@ internal static class RansomwareBetaDetector
|
|||||||
{
|
{
|
||||||
using (record)
|
using (record)
|
||||||
{
|
{
|
||||||
|
eventCount++;
|
||||||
processRecord(record);
|
processRecord(record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new RansomwareSensorStatus
|
||||||
|
{
|
||||||
|
Name = sensorName,
|
||||||
|
Enabled = true,
|
||||||
|
Available = true,
|
||||||
|
State = "available",
|
||||||
|
EventCount = eventCount
|
||||||
|
};
|
||||||
}
|
}
|
||||||
catch (EventLogNotFoundException)
|
catch (EventLogNotFoundException)
|
||||||
{
|
{
|
||||||
|
return new RansomwareSensorStatus
|
||||||
|
{
|
||||||
|
Name = sensorName,
|
||||||
|
Enabled = true,
|
||||||
|
State = "not-installed"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
errors.Add($"Ransomware beta query failed for {logName}: {exception.Message}");
|
errors.Add($"Ransomware beta query failed for {logName}: {exception.Message}");
|
||||||
|
return new RansomwareSensorStatus
|
||||||
|
{
|
||||||
|
Name = sensorName,
|
||||||
|
Enabled = true,
|
||||||
|
State = "query-failed",
|
||||||
|
EventCount = eventCount
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
using System.Text.Json;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace OCSentinelCli.Tests;
|
namespace OCSentinelCli.Tests;
|
||||||
@@ -6,6 +7,37 @@ namespace OCSentinelCli.Tests;
|
|||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
public sealed class RansomwareBetaTests
|
public sealed class RansomwareBetaTests
|
||||||
{
|
{
|
||||||
|
[Fact]
|
||||||
|
public void RansomwareBetaIsEnabledByDefault()
|
||||||
|
{
|
||||||
|
Assert.True(new ScannerConfiguration().RansomwareBetaEnabled);
|
||||||
|
Assert.False(new ScannerConfiguration().RansomwareBetaAlertingEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DisabledRansomwareBetaDoesNotReportSensorCoverage()
|
||||||
|
{
|
||||||
|
var summary = RansomwareBetaDetector.Scan(new ScannerConfiguration { RansomwareBetaEnabled = false }, []);
|
||||||
|
|
||||||
|
Assert.False(summary.Enabled);
|
||||||
|
Assert.Empty(summary.Sensors);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SensorCoverageIsIncludedInTheJsonReport()
|
||||||
|
{
|
||||||
|
var summary = new RansomwareBetaSummary
|
||||||
|
{
|
||||||
|
Enabled = true,
|
||||||
|
Sensors = [new RansomwareSensorStatus { Name = "security-process-4688", Enabled = true, Available = true, State = "available", EventCount = 4 }]
|
||||||
|
};
|
||||||
|
|
||||||
|
string json = JsonSerializer.Serialize(summary, JsonOptions.Default);
|
||||||
|
|
||||||
|
Assert.Contains("\"Sensors\"", json);
|
||||||
|
Assert.Contains("security-process-4688", json);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void FileChurnBelowBothThresholdsDoesNotCreateSignal()
|
public void FileChurnBelowBothThresholdsDoesNotCreateSignal()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user