Add signal contracts for reachability, exploitability, trust, and unknown symbols
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Signals DSSE Sign & Evidence Locker / sign-signals-artifacts (push) Has been cancelled
Signals DSSE Sign & Evidence Locker / verify-signatures (push) Has been cancelled

- Introduced `ReachabilityState`, `RuntimeHit`, `ExploitabilitySignal`, `ReachabilitySignal`, `SignalEnvelope`, `SignalType`, `TrustSignal`, and `UnknownSymbolSignal` records to define various signal types and their properties.
- Implemented JSON serialization attributes for proper data interchange.
- Created project files for the new signal contracts library and corresponding test projects.
- Added deterministic test fixtures for micro-interaction testing.
- Included cryptographic keys for secure operations with cosign.
This commit is contained in:
StellaOps Bot
2025-12-05 00:27:00 +02:00
parent b018949a8d
commit 8768c27f30
192 changed files with 27569 additions and 2552 deletions

View File

@@ -82,6 +82,12 @@ internal static class RiskProfileEndpoints
.Produces<RiskProfileHashResponse>(StatusCodes.Status200OK)
.Produces<ProblemHttpResult>(StatusCodes.Status404NotFound);
group.MapGet("/{profileId}/metadata", GetProfileMetadata)
.WithName("GetRiskProfileMetadata")
.WithSummary("Export risk profile metadata for notification enrichment (POLICY-RISK-40-002).")
.Produces<RiskProfileMetadataExportResponse>(StatusCodes.Status200OK)
.Produces<ProblemHttpResult>(StatusCodes.Status404NotFound);
return endpoints;
}
@@ -461,6 +467,53 @@ internal static class RiskProfileEndpoints
return Results.Ok(new RiskProfileHashResponse(profile.Id, profile.Version, hash, contentOnly));
}
private static IResult GetProfileMetadata(
HttpContext context,
[FromRoute] string profileId,
RiskProfileConfigurationService profileService,
RiskProfileLifecycleService lifecycleService)
{
var scopeResult = ScopeAuthorization.RequireScope(context, StellaOpsScopes.PolicyRead);
if (scopeResult is not null)
{
return scopeResult;
}
var profile = profileService.GetProfile(profileId);
if (profile == null)
{
return Results.NotFound(new ProblemDetails
{
Title = "Profile not found",
Detail = $"Risk profile '{profileId}' was not found.",
Status = StatusCodes.Status404NotFound
});
}
var versions = lifecycleService.GetAllVersions(profileId);
var activeVersion = versions.FirstOrDefault(v => v.Status == RiskProfileLifecycleStatus.Active);
var hash = profileService.ComputeHash(profile);
// Extract signal names and severity thresholds for notification context
var signalNames = profile.Signals.Select(s => s.Name).ToList();
var severityThresholds = profile.Overrides.Severity
.Select(s => new SeverityThresholdInfo(s.Set.ToString(), s.When))
.ToList();
return Results.Ok(new RiskProfileMetadataExportResponse(
ProfileId: profile.Id,
Version: profile.Version,
Description: profile.Description,
Hash: hash,
Status: activeVersion?.Status.ToString() ?? "unknown",
SignalNames: signalNames,
SeverityThresholds: severityThresholds,
CustomMetadata: profile.Metadata,
ExtendsProfile: profile.Extends,
ExportedAt: DateTime.UtcNow
));
}
private static string? ResolveActorId(HttpContext context)
{
var user = context.User;
@@ -521,4 +574,26 @@ internal sealed record CompareRiskProfilesRequest(
string ToProfileId,
string ToVersion);
/// <summary>
/// Metadata export response for notification enrichment (POLICY-RISK-40-002).
/// </summary>
internal sealed record RiskProfileMetadataExportResponse(
string ProfileId,
string Version,
string? Description,
string Hash,
string Status,
IReadOnlyList<string> SignalNames,
IReadOnlyList<SeverityThresholdInfo> SeverityThresholds,
Dictionary<string, object?>? CustomMetadata,
string? ExtendsProfile,
DateTime ExportedAt);
/// <summary>
/// Severity threshold information for notification context.
/// </summary>
internal sealed record SeverityThresholdInfo(
string TargetSeverity,
Dictionary<string, object> WhenConditions);
#endregion