310 lines
8.5 KiB
C#
310 lines
8.5 KiB
C#
// <copyright file="RuntimeCallEvent.cs" company="StellaOps">
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
// </copyright>
|
|
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace StellaOps.Signals.Ebpf.Schema;
|
|
|
|
|
|
/// <summary>
|
|
/// Event emitted when a function call is observed via eBPF.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This record is the deserialized form of events from the eBPF ring buffer.
|
|
/// The schema is designed for efficient serialization and deterministic ordering.
|
|
/// </remarks>
|
|
public sealed record RuntimeCallEvent
|
|
{
|
|
/// <summary>
|
|
/// Unique event identifier.
|
|
/// </summary>
|
|
public required Guid EventId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Container ID where the call was observed.
|
|
/// </summary>
|
|
public required string ContainerId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Process ID within the container.
|
|
/// </summary>
|
|
public required int Pid { get; init; }
|
|
|
|
/// <summary>
|
|
/// Thread ID.
|
|
/// </summary>
|
|
public required int Tid { get; init; }
|
|
|
|
/// <summary>
|
|
/// Timestamp in nanoseconds since boot.
|
|
/// </summary>
|
|
public required ulong TimestampNs { get; init; }
|
|
|
|
/// <summary>
|
|
/// Called function symbol name (if resolved).
|
|
/// </summary>
|
|
public string? Symbol { get; init; }
|
|
|
|
/// <summary>
|
|
/// Called function address.
|
|
/// </summary>
|
|
public required ulong FunctionAddress { get; init; }
|
|
|
|
/// <summary>
|
|
/// Call stack (addresses from bottom to top).
|
|
/// </summary>
|
|
public required IReadOnlyList<ulong> StackTrace { get; init; }
|
|
|
|
/// <summary>
|
|
/// Runtime type (native, jvm, node, python, dotnet, go).
|
|
/// </summary>
|
|
public required RuntimeType RuntimeType { get; init; }
|
|
|
|
/// <summary>
|
|
/// Library/module containing the function.
|
|
/// </summary>
|
|
public string? Library { get; init; }
|
|
|
|
/// <summary>
|
|
/// Package URL if resolvable.
|
|
/// </summary>
|
|
public string? Purl { get; init; }
|
|
|
|
/// <summary>
|
|
/// UTC timestamp when this event was received by the collector.
|
|
/// </summary>
|
|
public DateTimeOffset ReceivedAt { get; init; } = DateTimeOffset.UtcNow;
|
|
|
|
// --- Sprint: SPRINT_20260112_005_SIGNALS_runtime_nodehash (PW-SIG-001) ---
|
|
|
|
/// <summary>
|
|
/// Fully qualified function signature (namespace.type.method(params)).
|
|
/// </summary>
|
|
public string? FunctionSignature { get; init; }
|
|
|
|
/// <summary>
|
|
/// SHA256 digest of the binary containing this function.
|
|
/// </summary>
|
|
public string? BinaryDigest { get; init; }
|
|
|
|
/// <summary>
|
|
/// Offset within the binary where the function is located.
|
|
/// </summary>
|
|
public ulong? BinaryOffset { get; init; }
|
|
|
|
/// <summary>
|
|
/// Canonical node hash (sha256:hex) for static/runtime evidence joining.
|
|
/// Computed using NodeHashRecipe from PURL + FunctionSignature.
|
|
/// </summary>
|
|
public string? NodeHash { get; init; }
|
|
|
|
/// <summary>
|
|
/// SHA256 hash of the callstack for deterministic aggregation.
|
|
/// </summary>
|
|
public string? CallstackHash { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runtime type detected from process characteristics.
|
|
/// </summary>
|
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
|
public enum RuntimeType
|
|
{
|
|
/// <summary>Native binary (ELF/PE/Mach-O).</summary>
|
|
Native = 0,
|
|
|
|
/// <summary>Java Virtual Machine.</summary>
|
|
Jvm = 1,
|
|
|
|
/// <summary>Node.js / V8.</summary>
|
|
Node = 2,
|
|
|
|
/// <summary>Python interpreter.</summary>
|
|
Python = 3,
|
|
|
|
/// <summary>.NET runtime (CoreCLR).</summary>
|
|
DotNet = 4,
|
|
|
|
/// <summary>Go runtime.</summary>
|
|
Go = 5,
|
|
|
|
/// <summary>Ruby interpreter.</summary>
|
|
Ruby = 6,
|
|
|
|
/// <summary>Unknown or unidentified runtime.</summary>
|
|
Unknown = 255,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Observed call path from runtime signals.
|
|
/// </summary>
|
|
public sealed record ObservedCallPath
|
|
{
|
|
/// <summary>
|
|
/// Symbols in the call path (entry point to vulnerable function).
|
|
/// </summary>
|
|
public required IReadOnlyList<string> Symbols { get; init; }
|
|
|
|
/// <summary>
|
|
/// Number of times this path was observed.
|
|
/// </summary>
|
|
public required int ObservationCount { get; init; }
|
|
|
|
/// <summary>
|
|
/// Package URL if resolvable.
|
|
/// </summary>
|
|
public string? Purl { get; init; }
|
|
|
|
/// <summary>
|
|
/// Runtime type where this path was observed.
|
|
/// </summary>
|
|
public RuntimeType RuntimeType { get; init; } = RuntimeType.Unknown;
|
|
|
|
/// <summary>
|
|
/// First observation timestamp.
|
|
/// </summary>
|
|
public DateTimeOffset FirstObservedAt { get; init; }
|
|
|
|
/// <summary>
|
|
/// Last observation timestamp.
|
|
/// </summary>
|
|
public DateTimeOffset LastObservedAt { get; init; }
|
|
|
|
// --- Sprint: SPRINT_20260112_005_SIGNALS_runtime_nodehash (PW-SIG-001) ---
|
|
|
|
/// <summary>
|
|
/// Canonical node hashes for each symbol in the path (deterministic order).
|
|
/// </summary>
|
|
public IReadOnlyList<string>? NodeHashes { get; init; }
|
|
|
|
/// <summary>
|
|
/// Canonical path hash (sha256:hex) computed from ordered node hashes.
|
|
/// </summary>
|
|
public string? PathHash { get; init; }
|
|
|
|
/// <summary>
|
|
/// Callstack hash for efficient deduplication.
|
|
/// </summary>
|
|
public string? CallstackHash { get; init; }
|
|
|
|
/// <summary>
|
|
/// Function signatures for each symbol in the path.
|
|
/// </summary>
|
|
public IReadOnlyList<string>? FunctionSignatures { get; init; }
|
|
|
|
/// <summary>
|
|
/// Binary digests for each symbol in the path (null if not resolvable).
|
|
/// </summary>
|
|
public IReadOnlyList<string?>? BinaryDigests { get; init; }
|
|
|
|
/// <summary>
|
|
/// Binary offsets for each symbol in the path (null if not resolvable).
|
|
/// </summary>
|
|
public IReadOnlyList<ulong?>? BinaryOffsets { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Summary of runtime signals collected for a container.
|
|
/// </summary>
|
|
public sealed record RuntimeSignalSummary
|
|
{
|
|
/// <summary>
|
|
/// Container ID.
|
|
/// </summary>
|
|
public required string ContainerId { get; init; }
|
|
|
|
/// <summary>
|
|
/// When signal collection started.
|
|
/// </summary>
|
|
public required DateTimeOffset StartedAt { get; init; }
|
|
|
|
/// <summary>
|
|
/// When signal collection stopped.
|
|
/// </summary>
|
|
public required DateTimeOffset StoppedAt { get; init; }
|
|
|
|
/// <summary>
|
|
/// Total events captured.
|
|
/// </summary>
|
|
public required long TotalEvents { get; init; }
|
|
|
|
/// <summary>
|
|
/// Aggregated call paths.
|
|
/// </summary>
|
|
public required IReadOnlyList<ObservedCallPath> CallPaths { get; init; }
|
|
|
|
/// <summary>
|
|
/// Unique symbols observed.
|
|
/// </summary>
|
|
public required IReadOnlyList<string> ObservedSymbols { get; init; }
|
|
|
|
/// <summary>
|
|
/// Events that were dropped due to rate limiting.
|
|
/// </summary>
|
|
public long DroppedEvents { get; init; }
|
|
|
|
/// <summary>
|
|
/// Runtime types detected in this container.
|
|
/// </summary>
|
|
public IReadOnlyList<RuntimeType> DetectedRuntimes { get; init; } = [];
|
|
|
|
// --- Sprint: SPRINT_20260112_005_SIGNALS_runtime_nodehash (PW-SIG-004) ---
|
|
|
|
/// <summary>
|
|
/// Unique node hashes observed in this summary (deterministic sorted order).
|
|
/// </summary>
|
|
public IReadOnlyList<string>? ObservedNodeHashes { get; init; }
|
|
|
|
/// <summary>
|
|
/// Unique path hashes for all observed call paths (deterministic sorted order).
|
|
/// </summary>
|
|
public IReadOnlyList<string>? ObservedPathHashes { get; init; }
|
|
|
|
/// <summary>
|
|
/// Combined hash of all observed paths for summary-level identity.
|
|
/// </summary>
|
|
public string? CombinedPathHash { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Statistics about signal collection.
|
|
/// </summary>
|
|
public sealed record SignalStatistics
|
|
{
|
|
/// <summary>
|
|
/// Total events received.
|
|
/// </summary>
|
|
public required long TotalEvents { get; init; }
|
|
|
|
/// <summary>
|
|
/// Events per second (current rate).
|
|
/// </summary>
|
|
public required double EventsPerSecond { get; init; }
|
|
|
|
/// <summary>
|
|
/// Unique call paths observed.
|
|
/// </summary>
|
|
public required int UniqueCallPaths { get; init; }
|
|
|
|
/// <summary>
|
|
/// Ring buffer utilization percentage.
|
|
/// </summary>
|
|
public required double BufferUtilization { get; init; }
|
|
|
|
/// <summary>
|
|
/// Events dropped due to rate limiting.
|
|
/// </summary>
|
|
public required long DroppedEvents { get; init; }
|
|
|
|
/// <summary>
|
|
/// CPU overhead percentage from eBPF probes.
|
|
/// </summary>
|
|
public double CpuOverheadPercent { get; init; }
|
|
|
|
/// <summary>
|
|
/// Memory usage in bytes for signal collection.
|
|
/// </summary>
|
|
public long MemoryUsageBytes { get; init; }
|
|
}
|