feat: Add VEX Lens CI and Load Testing Plan
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled

- Introduced a comprehensive CI job structure for VEX Lens, including build, test, linting, and load testing.
- Defined load test parameters and SLOs for VEX Lens API and Issuer Directory.
- Created Grafana dashboards and alerting mechanisms for monitoring API performance and error rates.
- Established offline posture guidelines for CI jobs and load testing.

feat: Implement deterministic projection verification script

- Added `verify_projection.sh` script for verifying the integrity of projection exports against expected hashes.
- Ensured robust error handling for missing files and hash mismatches.

feat: Develop Vuln Explorer CI and Ops Plan

- Created CI jobs for Vuln Explorer, including build, test, and replay verification.
- Implemented backup and disaster recovery strategies for MongoDB and Redis.
- Established Merkle anchoring verification and automation for ledger projector.

feat: Introduce EventEnvelopeHasher for hashing event envelopes

- Implemented `EventEnvelopeHasher` to compute SHA256 hashes for event envelopes.

feat: Add Risk Store and Dashboard components

- Developed `RiskStore` for managing risk data and state.
- Created `RiskDashboardComponent` for displaying risk profiles with filtering capabilities.
- Implemented unit tests for `RiskStore` and `RiskDashboardComponent`.

feat: Enhance Vulnerability Detail Component

- Developed `VulnerabilityDetailComponent` for displaying detailed information about vulnerabilities.
- Implemented error handling for missing vulnerability IDs and loading failures.
This commit is contained in:
StellaOps Bot
2025-12-02 07:18:28 +02:00
parent 44171930ff
commit 885ce86af4
83 changed files with 2090 additions and 97 deletions

View File

@@ -2,6 +2,8 @@ using System.Collections.Immutable;
using System.Text.Json.Serialization;
namespace StellaOps.Orchestrator.Core;
using System.Text.Json;
using System.Text.Json.Serialization;
public sealed record EventEnvelope(
[property: JsonPropertyName("schemaVersion")] string SchemaVersion,

View File

@@ -26,7 +26,8 @@ public static class CanonicalJsonHasher
public static string ToCanonicalJson<T>(T value)
{
var node = JsonSerializer.SerializeToNode(value, SerializerOptions) ?? new JsonObject();
var ordered = OrderNode(node);
// Work on a detached copy to avoid parent conflicts.
var ordered = OrderNode(node.Clone());
return ordered.ToJsonString(SerializerOptions);
}
@@ -49,18 +50,18 @@ public static class CanonicalJsonHasher
var orderedObj = new JsonObject();
foreach (var kvp in obj.OrderBy(x => x.Key, StringComparer.Ordinal))
{
orderedObj.Add(kvp.Key, kvp.Value is null ? null : OrderNode(kvp.Value));
orderedObj.Add(kvp.Key, kvp.Value is null ? null : OrderNode(kvp.Value.Clone()));
}
return orderedObj;
case JsonArray arr:
var orderedArr = new JsonArray();
foreach (var item in arr)
{
orderedArr.Add(item is null ? null : OrderNode(item));
orderedArr.Add(item is null ? null : OrderNode(item.Clone()));
}
return orderedArr;
default:
return node; // primitives stay as-is
return node.Clone(); // primitives stay as-is
}
}
}

View File

@@ -0,0 +1,12 @@
using StellaOps.Orchestrator.Core.Domain.Events;
namespace StellaOps.Orchestrator.Core.Hashing;
public static class EventEnvelopeHasher
{
public static string Compute(EventEnvelope envelope)
{
ArgumentNullException.ThrowIfNull(envelope);
return CanonicalJsonHasher.ComputeCanonicalSha256(envelope);
}
}

View File

@@ -1,6 +1,7 @@
using System.Collections.Immutable;
using System.Text.Json;
using StellaOps.Orchestrator.Core;
using StellaOps.Orchestrator.Core.Hashing;
namespace StellaOps.Orchestrator.Tests;
@@ -52,4 +53,40 @@ public class EventEnvelopeTests
Assert.Equal(envelope.Job.Id, roundtrip.Job.Id);
Assert.Equal(envelope.Actor.Subject, roundtrip.Actor.Subject);
}
[Fact]
public void Hash_IsDeterministic()
{
var job = new EventJob(
Id: "job_123",
Type: "pack-run",
RunId: "run_123",
Attempt: 1,
LeaseId: "lease_1",
TaskRunnerId: "tr_9",
Status: "scheduled",
Reason: null,
PayloadDigest: "sha256:deadbeef",
Artifacts: ImmutableArray.Create<EventArtifact>(),
Provenance: ImmutableDictionary<string, string>.Empty);
var actor = new EventActor("worker-sdk-go", ImmutableArray.Create("orch:quota"));
var envelope = EventEnvelope.Create(
eventType: "job.scheduled",
tenantId: "tenant-alpha",
job: job,
actor: actor,
projectId: "proj-1",
correlationId: "corr-123",
occurredAt: new DateTimeOffset(2025, 12, 1, 12, 0, 0, TimeSpan.Zero),
eventId: "evt-fixed",
idempotencyKey: "fixed-key");
var hash1 = EventEnvelopeHasher.Compute(envelope);
var hash2 = EventEnvelopeHasher.Compute(envelope);
Assert.Equal(hash1, hash2);
Assert.Equal(64, hash1.Length);
}
}