save audit remarks applications progress

This commit is contained in:
StellaOps Bot
2026-01-04 22:49:53 +02:00
parent 8862e112c4
commit eca4e964d3
48 changed files with 1850 additions and 112 deletions

View File

@@ -11,6 +11,13 @@ namespace StellaOps.Scanner.Analyzers.Native.Hardening;
/// </summary>
public sealed class ElfHardeningExtractor : IHardeningExtractor
{
private readonly TimeProvider _timeProvider;
public ElfHardeningExtractor(TimeProvider? timeProvider = null)
{
_timeProvider = timeProvider ?? TimeProvider.System;
}
// ELF magic bytes
private static readonly byte[] ElfMagic = [0x7F, 0x45, 0x4C, 0x46]; // \x7FELF
@@ -596,7 +603,7 @@ public sealed class ElfHardeningExtractor : IHardeningExtractor
#endregion
private static BinaryHardeningFlags CreateResult(
private BinaryHardeningFlags CreateResult(
string path,
string digest,
List<HardeningFlag> flags,
@@ -623,7 +630,7 @@ public sealed class ElfHardeningExtractor : IHardeningExtractor
Flags: [.. flags],
HardeningScore: Math.Round(score, 2),
MissingFlags: [.. missing],
ExtractedAt: DateTimeOffset.UtcNow);
ExtractedAt: _timeProvider.GetUtcNow());
}
private static ushort ReadUInt16(ReadOnlySpan<byte> span, bool littleEndian)

View File

@@ -17,6 +17,13 @@ namespace StellaOps.Scanner.Analyzers.Native.Hardening;
/// </summary>
public sealed class MachoHardeningExtractor : IHardeningExtractor
{
private readonly TimeProvider _timeProvider;
public MachoHardeningExtractor(TimeProvider? timeProvider = null)
{
_timeProvider = timeProvider ?? TimeProvider.System;
}
// Mach-O magic numbers
private const uint MH_MAGIC = 0xFEEDFACE; // 32-bit
private const uint MH_CIGAM = 0xCEFAEDFE; // 32-bit (reversed)
@@ -257,7 +264,7 @@ public sealed class MachoHardeningExtractor : IHardeningExtractor
: BinaryPrimitives.ReadUInt32BigEndian(data.AsSpan(offset, 4));
}
private static BinaryHardeningFlags CreateResult(
private BinaryHardeningFlags CreateResult(
string path,
string digest,
List<HardeningFlag> flags,
@@ -283,6 +290,6 @@ public sealed class MachoHardeningExtractor : IHardeningExtractor
Flags: [.. flags],
HardeningScore: Math.Round(score, 2),
MissingFlags: [.. missing],
ExtractedAt: DateTimeOffset.UtcNow);
ExtractedAt: _timeProvider.GetUtcNow());
}
}

View File

@@ -19,6 +19,13 @@ namespace StellaOps.Scanner.Analyzers.Native.Hardening;
/// </summary>
public sealed class PeHardeningExtractor : IHardeningExtractor
{
private readonly TimeProvider _timeProvider;
public PeHardeningExtractor(TimeProvider? timeProvider = null)
{
_timeProvider = timeProvider ?? TimeProvider.System;
}
// PE magic bytes: MZ (DOS header)
private const ushort DOS_MAGIC = 0x5A4D; // "MZ"
private const uint PE_SIGNATURE = 0x00004550; // "PE\0\0"
@@ -233,7 +240,7 @@ public sealed class PeHardeningExtractor : IHardeningExtractor
}
}
private static BinaryHardeningFlags CreateResult(
private BinaryHardeningFlags CreateResult(
string path,
string digest,
List<HardeningFlag> flags,
@@ -259,6 +266,6 @@ public sealed class PeHardeningExtractor : IHardeningExtractor
Flags: [.. flags],
HardeningScore: Math.Round(score, 2),
MissingFlags: [.. missing],
ExtractedAt: DateTimeOffset.UtcNow);
ExtractedAt: _timeProvider.GetUtcNow());
}
}

View File

@@ -17,6 +17,7 @@ public sealed class OfflineBuildIdIndex : IBuildIdIndex
private readonly BuildIdIndexOptions _options;
private readonly ILogger<OfflineBuildIdIndex> _logger;
private readonly IDsseSigningService? _dsseSigningService;
private readonly TimeProvider _timeProvider;
private FrozenDictionary<string, BuildIdLookupResult> _index = FrozenDictionary<string, BuildIdLookupResult>.Empty;
private bool _isLoaded;
@@ -31,7 +32,8 @@ public sealed class OfflineBuildIdIndex : IBuildIdIndex
public OfflineBuildIdIndex(
IOptions<BuildIdIndexOptions> options,
ILogger<OfflineBuildIdIndex> logger,
IDsseSigningService? dsseSigningService = null)
IDsseSigningService? dsseSigningService = null,
TimeProvider? timeProvider = null)
{
ArgumentNullException.ThrowIfNull(options);
ArgumentNullException.ThrowIfNull(logger);
@@ -39,6 +41,7 @@ public sealed class OfflineBuildIdIndex : IBuildIdIndex
_options = options.Value;
_logger = logger;
_dsseSigningService = dsseSigningService;
_timeProvider = timeProvider ?? TimeProvider.System;
}
/// <inheritdoc />
@@ -176,7 +179,7 @@ public sealed class OfflineBuildIdIndex : IBuildIdIndex
// Check index freshness
if (_options.MaxIndexAge > TimeSpan.Zero)
{
var oldestAllowed = DateTimeOffset.UtcNow - _options.MaxIndexAge;
var oldestAllowed = _timeProvider.GetUtcNow() - _options.MaxIndexAge;
var latestEntry = entries.Values.MaxBy(e => e.IndexedAt);
if (latestEntry is not null && latestEntry.IndexedAt < oldestAllowed)
{

View File

@@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using StellaOps.Determinism;
namespace StellaOps.Scanner.Analyzers.Native.RuntimeCapture;
@@ -22,6 +23,8 @@ namespace StellaOps.Scanner.Analyzers.Native.RuntimeCapture;
[SupportedOSPlatform("linux")]
public sealed class LinuxEbpfCaptureAdapter : IRuntimeCaptureAdapter
{
private readonly TimeProvider _timeProvider;
private readonly IGuidProvider _guidProvider;
private readonly ConcurrentBag<RuntimeLoadEvent> _events = [];
private readonly object _stateLock = new();
private CaptureState _state = CaptureState.Idle;
@@ -33,6 +36,17 @@ public sealed class LinuxEbpfCaptureAdapter : IRuntimeCaptureAdapter
private long _droppedEvents;
private int _redactedPaths;
/// <summary>
/// Creates a new Linux eBPF capture adapter.
/// </summary>
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
/// <param name="guidProvider">Optional GUID provider for deterministic session IDs.</param>
public LinuxEbpfCaptureAdapter(TimeProvider? timeProvider = null, IGuidProvider? guidProvider = null)
{
_timeProvider = timeProvider ?? TimeProvider.System;
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
}
/// <inheritdoc />
public string AdapterId => "linux-ebpf-dlopen";
@@ -152,8 +166,8 @@ public sealed class LinuxEbpfCaptureAdapter : IRuntimeCaptureAdapter
_events.Clear();
_droppedEvents = 0;
_redactedPaths = 0;
SessionId = Guid.NewGuid().ToString("N");
_startTime = DateTime.UtcNow;
SessionId = _guidProvider.NewGuid().ToString("N");
_startTime = _timeProvider.GetUtcNow().UtcDateTime;
_captureCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
try
@@ -243,7 +257,7 @@ public sealed class LinuxEbpfCaptureAdapter : IRuntimeCaptureAdapter
var session = new RuntimeCaptureSession(
SessionId: SessionId ?? "unknown",
StartTime: _startTime,
EndTime: DateTime.UtcNow,
EndTime: _timeProvider.GetUtcNow().UtcDateTime,
Platform: Platform,
CaptureMethod: CaptureMethod,
TargetProcessId: _options?.TargetProcessId,
@@ -405,7 +419,7 @@ public sealed class LinuxEbpfCaptureAdapter : IRuntimeCaptureAdapter
if (parts[0] == "DLOPEN" && parts.Length >= 5)
{
return new RuntimeLoadEvent(
Timestamp: DateTime.UtcNow,
Timestamp: _timeProvider.GetUtcNow().UtcDateTime,
ProcessId: int.Parse(parts[1]),
ThreadId: int.Parse(parts[2]),
LoadType: RuntimeLoadType.Dlopen,

View File

@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using StellaOps.Determinism;
namespace StellaOps.Scanner.Analyzers.Native.RuntimeCapture;
@@ -23,6 +24,8 @@ namespace StellaOps.Scanner.Analyzers.Native.RuntimeCapture;
[SupportedOSPlatform("macos")]
public sealed class MacOsDyldCaptureAdapter : IRuntimeCaptureAdapter
{
private readonly TimeProvider _timeProvider;
private readonly IGuidProvider _guidProvider;
private readonly ConcurrentBag<RuntimeLoadEvent> _events = [];
private readonly object _stateLock = new();
private CaptureState _state = CaptureState.Idle;
@@ -34,6 +37,17 @@ public sealed class MacOsDyldCaptureAdapter : IRuntimeCaptureAdapter
private long _droppedEvents;
private int _redactedPaths;
/// <summary>
/// Creates a new macOS dyld capture adapter.
/// </summary>
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
/// <param name="guidProvider">Optional GUID provider for deterministic session IDs.</param>
public MacOsDyldCaptureAdapter(TimeProvider? timeProvider = null, IGuidProvider? guidProvider = null)
{
_timeProvider = timeProvider ?? TimeProvider.System;
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
}
/// <inheritdoc />
public string AdapterId => "macos-dyld-interpose";
@@ -156,8 +170,8 @@ public sealed class MacOsDyldCaptureAdapter : IRuntimeCaptureAdapter
_events.Clear();
_droppedEvents = 0;
_redactedPaths = 0;
SessionId = Guid.NewGuid().ToString("N");
_startTime = DateTime.UtcNow;
SessionId = _guidProvider.NewGuid().ToString("N");
_startTime = _timeProvider.GetUtcNow().UtcDateTime;
_captureCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
try
@@ -247,7 +261,7 @@ public sealed class MacOsDyldCaptureAdapter : IRuntimeCaptureAdapter
var session = new RuntimeCaptureSession(
SessionId: SessionId ?? "unknown",
StartTime: _startTime,
EndTime: DateTime.UtcNow,
EndTime: _timeProvider.GetUtcNow().UtcDateTime,
Platform: Platform,
CaptureMethod: CaptureMethod,
TargetProcessId: _options?.TargetProcessId,
@@ -417,7 +431,7 @@ public sealed class MacOsDyldCaptureAdapter : IRuntimeCaptureAdapter
: RuntimeLoadType.MacOsDlopen;
return new RuntimeLoadEvent(
Timestamp: DateTime.UtcNow,
Timestamp: _timeProvider.GetUtcNow().UtcDateTime,
ProcessId: int.Parse(parts[1]),
ThreadId: int.Parse(parts[2]),
LoadType: loadType,

View File

@@ -48,11 +48,13 @@ public static class RuntimeEvidenceAggregator
/// <param name="runtimeEvidence">Runtime capture evidence.</param>
/// <param name="staticEdges">Static analysis dependency edges.</param>
/// <param name="heuristicEdges">Heuristic analysis edges.</param>
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
/// <returns>Merged evidence document.</returns>
public static MergedEvidence MergeWithStaticAnalysis(
RuntimeEvidence runtimeEvidence,
IEnumerable<Observations.NativeObservationDeclaredEdge> staticEdges,
IEnumerable<Observations.NativeObservationHeuristicEdge> heuristicEdges)
IEnumerable<Observations.NativeObservationHeuristicEdge> heuristicEdges,
TimeProvider? timeProvider = null)
{
var staticList = staticEdges.ToList();
var heuristicList = heuristicEdges.ToList();
@@ -140,6 +142,7 @@ public static class RuntimeEvidenceAggregator
}
}
var tp = timeProvider ?? TimeProvider.System;
return new MergedEvidence(
ConfirmedEdges: confirmedEdges,
StaticOnlyEdges: staticOnlyEdges,
@@ -148,7 +151,7 @@ public static class RuntimeEvidenceAggregator
TotalRuntimeEvents: runtimeEvidence.Sessions.Sum(s => s.Events.Count),
TotalDroppedEvents: runtimeEvidence.Sessions.Sum(s => s.TotalEventsDropped),
CaptureStartTime: runtimeEvidence.Sessions.Min(s => s.StartTime),
CaptureEndTime: runtimeEvidence.Sessions.Max(s => s.EndTime ?? DateTime.UtcNow));
CaptureEndTime: runtimeEvidence.Sessions.Max(s => s.EndTime ?? tp.GetUtcNow().UtcDateTime));
}
/// <summary>

View File

@@ -273,7 +273,9 @@ public sealed record CollapsedStack
/// Parses a collapsed stack line.
/// Format: "container@digest;buildid=xxx;func;... count"
/// </summary>
public static CollapsedStack? Parse(string line)
/// <param name="line">The collapsed stack line to parse.</param>
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
public static CollapsedStack? Parse(string line, TimeProvider? timeProvider = null)
{
if (string.IsNullOrWhiteSpace(line))
return null;
@@ -305,7 +307,8 @@ public sealed record CollapsedStack
}
}
var now = DateTime.UtcNow;
var tp = timeProvider ?? TimeProvider.System;
var now = tp.GetUtcNow().UtcDateTime;
return new CollapsedStack
{
ContainerIdentifier = container,

View File

@@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Principal;
using System.Text.RegularExpressions;
using StellaOps.Determinism;
namespace StellaOps.Scanner.Analyzers.Native.RuntimeCapture;
@@ -21,6 +22,8 @@ namespace StellaOps.Scanner.Analyzers.Native.RuntimeCapture;
[SupportedOSPlatform("windows")]
public sealed class WindowsEtwCaptureAdapter : IRuntimeCaptureAdapter
{
private readonly TimeProvider _timeProvider;
private readonly IGuidProvider _guidProvider;
private readonly ConcurrentBag<RuntimeLoadEvent> _events = [];
private readonly object _stateLock = new();
private CaptureState _state = CaptureState.Idle;
@@ -34,6 +37,17 @@ public sealed class WindowsEtwCaptureAdapter : IRuntimeCaptureAdapter
private long _droppedEvents;
private int _redactedPaths;
/// <summary>
/// Creates a new Windows ETW capture adapter.
/// </summary>
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
/// <param name="guidProvider">Optional GUID provider for deterministic session IDs.</param>
public WindowsEtwCaptureAdapter(TimeProvider? timeProvider = null, IGuidProvider? guidProvider = null)
{
_timeProvider = timeProvider ?? TimeProvider.System;
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
}
/// <inheritdoc />
public string AdapterId => "windows-etw-imageload";
@@ -146,8 +160,8 @@ public sealed class WindowsEtwCaptureAdapter : IRuntimeCaptureAdapter
_events.Clear();
_droppedEvents = 0;
_redactedPaths = 0;
SessionId = Guid.NewGuid().ToString("N");
_startTime = DateTime.UtcNow;
SessionId = _guidProvider.NewGuid().ToString("N");
_startTime = _timeProvider.GetUtcNow().UtcDateTime;
_captureCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
try
@@ -240,7 +254,7 @@ public sealed class WindowsEtwCaptureAdapter : IRuntimeCaptureAdapter
var session = new RuntimeCaptureSession(
SessionId: SessionId ?? "unknown",
StartTime: _startTime,
EndTime: DateTime.UtcNow,
EndTime: _timeProvider.GetUtcNow().UtcDateTime,
Platform: Platform,
CaptureMethod: CaptureMethod,
TargetProcessId: _options?.TargetProcessId,
@@ -480,7 +494,7 @@ public sealed class WindowsEtwCaptureAdapter : IRuntimeCaptureAdapter
: RuntimeLoadType.LoadLibrary;
var evt = new RuntimeLoadEvent(
Timestamp: DateTime.UtcNow,
Timestamp: _timeProvider.GetUtcNow().UtcDateTime,
ProcessId: processId,
ThreadId: 0,
LoadType: loadType,

View File

@@ -15,6 +15,7 @@
<ItemGroup>
<ProjectReference Include="..\\__Libraries\\StellaOps.Scanner.ProofSpine\\StellaOps.Scanner.ProofSpine.csproj" />
<ProjectReference Include="..\\..\\__Libraries\\StellaOps.Determinism.Abstractions\\StellaOps.Determinism.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>