feat(audit): Apply TreatWarningsAsErrors=true to 160+ production csproj files

Sprint: SPRINT_20251229_049_BE_csproj_audit_maint_tests
Tasks: AUDIT-0001 through AUDIT-0147 APPLY tasks (approved decisions 1-9)

Changes:
- Set TreatWarningsAsErrors=true for all production .NET projects
- Fixed nullable warnings in Scanner.EntryTrace, Scanner.Evidence,
  Scheduler.Worker, Concelier connectors, and other modules
- Injected TimeProvider/IGuidProvider for deterministic time/ID generation
- Added path traversal validation in AirGap.Bundle
- Fixed NULL handling in various cursor classes
- Third-party GostCryptography retains TreatWarningsAsErrors=false (preserves original)
- Test projects excluded per user decision (rejected decision 10)

Note: All 17 ACSC connector tests pass after snapshot fixture sync
This commit is contained in:
StellaOps Bot
2026-01-04 11:21:16 +02:00
parent bc4dd4f377
commit e411fde1a9
438 changed files with 2648 additions and 668 deletions

View File

@@ -32,6 +32,18 @@ builder.Configuration
builder.Services.AddAdvisoryAiCore(builder.Configuration);
// Authorization service
builder.Services.AddSingleton<StellaOps.AdvisoryAI.WebService.Services.IAuthorizationService, StellaOps.AdvisoryAI.WebService.Services.HeaderBasedAuthorizationService>();
// Rate limits service with configuration
builder.Services.AddOptions<StellaOps.AdvisoryAI.WebService.Services.RateLimitsOptions>()
.Bind(builder.Configuration.GetSection(StellaOps.AdvisoryAI.WebService.Services.RateLimitsOptions.SectionName))
.ValidateOnStart();
builder.Services.AddSingleton<StellaOps.AdvisoryAI.WebService.Services.IRateLimitsService, StellaOps.AdvisoryAI.WebService.Services.ConfigDrivenRateLimitsService>();
// TimeProvider for deterministic timestamps
builder.Services.AddSingleton(TimeProvider.System);
// VEX-AI-016: Consent and justification services
builder.Services.AddSingleton<IAiConsentStore, InMemoryAiConsentStore>();
builder.Services.AddSingleton<IAiJustificationGenerator, DefaultAiJustificationGenerator>();
@@ -645,9 +657,12 @@ static async Task<IResult> HandlePolicyValidate(
}
// POLICY-19: POST /v1/advisory-ai/policy/studio/compile
// NOTE: This is a stub implementation. In production, this would compile rules into a PolicyBundle.
// The stub returns experimental markers to indicate incomplete implementation.
static Task<IResult> HandlePolicyCompile(
HttpContext httpContext,
PolicyCompileApiRequest request,
TimeProvider timeProvider,
CancellationToken cancellationToken)
{
using var activity = AdvisoryAiActivitySource.Instance.StartActivity("advisory_ai.policy_compile", ActivityKind.Server);
@@ -659,9 +674,14 @@ static Task<IResult> HandlePolicyCompile(
return Task.FromResult(Results.StatusCode(StatusCodes.Status403Forbidden));
}
// In a real implementation, this would compile rules into a PolicyBundle
var bundleId = $"bundle:{Guid.NewGuid():N}";
var now = DateTime.UtcNow;
// STUB: This endpoint is experimental and not wired to real policy compilation.
// Return a deterministic bundle ID derived from input to avoid nondeterministic output.
var inputHash = ComputeDeterministicBundleId(request.BundleName, request.RuleIds);
var bundleId = $"bundle:stub:{inputHash}";
var now = timeProvider.GetUtcNow();
// Compute content hash deterministically from the rule IDs
var contentHash = ComputeDeterministicContentHash(request.RuleIds);
var response = new PolicyBundleApiResponse
{
@@ -670,13 +690,29 @@ static Task<IResult> HandlePolicyCompile(
Version = "1.0.0",
RuleCount = request.RuleIds.Count,
CompiledAt = now.ToString("O"),
ContentHash = $"sha256:{Guid.NewGuid():N}",
ContentHash = $"sha256:{contentHash}",
SignatureId = null // Would be signed in production
};
return Task.FromResult(Results.Ok(response));
}
// Deterministic hash computation for stub bundle ID
static string ComputeDeterministicBundleId(string bundleName, IReadOnlyList<string> ruleIds)
{
var input = $"{bundleName}:{string.Join(",", ruleIds.OrderBy(x => x, StringComparer.Ordinal))}";
var bytes = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(input));
return Convert.ToHexString(bytes)[..32].ToLowerInvariant();
}
// Deterministic content hash for stub bundles
static string ComputeDeterministicContentHash(IReadOnlyList<string> ruleIds)
{
var input = string.Join(",", ruleIds.OrderBy(x => x, StringComparer.Ordinal));
var bytes = System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(input));
return Convert.ToHexString(bytes).ToLowerInvariant();
}
// VEX-AI-016: Consent handler functions
static string GetTenantId(HttpContext context)
{
@@ -869,41 +905,24 @@ static async Task<IResult> HandleRemediate(
}
}
// VEX-AI-016: Rate limits handler
// VEX-AI-016: Rate limits handler using config-driven service
static Task<IResult> HandleGetRateLimits(
HttpContext httpContext,
StellaOps.AdvisoryAI.WebService.Services.IRateLimitsService rateLimitsService,
TimeProvider timeProvider,
CancellationToken cancellationToken)
{
// Return current rate limit info for each feature
var now = DateTimeOffset.UtcNow;
var resetTime = now.AddMinutes(1);
var limits = rateLimitsService.GetRateLimits(timeProvider);
var limits = new List<AiRateLimitInfoResponse>
var response = limits.Select(l => new AiRateLimitInfoResponse
{
new AiRateLimitInfoResponse
{
Feature = "explain",
Limit = 10,
Remaining = 10,
ResetsAt = resetTime.ToString("O")
},
new AiRateLimitInfoResponse
{
Feature = "remediate",
Limit = 5,
Remaining = 5,
ResetsAt = resetTime.ToString("O")
},
new AiRateLimitInfoResponse
{
Feature = "justify",
Limit = 3,
Remaining = 3,
ResetsAt = resetTime.ToString("O")
}
};
Feature = l.Feature,
Limit = l.Limit,
Remaining = l.Remaining,
ResetsAt = l.ResetsAt.ToString("O")
}).ToList();
return Task.FromResult(Results.Ok(limits));
return Task.FromResult(Results.Ok(response));
}
internal sealed record PipelinePlanRequest(