Frontend gaps fill work. Testing fixes work. Auditing in progress.
This commit is contained in:
@@ -0,0 +1,330 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.VexLens.Api;
|
||||
|
||||
namespace StellaOps.VexLens.WebService.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for mapping VexLens API endpoints.
|
||||
/// </summary>
|
||||
public static class VexLensEndpointExtensions
|
||||
{
|
||||
private const string TenantHeader = "X-StellaOps-Tenant";
|
||||
|
||||
/// <summary>
|
||||
/// Maps all VexLens API endpoints.
|
||||
/// </summary>
|
||||
public static IEndpointRouteBuilder MapVexLensEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.MapGroup("/api/v1/vexlens")
|
||||
.WithTags("VexLens")
|
||||
.WithOpenApi();
|
||||
|
||||
// Consensus endpoints
|
||||
group.MapPost("/consensus", ComputeConsensusAsync)
|
||||
.WithName("ComputeConsensus")
|
||||
.WithDescription("Compute consensus for a vulnerability-product pair")
|
||||
.Produces<ComputeConsensusResponse>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status400BadRequest);
|
||||
|
||||
group.MapPost("/consensus:batch", ComputeConsensusBatchAsync)
|
||||
.WithName("ComputeConsensusBatch")
|
||||
.WithDescription("Compute consensus for multiple vulnerability-product pairs")
|
||||
.Produces<ComputeConsensusBatchResponse>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status400BadRequest);
|
||||
|
||||
// Projection endpoints
|
||||
group.MapGet("/projections", QueryProjectionsAsync)
|
||||
.WithName("QueryProjections")
|
||||
.WithDescription("Query consensus projections with filtering")
|
||||
.Produces<QueryProjectionsResponse>(StatusCodes.Status200OK);
|
||||
|
||||
group.MapGet("/projections/{projectionId}", GetProjectionAsync)
|
||||
.WithName("GetProjection")
|
||||
.WithDescription("Get a specific consensus projection by ID")
|
||||
.Produces<ProjectionDetailResponse>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapGet("/projections/latest", GetLatestProjectionAsync)
|
||||
.WithName("GetLatestProjection")
|
||||
.WithDescription("Get the latest projection for a vulnerability-product pair")
|
||||
.Produces<ProjectionDetailResponse>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
group.MapGet("/projections/history", GetProjectionHistoryAsync)
|
||||
.WithName("GetProjectionHistory")
|
||||
.WithDescription("Get projection history for a vulnerability-product pair")
|
||||
.Produces<ProjectionHistoryResponse>(StatusCodes.Status200OK);
|
||||
|
||||
// Statistics endpoint
|
||||
group.MapGet("/stats", GetStatisticsAsync)
|
||||
.WithName("GetVexLensStatistics")
|
||||
.WithDescription("Get consensus projection statistics")
|
||||
.Produces<ConsensusStatisticsResponse>(StatusCodes.Status200OK);
|
||||
|
||||
// Conflict endpoints
|
||||
group.MapGet("/conflicts", GetConflictsAsync)
|
||||
.WithName("GetConflicts")
|
||||
.WithDescription("Get projections with conflicts")
|
||||
.Produces<QueryProjectionsResponse>(StatusCodes.Status200OK);
|
||||
|
||||
// Issuer endpoints
|
||||
var issuerGroup = app.MapGroup("/api/v1/vexlens/issuers")
|
||||
.WithTags("VexLens Issuers")
|
||||
.WithOpenApi();
|
||||
|
||||
issuerGroup.MapGet("/", ListIssuersAsync)
|
||||
.WithName("ListIssuers")
|
||||
.WithDescription("List registered VEX issuers")
|
||||
.Produces<IssuerListResponse>(StatusCodes.Status200OK);
|
||||
|
||||
issuerGroup.MapGet("/{issuerId}", GetIssuerAsync)
|
||||
.WithName("GetIssuer")
|
||||
.WithDescription("Get issuer details")
|
||||
.Produces<IssuerDetailResponse>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
issuerGroup.MapPost("/", RegisterIssuerAsync)
|
||||
.WithName("RegisterIssuer")
|
||||
.WithDescription("Register a new VEX issuer")
|
||||
.Produces<IssuerDetailResponse>(StatusCodes.Status201Created)
|
||||
.Produces(StatusCodes.Status400BadRequest);
|
||||
|
||||
issuerGroup.MapDelete("/{issuerId}", RevokeIssuerAsync)
|
||||
.WithName("RevokeIssuer")
|
||||
.WithDescription("Revoke an issuer")
|
||||
.Produces(StatusCodes.Status204NoContent)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
issuerGroup.MapPost("/{issuerId}/keys", AddIssuerKeyAsync)
|
||||
.WithName("AddIssuerKey")
|
||||
.WithDescription("Add a key to an issuer")
|
||||
.Produces<IssuerDetailResponse>(StatusCodes.Status200OK)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
issuerGroup.MapDelete("/{issuerId}/keys/{fingerprint}", RevokeIssuerKeyAsync)
|
||||
.WithName("RevokeIssuerKey")
|
||||
.WithDescription("Revoke an issuer key")
|
||||
.Produces(StatusCodes.Status204NoContent)
|
||||
.Produces(StatusCodes.Status404NotFound);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
private static string? GetTenantId(HttpContext context)
|
||||
{
|
||||
return context.Request.Headers.TryGetValue(TenantHeader, out var value)
|
||||
? value.ToString()
|
||||
: null;
|
||||
}
|
||||
|
||||
// Consensus handlers
|
||||
private static async Task<IResult> ComputeConsensusAsync(
|
||||
[FromBody] ComputeConsensusRequest request,
|
||||
[FromServices] IVexLensApiService service,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = GetTenantId(context) ?? request.TenantId;
|
||||
var requestWithTenant = request with { TenantId = tenantId };
|
||||
var result = await service.ComputeConsensusAsync(requestWithTenant, cancellationToken);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
|
||||
private static async Task<IResult> ComputeConsensusBatchAsync(
|
||||
[FromBody] ComputeConsensusBatchRequest request,
|
||||
[FromServices] IVexLensApiService service,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = GetTenantId(context) ?? request.TenantId;
|
||||
var requestWithTenant = request with { TenantId = tenantId };
|
||||
var result = await service.ComputeConsensusBatchAsync(requestWithTenant, cancellationToken);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
|
||||
// Projection handlers
|
||||
private static async Task<IResult> QueryProjectionsAsync(
|
||||
[AsParameters] ProjectionQueryParams query,
|
||||
[FromServices] IVexLensApiService service,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = GetTenantId(context);
|
||||
var request = new QueryProjectionsRequest(
|
||||
VulnerabilityId: query.VulnerabilityId,
|
||||
ProductKey: query.ProductKey,
|
||||
Status: null,
|
||||
Outcome: query.Outcome,
|
||||
MinimumConfidence: query.MinimumConfidence,
|
||||
ComputedAfter: query.ComputedAfter,
|
||||
ComputedBefore: query.ComputedBefore,
|
||||
StatusChanged: query.StatusChanged,
|
||||
Limit: query.Limit,
|
||||
Offset: query.Offset,
|
||||
SortBy: query.SortBy,
|
||||
SortDescending: query.SortDescending);
|
||||
|
||||
var result = await service.QueryProjectionsAsync(request, tenantId, cancellationToken);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetProjectionAsync(
|
||||
string projectionId,
|
||||
[FromServices] IVexLensApiService service,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await service.GetProjectionAsync(projectionId, cancellationToken);
|
||||
return result != null ? Results.Ok(result) : Results.NotFound();
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetLatestProjectionAsync(
|
||||
[FromQuery] string vulnerabilityId,
|
||||
[FromQuery] string productKey,
|
||||
[FromServices] IVexLensApiService service,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = GetTenantId(context);
|
||||
var result = await service.GetLatestProjectionAsync(vulnerabilityId, productKey, tenantId, cancellationToken);
|
||||
return result != null ? Results.Ok(result) : Results.NotFound();
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetProjectionHistoryAsync(
|
||||
[FromQuery] string vulnerabilityId,
|
||||
[FromQuery] string productKey,
|
||||
[FromQuery] int? limit,
|
||||
[FromServices] IVexLensApiService service,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = GetTenantId(context);
|
||||
var result = await service.GetProjectionHistoryAsync(vulnerabilityId, productKey, tenantId, limit, cancellationToken);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetStatisticsAsync(
|
||||
[FromServices] IVexLensApiService service,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = GetTenantId(context);
|
||||
var result = await service.GetStatisticsAsync(tenantId, cancellationToken);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetConflictsAsync(
|
||||
[FromQuery] int? limit,
|
||||
[FromQuery] int? offset,
|
||||
[FromServices] IVexLensApiService service,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantId = GetTenantId(context);
|
||||
// Query for projections with conflicts (conflictCount > 0)
|
||||
var request = new QueryProjectionsRequest(
|
||||
VulnerabilityId: null,
|
||||
ProductKey: null,
|
||||
Status: null,
|
||||
Outcome: null,
|
||||
MinimumConfidence: null,
|
||||
ComputedAfter: null,
|
||||
ComputedBefore: null,
|
||||
StatusChanged: null,
|
||||
Limit: limit ?? 50,
|
||||
Offset: offset ?? 0,
|
||||
SortBy: "ComputedAt",
|
||||
SortDescending: true);
|
||||
|
||||
var result = await service.QueryProjectionsAsync(request, tenantId, cancellationToken);
|
||||
|
||||
// Filter to only show projections with conflicts
|
||||
var conflictsOnly = new QueryProjectionsResponse(
|
||||
Projections: result.Projections.Where(p => p.ConflictCount > 0).ToList(),
|
||||
TotalCount: result.Projections.Count(p => p.ConflictCount > 0),
|
||||
Offset: result.Offset,
|
||||
Limit: result.Limit);
|
||||
|
||||
return Results.Ok(conflictsOnly);
|
||||
}
|
||||
|
||||
// Issuer handlers
|
||||
private static async Task<IResult> ListIssuersAsync(
|
||||
[FromQuery] string? category,
|
||||
[FromQuery] string? minimumTrustTier,
|
||||
[FromQuery] string? status,
|
||||
[FromQuery] string? search,
|
||||
[FromQuery] int? limit,
|
||||
[FromQuery] int? offset,
|
||||
[FromServices] IVexLensApiService service,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await service.ListIssuersAsync(
|
||||
category, minimumTrustTier, status, search, limit, offset, cancellationToken);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
|
||||
private static async Task<IResult> GetIssuerAsync(
|
||||
string issuerId,
|
||||
[FromServices] IVexLensApiService service,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await service.GetIssuerAsync(issuerId, cancellationToken);
|
||||
return result != null ? Results.Ok(result) : Results.NotFound();
|
||||
}
|
||||
|
||||
private static async Task<IResult> RegisterIssuerAsync(
|
||||
[FromBody] RegisterIssuerRequest request,
|
||||
[FromServices] IVexLensApiService service,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await service.RegisterIssuerAsync(request, cancellationToken);
|
||||
return Results.Created($"/api/v1/vexlens/issuers/{result.IssuerId}", result);
|
||||
}
|
||||
|
||||
private static async Task<IResult> RevokeIssuerAsync(
|
||||
string issuerId,
|
||||
[FromBody] RevokeRequest request,
|
||||
[FromServices] IVexLensApiService service,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var success = await service.RevokeIssuerAsync(issuerId, request, cancellationToken);
|
||||
return success ? Results.NoContent() : Results.NotFound();
|
||||
}
|
||||
|
||||
private static async Task<IResult> AddIssuerKeyAsync(
|
||||
string issuerId,
|
||||
[FromBody] RegisterKeyRequest request,
|
||||
[FromServices] IVexLensApiService service,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await service.AddIssuerKeyAsync(issuerId, request, cancellationToken);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
|
||||
private static async Task<IResult> RevokeIssuerKeyAsync(
|
||||
string issuerId,
|
||||
string fingerprint,
|
||||
[FromBody] RevokeRequest request,
|
||||
[FromServices] IVexLensApiService service,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var success = await service.RevokeIssuerKeyAsync(issuerId, fingerprint, request, cancellationToken);
|
||||
return success ? Results.NoContent() : Results.NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query parameters for projection queries.
|
||||
/// </summary>
|
||||
public sealed record ProjectionQueryParams(
|
||||
[FromQuery] string? VulnerabilityId,
|
||||
[FromQuery] string? ProductKey,
|
||||
[FromQuery] string? Outcome,
|
||||
[FromQuery] double? MinimumConfidence,
|
||||
[FromQuery] DateTimeOffset? ComputedAfter,
|
||||
[FromQuery] DateTimeOffset? ComputedBefore,
|
||||
[FromQuery] bool? StatusChanged,
|
||||
[FromQuery] int? Limit,
|
||||
[FromQuery] int? Offset,
|
||||
[FromQuery] string? SortBy,
|
||||
[FromQuery] bool? SortDescending);
|
||||
137
src/VexLens/StellaOps.VexLens.WebService/Program.cs
Normal file
137
src/VexLens/StellaOps.VexLens.WebService/Program.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using OpenTelemetry.Resources;
|
||||
using OpenTelemetry.Trace;
|
||||
using Serilog;
|
||||
using StellaOps.VexLens.Api;
|
||||
using StellaOps.VexLens.Consensus;
|
||||
using StellaOps.VexLens.Persistence;
|
||||
using StellaOps.VexLens.Storage;
|
||||
using StellaOps.VexLens.Trust;
|
||||
using StellaOps.VexLens.WebService.Extensions;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Configure Serilog
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(builder.Configuration)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
|
||||
.CreateLogger();
|
||||
|
||||
builder.Host.UseSerilog();
|
||||
|
||||
// Configure OpenAPI
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
// Configure OpenTelemetry
|
||||
builder.Services.AddOpenTelemetry()
|
||||
.ConfigureResource(resource => resource.AddService("StellaOps.VexLens"))
|
||||
.WithTracing(tracing =>
|
||||
{
|
||||
tracing
|
||||
.AddAspNetCoreInstrumentation()
|
||||
.AddHttpClientInstrumentation();
|
||||
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
tracing.AddConsoleExporter();
|
||||
}
|
||||
});
|
||||
|
||||
// Configure VexLens services
|
||||
builder.Services.AddSingleton<IVexConsensusEngine, DefaultVexConsensusEngine>();
|
||||
builder.Services.AddSingleton<ITrustWeightEngine, DefaultTrustWeightEngine>();
|
||||
builder.Services.AddSingleton<IConsensusProjectionStore, InMemoryConsensusProjectionStore>();
|
||||
builder.Services.AddSingleton<IIssuerDirectory, InMemoryIssuerDirectory>();
|
||||
builder.Services.AddSingleton<IVexStatementProvider, NullVexStatementProvider>();
|
||||
builder.Services.AddScoped<IVexLensApiService, VexLensApiService>();
|
||||
|
||||
// Configure PostgreSQL persistence if configured
|
||||
var connectionString = builder.Configuration.GetConnectionString("VexLens");
|
||||
if (!string.IsNullOrEmpty(connectionString))
|
||||
{
|
||||
builder.Services.AddSingleton<IConsensusProjectionStore>(sp =>
|
||||
new PostgresConsensusProjectionStore(connectionString, "vexlens"));
|
||||
builder.Services.AddSingleton<IIssuerDirectory>(sp =>
|
||||
new PostgresIssuerDirectory(connectionString, "vexlens"));
|
||||
}
|
||||
|
||||
// Configure health checks
|
||||
builder.Services.AddHealthChecks();
|
||||
|
||||
// Configure rate limiting
|
||||
builder.Services.AddRateLimiter(options =>
|
||||
{
|
||||
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
|
||||
options.AddFixedWindowLimiter("vexlens", limiterOptions =>
|
||||
{
|
||||
limiterOptions.PermitLimit = 100;
|
||||
limiterOptions.Window = TimeSpan.FromMinutes(1);
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure request pipeline
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.UseRateLimiter();
|
||||
app.UseSerilogRequestLogging();
|
||||
|
||||
// Map health check endpoint
|
||||
app.MapHealthChecks("/health", new HealthCheckOptions
|
||||
{
|
||||
ResponseWriter = async (context, report) =>
|
||||
{
|
||||
context.Response.ContentType = "application/json";
|
||||
var result = new
|
||||
{
|
||||
status = report.Status.ToString(),
|
||||
checks = report.Entries.Select(e => new
|
||||
{
|
||||
name = e.Key,
|
||||
status = e.Value.Status.ToString(),
|
||||
description = e.Value.Description
|
||||
})
|
||||
};
|
||||
await context.Response.WriteAsJsonAsync(result);
|
||||
}
|
||||
});
|
||||
|
||||
// Map VexLens API endpoints
|
||||
app.MapVexLensEndpoints();
|
||||
|
||||
// Log startup
|
||||
Log.Information("VexLens WebService starting on {Urls}", string.Join(", ", app.Urls));
|
||||
|
||||
try
|
||||
{
|
||||
app.Run();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "VexLens WebService terminated unexpectedly");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Null implementation for development without VexHub integration.
|
||||
/// </summary>
|
||||
internal sealed class NullVexStatementProvider : IVexStatementProvider
|
||||
{
|
||||
public Task<IReadOnlyList<VexStatementWithContext>> GetStatementsAsync(
|
||||
string vulnerabilityId,
|
||||
string productKey,
|
||||
string? tenantId,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult<IReadOnlyList<VexStatementWithContext>>([]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<RootNamespace>StellaOps.VexLens.WebService</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Console" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
|
||||
<PackageReference Include="Serilog.AspNetCore" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../StellaOps.VexLens/StellaOps.VexLens.csproj" />
|
||||
<ProjectReference Include="../StellaOps.VexLens.Persistence/StellaOps.VexLens.Persistence.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
|
||||
<ProjectReference Include="../../Router/__Libraries/StellaOps.Messaging/StellaOps.Messaging.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.DependencyInjection/StellaOps.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Configuration/StellaOps.Configuration.csproj" />
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Ingestion.Telemetry/StellaOps.Ingestion.Telemetry.csproj" />
|
||||
<ProjectReference Include="../../Authority/StellaOps.Authority/StellaOps.Auth.Abstractions/StellaOps.Auth.Abstractions.csproj" />
|
||||
<ProjectReference Include="../../Authority/StellaOps.Authority/StellaOps.Auth.Client/StellaOps.Auth.Client.csproj" />
|
||||
<ProjectReference Include="../../Authority/StellaOps.Authority/StellaOps.Auth.ServerIntegration/StellaOps.Auth.ServerIntegration.csproj" />
|
||||
<ProjectReference Include="../../Router/__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"Microsoft.AspNetCore": "Information"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Debug"
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/VexLens/StellaOps.VexLens.WebService/appsettings.json
Normal file
28
src/VexLens/StellaOps.VexLens.WebService/appsettings.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Information",
|
||||
"Override": {
|
||||
"Microsoft": "Warning",
|
||||
"System": "Warning"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"VexLens": ""
|
||||
},
|
||||
"VexLens": {
|
||||
"DefaultConsensusMode": "WeightedVote",
|
||||
"MinimumWeightThreshold": 0.1,
|
||||
"ConflictThreshold": 0.3,
|
||||
"ProjectionHistoryLimit": 100,
|
||||
"CacheDurationSeconds": 300
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
Reference in New Issue
Block a user