consolidation of some of the modules, localization fixes, product advisories work, qa work
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using static StellaOps.Localization.T;
|
||||
using StellaOps.RiskEngine.Core.Contracts;
|
||||
using StellaOps.RiskEngine.Core.Providers;
|
||||
using StellaOps.RiskEngine.WebService.Security;
|
||||
using StellaOps.Auth.ServerIntegration.Tenancy;
|
||||
|
||||
namespace StellaOps.RiskEngine.WebService.Endpoints;
|
||||
|
||||
/// <summary>
|
||||
/// Minimal API endpoints for exploit maturity assessment.
|
||||
/// </summary>
|
||||
public static class ExploitMaturityEndpoints
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps exploit maturity endpoints to the application.
|
||||
/// </summary>
|
||||
public static IEndpointRouteBuilder MapExploitMaturityEndpoints(this IEndpointRouteBuilder app)
|
||||
{
|
||||
var group = app.MapGroup("/exploit-maturity")
|
||||
.WithTags("ExploitMaturity")
|
||||
.RequireAuthorization(RiskEnginePolicies.Read)
|
||||
.RequireTenant();
|
||||
|
||||
// GET /exploit-maturity/{cveId} - Assess exploit maturity for a CVE
|
||||
group.MapGet("/{cveId}", async (
|
||||
string cveId,
|
||||
[FromServices] IExploitMaturityService service,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await service.AssessMaturityAsync(cveId, ct).ConfigureAwait(false);
|
||||
return Results.Ok(result);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return Results.BadRequest(new { error = ex.Message });
|
||||
}
|
||||
})
|
||||
.WithName("GetExploitMaturity")
|
||||
.WithSummary("Assess exploit maturity for a CVE")
|
||||
.WithDescription(_t("riskengine.exploit_maturity.assess_description"))
|
||||
.Produces<ExploitMaturityResult>()
|
||||
.ProducesProblem(400);
|
||||
|
||||
// GET /exploit-maturity/{cveId}/level - Get just the maturity level
|
||||
group.MapGet("/{cveId}/level", async (
|
||||
string cveId,
|
||||
[FromServices] IExploitMaturityService service,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var level = await service.GetMaturityLevelAsync(cveId, ct).ConfigureAwait(false);
|
||||
return level.HasValue
|
||||
? Results.Ok(new { cveId, level = level.Value.ToString() })
|
||||
: Results.NotFound(new { cveId, error = _t("riskengine.error.maturity_level_undetermined") });
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return Results.BadRequest(new { error = ex.Message });
|
||||
}
|
||||
})
|
||||
.WithName("GetExploitMaturityLevel")
|
||||
.WithSummary("Get exploit maturity level for a CVE")
|
||||
.WithDescription(_t("riskengine.exploit_maturity.get_level_description"));
|
||||
|
||||
// GET /exploit-maturity/{cveId}/history - Get maturity history
|
||||
group.MapGet("/{cveId}/history", async (
|
||||
string cveId,
|
||||
[FromServices] IExploitMaturityService service,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var history = await service.GetMaturityHistoryAsync(cveId, ct).ConfigureAwait(false);
|
||||
return Results.Ok(new { cveId, entries = history });
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return Results.BadRequest(new { error = ex.Message });
|
||||
}
|
||||
})
|
||||
.WithName("GetExploitMaturityHistory")
|
||||
.WithSummary("Get exploit maturity history for a CVE")
|
||||
.WithDescription(_t("riskengine.exploit_maturity.get_history_description"));
|
||||
|
||||
// POST /exploit-maturity/batch - Batch assess multiple CVEs
|
||||
group.MapPost("/batch", async (
|
||||
BatchMaturityRequest request,
|
||||
[FromServices] IExploitMaturityService service,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
if (request.CveIds is null || request.CveIds.Count == 0)
|
||||
{
|
||||
return Results.BadRequest(new { error = _t("riskengine.error.cve_ids_required") });
|
||||
}
|
||||
|
||||
var results = new List<ExploitMaturityResult>();
|
||||
var errors = new List<BatchError>();
|
||||
|
||||
foreach (var cveId in request.CveIds.Distinct())
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await service.AssessMaturityAsync(cveId, ct).ConfigureAwait(false);
|
||||
results.Add(result);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
errors.Add(new BatchError(cveId, ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
return Results.Ok(new { results, errors });
|
||||
})
|
||||
.WithName("BatchAssessExploitMaturity")
|
||||
.WithSummary("Batch assess exploit maturity for multiple CVEs")
|
||||
.WithDescription(_t("riskengine.exploit_maturity.batch_assess_description"))
|
||||
.RequireAuthorization(RiskEnginePolicies.Operate);
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request for batch maturity assessment.
|
||||
/// </summary>
|
||||
public sealed record BatchMaturityRequest(IReadOnlyList<string>? CveIds);
|
||||
|
||||
/// <summary>
|
||||
/// Error entry in batch response.
|
||||
/// </summary>
|
||||
public sealed record BatchError(string CveId, string Error);
|
||||
263
src/Findings/StellaOps.RiskEngine.WebService/Program.cs
Normal file
263
src/Findings/StellaOps.RiskEngine.WebService/Program.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using StellaOps.Auth.Abstractions;
|
||||
using StellaOps.Localization;
|
||||
using StellaOps.Auth.ServerIntegration;
|
||||
using StellaOps.Auth.ServerIntegration.Tenancy;
|
||||
using StellaOps.RiskEngine.Core.Contracts;
|
||||
using StellaOps.RiskEngine.Core.Providers;
|
||||
using StellaOps.RiskEngine.Core.Services;
|
||||
using StellaOps.RiskEngine.Infrastructure.Stores;
|
||||
using StellaOps.RiskEngine.WebService.Endpoints;
|
||||
using StellaOps.RiskEngine.WebService.Security;
|
||||
using StellaOps.Router.AspNet;
|
||||
using System.Linq;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
builder.Services.AddSingleton<RiskScoreQueue>();
|
||||
var storageDriver = ResolveStorageDriver(builder.Configuration, "RiskEngine");
|
||||
RegisterResultStore(builder.Services, builder.Configuration, builder.Environment.IsDevelopment(), storageDriver);
|
||||
builder.Services.AddSingleton<IRiskScoreProviderRegistry>(_ =>
|
||||
new RiskScoreProviderRegistry(new IRiskScoreProvider[]
|
||||
{
|
||||
new DefaultTransformsProvider(),
|
||||
new CvssKevProvider(new NullCvssSource(), new NullKevSource()),
|
||||
new EpssProvider(new NullEpssSource()),
|
||||
new CvssKevEpssProvider(new NullCvssSource(), new NullKevSource(), new NullEpssSource()),
|
||||
new VexGateProvider(),
|
||||
new FixExposureProvider()
|
||||
}));
|
||||
|
||||
// Exploit Maturity Service registration
|
||||
builder.Services.AddSingleton<IEpssSource, NullEpssSource>();
|
||||
builder.Services.AddSingleton<IKevSource, NullKevSource>();
|
||||
builder.Services.AddSingleton<IExploitMaturityService, ExploitMaturityService>();
|
||||
|
||||
// Authentication and authorization
|
||||
builder.Services.AddStellaOpsResourceServerAuthentication(builder.Configuration);
|
||||
builder.Services.AddStellaOpsTenantServices();
|
||||
builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddStellaOpsScopePolicy(RiskEnginePolicies.Read, StellaOpsScopes.RiskEngineRead);
|
||||
options.AddStellaOpsScopePolicy(RiskEnginePolicies.Operate, StellaOpsScopes.RiskEngineOperate);
|
||||
});
|
||||
|
||||
builder.Services.AddStellaOpsLocalization(builder.Configuration);
|
||||
builder.Services.AddTranslationBundle(System.Reflection.Assembly.GetExecutingAssembly());
|
||||
|
||||
// Stella Router integration
|
||||
var routerEnabled = builder.Services.AddRouterMicroservice(
|
||||
builder.Configuration,
|
||||
serviceName: "riskengine",
|
||||
version: System.Reflection.CustomAttributeExtensions.GetCustomAttribute<System.Reflection.AssemblyInformationalVersionAttribute>(System.Reflection.Assembly.GetExecutingAssembly())?.InformationalVersion ?? "1.0.0",
|
||||
routerOptionsSection: "Router");
|
||||
|
||||
builder.Services.AddStellaOpsCors(builder.Environment, builder.Configuration);
|
||||
|
||||
builder.TryAddStellaOpsLocalBinding("riskengine");
|
||||
var app = builder.Build();
|
||||
app.LogStellaOpsLocalHostname("riskengine");
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.UseStellaOpsCors();
|
||||
app.UseStellaOpsLocalization();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseStellaOpsTenantMiddleware();
|
||||
app.TryUseStellaRouter(routerEnabled);
|
||||
|
||||
await app.LoadTranslationsAsync();
|
||||
|
||||
// Map exploit maturity endpoints
|
||||
app.MapExploitMaturityEndpoints();
|
||||
|
||||
app.MapGet("/risk-scores/providers", (IRiskScoreProviderRegistry registry) =>
|
||||
Results.Ok(new { providers = registry.ProviderNames.OrderBy(n => n, StringComparer.OrdinalIgnoreCase) }))
|
||||
.WithName("ListRiskScoreProviders")
|
||||
.WithDescription("Returns the sorted list of registered risk score provider names. Use this to discover which scoring strategies are available before submitting job or simulation requests.")
|
||||
.RequireAuthorization(RiskEnginePolicies.Read)
|
||||
.RequireTenant();
|
||||
|
||||
app.MapPost("/risk-scores/jobs", async (
|
||||
ScoreRequest request,
|
||||
[FromServices] RiskScoreQueue queue,
|
||||
[FromServices] IRiskScoreProviderRegistry registry,
|
||||
[FromServices] IRiskScoreResultStore store,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
var normalized = new ScoreRequest(
|
||||
request.Provider,
|
||||
request.Subject,
|
||||
request.Signals ?? new Dictionary<string, double>());
|
||||
|
||||
var jobId = await queue.EnqueueWithIdAsync(normalized, ct).ConfigureAwait(false);
|
||||
var worker = new RiskScoreWorker(queue, registry, store, TimeProvider.System);
|
||||
var result = await worker.ProcessNextAsync(ct).ConfigureAwait(false);
|
||||
return Results.Accepted($"/risk-scores/jobs/{jobId}", new { jobId, result });
|
||||
})
|
||||
.WithName("CreateRiskScoreJob")
|
||||
.WithDescription("Enqueues a risk scoring job for the specified subject and provider, immediately executes it synchronously, and returns a 202 Accepted response with the job ID and computed result. The provider must be registered or the job will fail with an error in the result payload.")
|
||||
.RequireAuthorization(RiskEnginePolicies.Operate)
|
||||
.RequireTenant();
|
||||
|
||||
app.MapGet("/risk-scores/jobs/{jobId:guid}", (
|
||||
Guid jobId,
|
||||
[FromServices] IRiskScoreResultStore store) =>
|
||||
store.TryGet(jobId, out var result)
|
||||
? Results.Ok(result)
|
||||
: Results.NotFound())
|
||||
.WithName("GetRiskScoreJob")
|
||||
.WithDescription("Returns the stored risk score result for the specified job ID. Returns 404 if the job ID is not found in the result store, which may occur if the store has been cleared or the ID is invalid.")
|
||||
.RequireAuthorization(RiskEnginePolicies.Read)
|
||||
.RequireTenant();
|
||||
|
||||
app.MapPost("/risk-scores/simulations", async (
|
||||
IReadOnlyCollection<ScoreRequest> requests,
|
||||
[FromServices] IRiskScoreProviderRegistry registry,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
var results = await EvaluateAsync(requests, registry, ct).ConfigureAwait(false);
|
||||
return Results.Ok(new { results });
|
||||
})
|
||||
.WithName("RunRiskScoreSimulation")
|
||||
.WithDescription("Evaluates a collection of risk score requests against the registered providers and returns the full result list. Unlike the job endpoint, simulations do not persist results. Requests for unregistered providers are returned with a failure flag and error message.")
|
||||
.RequireAuthorization(RiskEnginePolicies.Operate)
|
||||
.RequireTenant();
|
||||
|
||||
app.MapPost("/risk-scores/simulations/summary", async (
|
||||
IReadOnlyCollection<ScoreRequest> requests,
|
||||
[FromServices] IRiskScoreProviderRegistry registry,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
var results = await EvaluateAsync(requests, registry, ct).ConfigureAwait(false);
|
||||
|
||||
var scores = results.Select(r => r.Score).ToArray();
|
||||
var summary = new
|
||||
{
|
||||
averageScore = scores.Length == 0 ? 0d : scores.Average(),
|
||||
minScore = scores.Length == 0 ? 0d : scores.Min(),
|
||||
maxScore = scores.Length == 0 ? 0d : scores.Max(),
|
||||
topMovers = results
|
||||
.OrderByDescending(r => r.Score)
|
||||
.ThenBy(r => r.Subject, StringComparer.Ordinal)
|
||||
.Take(3)
|
||||
.ToArray()
|
||||
};
|
||||
|
||||
return Results.Ok(new { summary, results });
|
||||
})
|
||||
.WithName("GetRiskScoreSimulationSummary")
|
||||
.WithDescription("Evaluates a collection of risk score requests and returns both the full result list and an aggregate summary including average, minimum, and maximum scores plus the top-three highest-scoring subjects. Use this variant when a dashboard-style overview is required alongside per-subject detail.")
|
||||
.RequireAuthorization(RiskEnginePolicies.Operate)
|
||||
.RequireTenant();
|
||||
|
||||
// Refresh Router endpoint cache
|
||||
app.TryRefreshStellaRouterEndpoints(routerEnabled);
|
||||
|
||||
await app.RunAsync().ConfigureAwait(false);
|
||||
|
||||
static void RegisterResultStore(IServiceCollection services, IConfiguration configuration, bool isDevelopment, string storageDriver)
|
||||
{
|
||||
if (string.Equals(storageDriver, "postgres", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var connectionString = ResolvePostgresConnectionString(configuration, "RiskEngine");
|
||||
if (string.IsNullOrWhiteSpace(connectionString))
|
||||
{
|
||||
if (!isDevelopment)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"RiskEngine requires PostgreSQL connection settings in non-development mode. " +
|
||||
"Set ConnectionStrings:Default or RiskEngine:Storage:Postgres:ConnectionString.");
|
||||
}
|
||||
|
||||
services.AddSingleton<IRiskScoreResultStore, InMemoryRiskScoreResultStore>();
|
||||
return;
|
||||
}
|
||||
|
||||
services.AddSingleton<IRiskScoreResultStore>(_ => new PostgresRiskScoreResultStore(connectionString));
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Equals(storageDriver, "inmemory", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
services.AddSingleton<IRiskScoreResultStore, InMemoryRiskScoreResultStore>();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Unsupported RiskEngine storage driver '{storageDriver}'. Allowed values: postgres, inmemory.");
|
||||
}
|
||||
|
||||
static string ResolveStorageDriver(IConfiguration configuration, string serviceName)
|
||||
{
|
||||
return FirstNonEmpty(
|
||||
configuration["Storage:Driver"],
|
||||
configuration[$"{serviceName}:Storage:Driver"])
|
||||
?? "postgres";
|
||||
}
|
||||
|
||||
static string? ResolvePostgresConnectionString(IConfiguration configuration, string serviceName)
|
||||
{
|
||||
return FirstNonEmpty(
|
||||
configuration[$"{serviceName}:Storage:Postgres:ConnectionString"],
|
||||
configuration["Storage:Postgres:ConnectionString"],
|
||||
configuration[$"Postgres:{serviceName}:ConnectionString"],
|
||||
configuration[$"ConnectionStrings:{serviceName}"],
|
||||
configuration["ConnectionStrings:Default"]);
|
||||
}
|
||||
|
||||
static string? FirstNonEmpty(params string?[] values)
|
||||
{
|
||||
foreach (var value in values)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static async Task<List<RiskScoreResult>> EvaluateAsync(
|
||||
IReadOnlyCollection<ScoreRequest> requests,
|
||||
IRiskScoreProviderRegistry registry,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var results = new List<RiskScoreResult>(requests.Count);
|
||||
foreach (var req in requests)
|
||||
{
|
||||
var normalized = new ScoreRequest(
|
||||
req.Provider,
|
||||
req.Subject,
|
||||
req.Signals ?? new Dictionary<string, double>());
|
||||
|
||||
if (!registry.TryGet(normalized.Provider, out var provider))
|
||||
{
|
||||
results.Add(new RiskScoreResult(Guid.NewGuid(), normalized.Provider, normalized.Subject, 0d, false, "Provider not registered", normalized.Signals, TimeProvider.System.GetUtcNow()));
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var score = await provider.ScoreAsync(normalized, ct).ConfigureAwait(false);
|
||||
results.Add(new RiskScoreResult(Guid.NewGuid(), normalized.Provider, normalized.Subject, score, true, null, normalized.Signals, TimeProvider.System.GetUtcNow()));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
results.Add(new RiskScoreResult(Guid.NewGuid(), normalized.Provider, normalized.Subject, 0d, false, ex.Message, normalized.Signals, TimeProvider.System.GetUtcNow()));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:10161",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"STELLAOPS_WEBSERVICES_CORS": "true",
|
||||
"STELLAOPS_WEBSERVICES_CORS_ORIGIN": "https://stella-ops.local,https://stella-ops.local:10000,https://localhost:10000"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:10160;http://localhost:10161",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"STELLAOPS_WEBSERVICES_CORS": "true",
|
||||
"STELLAOPS_WEBSERVICES_CORS_ORIGIN": "https://stella-ops.local,https://stella-ops.local:10000,https://localhost:10000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) StellaOps. Licensed under the BUSL-1.1.
|
||||
|
||||
namespace StellaOps.RiskEngine.WebService.Security;
|
||||
|
||||
/// <summary>
|
||||
/// Named authorization policy constants for the Risk Engine service.
|
||||
/// Policies are registered via AddStellaOpsScopePolicy in Program.cs.
|
||||
/// </summary>
|
||||
internal static class RiskEnginePolicies
|
||||
{
|
||||
/// <summary>Policy for querying risk score providers and job results. Requires risk-engine:read scope.</summary>
|
||||
public const string Read = "RiskEngine.Read";
|
||||
|
||||
/// <summary>Policy for submitting risk score jobs and simulations. Requires risk-engine:operate scope.</summary>
|
||||
public const string Operate = "RiskEngine.Operate";
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" ?>
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
|
||||
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
<ProjectReference Include="..\StellaOps.RiskEngine.Core\StellaOps.RiskEngine.Core.csproj"/>
|
||||
|
||||
|
||||
<ProjectReference Include="..\__Libraries\StellaOps.RiskEngine.Infrastructure\StellaOps.RiskEngine.Infrastructure.csproj"/>
|
||||
<ProjectReference Include="..\..\Router\__Libraries\StellaOps.Router.AspNet\StellaOps.Router.AspNet.csproj"/>
|
||||
<ProjectReference Include="..\..\Authority\StellaOps.Authority\StellaOps.Auth.ServerIntegration\StellaOps.Auth.ServerIntegration.csproj"/>
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Localization\StellaOps.Localization.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Translations\*.json" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
||||
<PropertyGroup Label="StellaOpsReleaseVersion">
|
||||
<Version>1.0.0-alpha1</Version>
|
||||
<InformationalVersion>1.0.0-alpha1</InformationalVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,6 @@
|
||||
@StellaOps.RiskEngine.WebService_HostAddress = http://localhost:5115
|
||||
|
||||
GET {{StellaOps.RiskEngine.WebService_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
9
src/Findings/StellaOps.RiskEngine.WebService/TASKS.md
Normal file
9
src/Findings/StellaOps.RiskEngine.WebService/TASKS.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# StellaOps.RiskEngine.WebService Task Board
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20260130_002_Tools_csproj_remediation_solid_review.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| REMED-05 | TODO | Remediation checklist: docs/implplan/audits/csproj-standards/remediation/checklists/src/RiskEngine/StellaOps.RiskEngine/StellaOps.RiskEngine.WebService/StellaOps.RiskEngine.WebService.md. |
|
||||
| REMED-06 | DONE | SOLID review notes captured for SPRINT_20260130_002. |
|
||||
| SPRINT-312-005 | DONE | Production result-store wiring switched from in-memory to Postgres by storage-driver contract, with explicit in-memory fallback. |
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"_meta": { "locale": "en-US", "namespace": "riskengine", "version": "1.0" },
|
||||
|
||||
"riskengine.exploit_maturity.assess_description": "Returns a unified exploit maturity assessment for the specified CVE by aggregating EPSS probability, KEV catalog membership, and in-the-wild exploitation signals. The result includes the overall maturity level, per-provider signal breakdown, and a composite confidence score.",
|
||||
"riskengine.exploit_maturity.get_level_description": "Returns only the resolved maturity level enum value for the specified CVE without the full per-provider signal breakdown. Use this lightweight variant when only the top-level classification is needed. Returns 404 if the maturity level could not be determined.",
|
||||
"riskengine.exploit_maturity.get_history_description": "Returns the chronological history of maturity level assessments for the specified CVE, ordered from oldest to newest. Each entry records the maturity level, the contributing signals, and the timestamp of assessment. Useful for tracking escalation from theoretical to active exploitation.",
|
||||
"riskengine.exploit_maturity.batch_assess_description": "Submits a list of CVE IDs for bulk exploit maturity assessment and returns results for all successfully evaluated CVEs plus a separate errors array for any that could not be resolved. Duplicate CVE IDs are deduplicated before evaluation.",
|
||||
|
||||
"riskengine.error.maturity_level_undetermined": "Maturity level could not be determined",
|
||||
"riskengine.error.cve_ids_required": "CveIds list is required"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
Reference in New Issue
Block a user