Files
StellaOps Bot 71e9a56cfd
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
feat: Add Scanner CI runner and related artifacts
- 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.
2025-11-30 19:12:35 +02:00

108 lines
3.5 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using StellaOps.Auth.Abstractions;
using StellaOps.Auth.ServerIntegration;
using StellaOps.TimelineIndexer.Core.Abstractions;
using StellaOps.TimelineIndexer.Core.Models;
using StellaOps.TimelineIndexer.Infrastructure.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
builder.Configuration.AddJsonFile("appsettings.Development.json", optional: true, reloadOnChange: true);
builder.Configuration.AddEnvironmentVariables(prefix: "TIMELINE_");
builder.Services.AddTimelineIndexerPostgres(builder.Configuration);
builder.Services.AddStellaOpsResourceServerAuthentication(
builder.Configuration,
configure: options =>
{
options.RequiredScopes.Clear();
});
builder.Services.AddAuthorization(options =>
{
options.AddObservabilityResourcePolicies();
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddRequirements(new StellaOpsScopeRequirement(new[] { StellaOpsScopes.TimelineRead }))
.Build();
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddOpenApi();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/timeline", async (
HttpContext ctx,
ITimelineQueryService service,
[FromQuery] string? eventType,
[FromQuery] string? correlationId,
[FromQuery] string? traceId,
[FromQuery] string? severity,
[FromQuery] DateTimeOffset? since,
[FromQuery] long? after,
[FromQuery] int? limit,
CancellationToken cancellationToken) =>
{
var tenantId = GetTenantId(ctx);
var options = new TimelineQueryOptions
{
EventType = eventType,
CorrelationId = correlationId,
TraceId = traceId,
Severity = severity,
Since = since,
AfterEventSeq = after,
Limit = limit ?? 100
};
var items = await service.QueryAsync(tenantId, options, cancellationToken).ConfigureAwait(false);
return Results.Ok(items);
})
.RequireAuthorization(StellaOpsResourceServerPolicies.TimelineRead);
app.MapGet("/timeline/{eventId}", async (
HttpContext ctx,
ITimelineQueryService service,
string eventId,
CancellationToken cancellationToken) =>
{
var tenantId = GetTenantId(ctx);
var item = await service.GetAsync(tenantId, eventId, cancellationToken).ConfigureAwait(false);
return item is null ? Results.NotFound() : Results.Ok(item);
})
.RequireAuthorization(StellaOpsResourceServerPolicies.TimelineRead);
app.MapPost("/timeline/events", () => Results.Accepted("/timeline/events", new { status = "indexed" }))
.RequireAuthorization(StellaOpsResourceServerPolicies.TimelineWrite);
app.Run();
static string GetTenantId(HttpContext ctx)
{
// Temporary: allow explicit header override; fallback to claim if present.
if (ctx.Request.Headers.TryGetValue("X-Tenant", out var header) && !string.IsNullOrWhiteSpace(header))
{
return header!;
}
var tenant = ctx.User.FindFirst("tenant")?.Value;
if (!string.IsNullOrWhiteSpace(tenant))
{
return tenant!;
}
throw new InvalidOperationException("Tenant not provided");
}