feat: Add UI benchmark driver and scenarios for graph interactions
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
Policy Lint & Smoke / policy-lint (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled

- Introduced `ui_bench_driver.mjs` to read scenarios and fixture manifest, generating a deterministic run plan.
- Created `ui_bench_plan.md` outlining the purpose, scope, and next steps for the benchmark.
- Added `ui_bench_scenarios.json` containing various scenarios for graph UI interactions.
- Implemented tests for CLI commands, ensuring bundle verification and telemetry defaults.
- Developed schemas for orchestrator components, including replay manifests and event envelopes.
- Added mock API for risk management, including listing and statistics functionalities.
- Implemented models for risk profiles and query options to support the new API.
This commit is contained in:
StellaOps Bot
2025-12-02 01:28:17 +02:00
parent 909d9b6220
commit 44171930ff
94 changed files with 3606 additions and 271 deletions

View File

@@ -48,17 +48,43 @@ namespace StellaOps.Cli.Commands;
internal static class CommandHandlers
{
private const string KmsPassphraseEnvironmentVariable = "STELLAOPS_KMS_PASSPHRASE";
private static readonly JsonSerializerOptions KmsJsonOptions = new(JsonSerializerDefaults.Web)
{
WriteIndented = true
};
private static readonly JsonSerializerOptions KmsJsonOptions = new(JsonSerializerDefaults.Web)
{
WriteIndented = true
};
private static async Task VerifyBundleAsync(string path, ILogger logger, CancellationToken cancellationToken)
{
// Simple SHA256 check using sidecar .sha256 file if present; fail closed on mismatch.
var shaPath = path + ".sha256";
if (!File.Exists(shaPath))
{
logger.LogError("Checksum file missing for bundle {Bundle}. Expected sidecar {Sidecar}.", path, shaPath);
Environment.ExitCode = 21;
throw new InvalidOperationException("Checksum file missing");
}
var expected = (await File.ReadAllTextAsync(shaPath, cancellationToken).ConfigureAwait(false)).Trim();
using var stream = File.OpenRead(path);
var hash = await SHA256.HashDataAsync(stream, cancellationToken).ConfigureAwait(false);
var actual = Convert.ToHexString(hash).ToLowerInvariant();
if (!string.Equals(expected, actual, StringComparison.OrdinalIgnoreCase))
{
logger.LogError("Checksum mismatch for {Bundle}. Expected {Expected} but found {Actual}", path, expected, actual);
Environment.ExitCode = 22;
throw new InvalidOperationException("Checksum verification failed");
}
logger.LogInformation("Checksum verified for {Bundle}", path);
}
public static async Task HandleScannerDownloadAsync(
IServiceProvider services,
string channel,
string? output,
bool overwrite,
bool install,
public static async Task HandleScannerDownloadAsync(
IServiceProvider services,
string channel,
string? output,
bool overwrite,
bool install,
bool verbose,
CancellationToken cancellationToken)
{
@@ -88,24 +114,29 @@ internal static class CommandHandlers
CliMetrics.RecordScannerDownload(channel, result.FromCache);
if (install)
{
var installer = scope.ServiceProvider.GetRequiredService<IScannerInstaller>();
await installer.InstallAsync(result.Path, verbose, cancellationToken).ConfigureAwait(false);
CliMetrics.RecordScannerInstall(channel);
}
if (install)
{
await VerifyBundleAsync(result.Path, logger, cancellationToken).ConfigureAwait(false);
var installer = scope.ServiceProvider.GetRequiredService<IScannerInstaller>();
await installer.InstallAsync(result.Path, verbose, cancellationToken).ConfigureAwait(false);
CliMetrics.RecordScannerInstall(channel);
}
Environment.ExitCode = 0;
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to download scanner bundle.");
Environment.ExitCode = 1;
}
finally
{
verbosity.MinimumLevel = previousLevel;
}
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to download scanner bundle.");
if (Environment.ExitCode == 0)
{
Environment.ExitCode = 1;
}
}
finally
{
verbosity.MinimumLevel = previousLevel;
}
}
public static async Task HandleTaskRunnerSimulateAsync(