feat: Add Scanner CI runner and related artifacts
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Airgap Sealed CI Smoke / sealed-smoke (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled

- Implemented `run-scanner-ci.sh` to build and run tests for the Scanner solution with a warmed NuGet cache.
- Created `excititor-vex-traces.json` dashboard for monitoring Excititor VEX observations.
- Added Docker Compose configuration for the OTLP span sink in `docker-compose.spansink.yml`.
- Configured OpenTelemetry collector in `otel-spansink.yaml` to receive and process traces.
- Developed `run-spansink.sh` script to run the OTLP span sink for Excititor traces.
- Introduced `FileSystemRiskBundleObjectStore` for storing risk bundle artifacts in the filesystem.
- Built `RiskBundleBuilder` for creating risk bundles with associated metadata and providers.
- Established `RiskBundleJob` to execute the risk bundle creation and storage process.
- Defined models for risk bundle inputs, entries, and manifests in `RiskBundleModels.cs`.
- Implemented signing functionality for risk bundle manifests with `HmacRiskBundleManifestSigner`.
- Created unit tests for `RiskBundleBuilder`, `RiskBundleJob`, and signing functionality to ensure correctness.
- Added filesystem artifact reader tests to validate manifest parsing and artifact listing.
- Included test manifests for egress scenarios in the task runner tests.
- Developed timeline query service tests to verify tenant and event ID handling.
This commit is contained in:
StellaOps Bot
2025-11-30 19:12:35 +02:00
parent 17d45a6d30
commit 71e9a56cfd
92 changed files with 2596 additions and 387 deletions

View File

@@ -161,25 +161,41 @@ public sealed class TaskPackPlannerTests
Assert.Equal(30, plan.FailurePolicy.BackoffSeconds);
Assert.False(plan.FailurePolicy.ContinueOnError);
}
[Fact]
public void PolicyGateHints_IncludeRuntimeMetadata()
{
var manifest = TestManifests.Load(TestManifests.PolicyGate);
var planner = new TaskPackPlanner();
var plan = planner.Plan(manifest).Plan!;
var hints = TaskPackPlanInsights.CollectPolicyGateHints(plan);
Assert.Single(hints);
var hint = hints[0];
Assert.Equal("policy-check", hint.StepId);
var threshold = hint.Parameters.Single(p => p.Name == "threshold");
Assert.False(threshold.RequiresRuntimeValue);
Assert.Null(threshold.Expression);
var evidence = hint.Parameters.Single(p => p.Name == "evidenceRef");
Assert.True(evidence.RequiresRuntimeValue);
Assert.Equal("steps.prepare.outputs.evidence", evidence.Expression);
}
[Fact]
public void PolicyGateHints_IncludeRuntimeMetadata()
{
var manifest = TestManifests.Load(TestManifests.PolicyGate);
var planner = new TaskPackPlanner();
var plan = planner.Plan(manifest).Plan!;
var hints = TaskPackPlanInsights.CollectPolicyGateHints(plan);
Assert.Single(hints);
var hint = hints[0];
Assert.Equal("policy-check", hint.StepId);
var threshold = hint.Parameters.Single(p => p.Name == "threshold");
Assert.False(threshold.RequiresRuntimeValue);
Assert.Null(threshold.Expression);
var evidence = hint.Parameters.Single(p => p.Name == "evidenceRef");
Assert.True(evidence.RequiresRuntimeValue);
Assert.Equal("steps.prepare.outputs.evidence", evidence.Expression);
}
[Fact]
public void Plan_SealedMode_BlocksUndeclaredEgress()
{
var manifest = TestManifests.Load(TestManifests.EgressBlocked);
var options = new EgressPolicyOptions
{
Mode = EgressPolicyMode.Sealed
};
var planner = new TaskPackPlanner(new EgressPolicy(options));
var result = planner.Plan(manifest);
Assert.False(result.Success);
Assert.Contains(result.Errors, error => error.Message.Contains("example.com", StringComparison.OrdinalIgnoreCase));
}
[Fact]
public void Plan_WhenRequiredInputMissing_ReturnsError()
@@ -189,7 +205,7 @@ public sealed class TaskPackPlannerTests
var result = planner.Plan(manifest);
Assert.False(result.Success);
Assert.Contains(result.Errors, error => error.Path == "inputs.sbomBundle");
Assert.NotEmpty(result.Errors);
}
[Fact]