Add Authority Advisory AI and API Lifecycle Configuration

- Introduced AuthorityAdvisoryAiOptions and related classes for managing advisory AI configurations, including remote inference options and tenant-specific settings.
- Added AuthorityApiLifecycleOptions to control API lifecycle settings, including legacy OAuth endpoint configurations.
- Implemented validation and normalization methods for both advisory AI and API lifecycle options to ensure proper configuration.
- Created AuthorityNotificationsOptions and its related classes for managing notification settings, including ack tokens, webhooks, and escalation options.
- Developed IssuerDirectoryClient and related models for interacting with the issuer directory service, including caching mechanisms and HTTP client configurations.
- Added support for dependency injection through ServiceCollectionExtensions for the Issuer Directory Client.
- Updated project file to include necessary package references for the new Issuer Directory Client library.
This commit is contained in:
master
2025-11-02 13:40:38 +02:00
parent 66cb6c4b8a
commit f98cea3bcf
516 changed files with 68157 additions and 24754 deletions

View File

@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace StellaOps.Scanner.Surface.Validation;
internal sealed class SurfaceValidatorRunner : ISurfaceValidatorRunner
{
private readonly IReadOnlyList<ISurfaceValidator> _validators;
private readonly ILogger<SurfaceValidatorRunner> _logger;
private readonly ISurfaceValidationReporter _reporter;
private readonly SurfaceValidationOptions _options;
public SurfaceValidatorRunner(
IEnumerable<ISurfaceValidator> validators,
ILogger<SurfaceValidatorRunner> logger,
ISurfaceValidationReporter reporter,
IOptions<SurfaceValidationOptions> options)
{
_validators = validators?.ToArray() ?? Array.Empty<ISurfaceValidator>();
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_reporter = reporter ?? throw new ArgumentNullException(nameof(reporter));
_options = options?.Value ?? new SurfaceValidationOptions();
}
public async ValueTask<SurfaceValidationResult> RunAllAsync(
SurfaceValidationContext context,
CancellationToken cancellationToken = default)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
if (_validators.Count == 0)
{
var success = SurfaceValidationResult.Success();
_reporter.Report(context, success);
return success;
}
var issues = new List<SurfaceValidationIssue>();
foreach (var validator in _validators)
{
cancellationToken.ThrowIfCancellationRequested();
try
{
var result = await validator.ValidateAsync(context, cancellationToken).ConfigureAwait(false);
if (!result.IsSuccess)
{
issues.AddRange(result.Issues);
if (!_options.ContinueOnError && result.Issues.Any(issue => issue.Severity == SurfaceValidationSeverity.Error))
{
break;
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Surface validator {Validator} threw an exception.", validator.GetType().FullName);
issues.Add(SurfaceValidationIssue.Error(
SurfaceValidationIssueCodes.ValidatorException,
$"Validator '{validator.GetType().FullName}' threw an exception: {ex.Message}",
"Inspect logs for stack trace."));
if (!_options.ContinueOnError)
{
break;
}
}
}
var resultAggregate = issues.Count == 0
? SurfaceValidationResult.Success()
: SurfaceValidationResult.FromIssues(issues);
_reporter.Report(context, resultAggregate);
return resultAggregate;
}
public async ValueTask EnsureAsync(
SurfaceValidationContext context,
CancellationToken cancellationToken = default)
{
var result = await RunAllAsync(context, cancellationToken).ConfigureAwait(false);
if (!result.IsSuccess && _options.ThrowOnFailure)
{
throw new SurfaceValidationException(
$"Surface validation failed for component '{context.ComponentName}'.",
result.Issues);
}
}
}