Add tests and implement timeline ingestion options with NATS and Redis subscribers

- Introduced `BinaryReachabilityLifterTests` to validate binary lifting functionality.
- Created `PackRunWorkerOptions` for configuring worker paths and execution persistence.
- Added `TimelineIngestionOptions` for configuring NATS and Redis ingestion transports.
- Implemented `NatsTimelineEventSubscriber` for subscribing to NATS events.
- Developed `RedisTimelineEventSubscriber` for reading from Redis Streams.
- Added `TimelineEnvelopeParser` to normalize incoming event envelopes.
- Created unit tests for `TimelineEnvelopeParser` to ensure correct field mapping.
- Implemented `TimelineAuthorizationAuditSink` for logging authorization outcomes.
This commit is contained in:
StellaOps Bot
2025-12-03 09:46:48 +02:00
parent e923880694
commit 35c8f9216f
520 changed files with 4416 additions and 31492 deletions

View File

@@ -0,0 +1,62 @@
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using StellaOps.Scanner.Reachability;
using StellaOps.Scanner.Reachability.Lifters;
using Xunit;
namespace StellaOps.Scanner.Reachability.Tests;
public class BinaryReachabilityLifterTests
{
[Fact]
public async Task EmitsSymbolAndCodeIdForBinary()
{
using var temp = new TempDir();
var binaryPath = System.IO.Path.Combine(temp.Path, "sample.so");
var bytes = CreateMinimalElf();
await System.IO.File.WriteAllBytesAsync(binaryPath, bytes);
var context = new ReachabilityLifterContext
{
RootPath = temp.Path,
AnalysisId = "analysis-42"
};
var builder = new ReachabilityGraphBuilder();
var lifter = new BinaryReachabilityLifter();
await lifter.LiftAsync(context, builder, CancellationToken.None);
var graph = builder.ToUnionGraph(SymbolId.Lang.Binary);
var node = Assert.Single(graph.Nodes);
Assert.Equal(SymbolId.Lang.Binary, node.Lang);
var shaHex = Convert.ToHexString(SHA256.HashData(bytes)).ToLowerInvariant();
var expectedSymbolId = SymbolId.ForBinaryAddressed($"sha256:{shaHex}", ".text", "0x0", "sample.so", "static");
Assert.Equal(expectedSymbolId, node.SymbolId);
Assert.NotNull(node.Attributes);
var expectedCodeId = CodeId.ForBinarySegment("elf", $"sha256:{shaHex}", "0x0", bytes.LongLength, ".text");
Assert.Equal(expectedCodeId, node.Attributes!["code_id"]);
var rich = RichGraphBuilder.FromUnion(graph, "test-analyzer", "1.0.0");
var richNode = Assert.Single(rich.Nodes);
Assert.Equal(expectedCodeId, richNode.CodeId);
}
private static byte[] CreateMinimalElf()
{
var data = new byte[64];
data[0] = 0x7F;
data[1] = (byte)'E';
data[2] = (byte)'L';
data[3] = (byte)'F';
data[4] = 2; // 64-bit
data[5] = 1; // little endian
data[7] = 0; // System V ABI
data[18] = 0x3E; // EM_X86_64
data[19] = 0x00;
return data;
}
}

View File

@@ -21,7 +21,7 @@ public class RichGraphPublisherTests
var rich = RichGraphBuilder.FromUnion(union, "test", "1.0.0");
var result = await publisher.PublishAsync(rich, "scan-1", cas, temp.Path);
Assert.StartsWith("blake3:", result.GraphHash);
Assert.StartsWith("sha256:", result.GraphHash);
Assert.Equal(1, result.NodeCount);
}
}