audit work, fixed StellaOps.sln warnings/errors, fixed tests, sprints work, new advisories
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -264,7 +265,7 @@ internal sealed class ExceptionAdapter : IExceptionAdapter
|
||||
builder["exception.owner"] = exception.OwnerId;
|
||||
builder["exception.requester"] = exception.RequesterId;
|
||||
builder["exception.rationale"] = exception.Rationale;
|
||||
builder["exception.expiresAt"] = exception.ExpiresAt.ToString("O");
|
||||
builder["exception.expiresAt"] = exception.ExpiresAt.ToString("O", CultureInfo.InvariantCulture);
|
||||
|
||||
if (exception.ApproverIds.Length > 0)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace StellaOps.Policy.Engine.AirGap;
|
||||
@@ -393,7 +394,7 @@ internal sealed class WebhookNotificationChannel : IAirGapNotificationChannel
|
||||
severity = notification.Severity.ToString(),
|
||||
title = notification.Title,
|
||||
message = notification.Message,
|
||||
occurred_at = notification.OccurredAt.ToString("O"),
|
||||
occurred_at = notification.OccurredAt.ToString("O", CultureInfo.InvariantCulture),
|
||||
metadata = notification.Metadata
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -68,7 +69,7 @@ internal sealed class PolicyPackBundleImportService
|
||||
TenantId: tenantId,
|
||||
Status: BundleImportStatus.Validating,
|
||||
ExportCount: 0,
|
||||
ImportedAt: now.ToString("O"),
|
||||
ImportedAt: now.ToString("O", CultureInfo.InvariantCulture),
|
||||
Error: null,
|
||||
Bundle: null);
|
||||
|
||||
@@ -163,7 +164,7 @@ internal sealed class PolicyPackBundleImportService
|
||||
TenantId: tenantId,
|
||||
Status: BundleImportStatus.Imported,
|
||||
ExportCount: bundle.Exports.Count,
|
||||
ImportedAt: now.ToString("O"),
|
||||
ImportedAt: now.ToString("O", CultureInfo.InvariantCulture),
|
||||
Error: null,
|
||||
Bundle: bundle);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -76,7 +77,7 @@ public sealed class RiskProfileAirGapExportService
|
||||
ExportId: Guid.NewGuid().ToString("N")[..16],
|
||||
ProfileId: profile.Id,
|
||||
ProfileVersion: profile.Version,
|
||||
CreatedAt: now.ToString("O"),
|
||||
CreatedAt: now.ToString("O", CultureInfo.InvariantCulture),
|
||||
ArtifactSizeBytes: Encoding.UTF8.GetByteCount(profileJson),
|
||||
ArtifactDigest: artifactDigest,
|
||||
ContentHash: contentHash,
|
||||
@@ -99,7 +100,7 @@ public sealed class RiskProfileAirGapExportService
|
||||
|
||||
return new RiskProfileAirGapBundle(
|
||||
SchemaVersion: 1,
|
||||
GeneratedAt: now.ToString("O"),
|
||||
GeneratedAt: now.ToString("O", CultureInfo.InvariantCulture),
|
||||
TargetRepository: request.TargetRepository,
|
||||
DomainId: DomainId,
|
||||
DisplayName: request.DisplayName ?? "Risk Profiles Export",
|
||||
@@ -337,7 +338,7 @@ public sealed class RiskProfileAirGapExportService
|
||||
Algorithm: "HMAC-SHA256",
|
||||
KeyId: keyId ?? "default",
|
||||
Provider: "stellaops",
|
||||
SignedAt: signedAt.ToString("O"));
|
||||
SignedAt: signedAt.ToString("O", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
private static string ComputeSignatureData(List<RiskProfileAirGapExport> exports, string merkleRoot)
|
||||
@@ -422,7 +423,7 @@ public sealed class RiskProfileAirGapExportService
|
||||
PredicateType: PredicateType,
|
||||
RekorLocation: null,
|
||||
EnvelopeDigest: null,
|
||||
SignedAt: signedAt.ToString("O"));
|
||||
SignedAt: signedAt.ToString("O", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
private static string GenerateBundleId(DateTimeOffset timestamp)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -129,7 +130,7 @@ public sealed record ScoreProvenanceChain
|
||||
rule_name = Verdict.MatchedRuleName,
|
||||
verdict_digest = Verdict.VerdictDigest
|
||||
},
|
||||
created_at = CreatedAt.ToUniversalTime().ToString("O")
|
||||
created_at = CreatedAt.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture)
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(canonical, ProvenanceJsonOptions.Default);
|
||||
@@ -659,7 +660,7 @@ public sealed record ProvenanceVerdictRef
|
||||
status = predicate.Verdict.Status,
|
||||
severity = predicate.Verdict.Severity,
|
||||
score = predicate.Verdict.Score,
|
||||
evaluated_at = predicate.EvaluatedAt.ToUniversalTime().ToString("O")
|
||||
evaluated_at = predicate.EvaluatedAt.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture)
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(canonical, ProvenanceJsonOptions.Default);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -38,7 +39,7 @@ internal sealed class BatchContextService
|
||||
ComputeTraceRef(request.TenantId, i)))
|
||||
.ToList();
|
||||
|
||||
var expires = _timeProvider.GetUtcNow().AddHours(1).ToString("O");
|
||||
var expires = _timeProvider.GetUtcNow().AddHours(1).ToString("O", CultureInfo.InvariantCulture);
|
||||
var contextId = ComputeContextId(request, sortedItems);
|
||||
|
||||
return new BatchContextResponse(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -58,7 +59,7 @@ internal sealed partial class ConsoleExportJobService
|
||||
Destination: request.Destination,
|
||||
Signing: request.Signing,
|
||||
Enabled: true,
|
||||
CreatedAt: now.ToString("O"),
|
||||
CreatedAt: now.ToString("O", CultureInfo.InvariantCulture),
|
||||
LastRunAt: null,
|
||||
NextRunAt: CalculateNextRun(request.Schedule, now));
|
||||
|
||||
@@ -128,7 +129,7 @@ internal sealed partial class ConsoleExportJobService
|
||||
JobId: jobId,
|
||||
Status: "running",
|
||||
BundleId: null,
|
||||
StartedAt: now.ToString("O"),
|
||||
StartedAt: now.ToString("O", CultureInfo.InvariantCulture),
|
||||
CompletedAt: null,
|
||||
Error: null);
|
||||
|
||||
@@ -177,7 +178,7 @@ internal sealed partial class ConsoleExportJobService
|
||||
BundleId: bundleId,
|
||||
JobId: job.JobId,
|
||||
TenantId: job.TenantId,
|
||||
CreatedAt: now.ToString("O"),
|
||||
CreatedAt: now.ToString("O", CultureInfo.InvariantCulture),
|
||||
Format: job.Format,
|
||||
ArtifactDigest: artifactDigest,
|
||||
ArtifactSizeBytes: contentBytes.Length,
|
||||
@@ -195,14 +196,14 @@ internal sealed partial class ConsoleExportJobService
|
||||
{
|
||||
Status = "completed",
|
||||
BundleId = bundleId,
|
||||
CompletedAt = now.ToString("O")
|
||||
CompletedAt = now.ToString("O", CultureInfo.InvariantCulture)
|
||||
};
|
||||
await _executionStore.SaveAsync(completedExecution, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Update job with last run
|
||||
var updatedJob = job with
|
||||
{
|
||||
LastRunAt = now.ToString("O"),
|
||||
LastRunAt = now.ToString("O", CultureInfo.InvariantCulture),
|
||||
NextRunAt = CalculateNextRun(job.Schedule, now)
|
||||
};
|
||||
await _jobStore.SaveAsync(updatedJob, cancellationToken).ConfigureAwait(false);
|
||||
@@ -212,7 +213,7 @@ internal sealed partial class ConsoleExportJobService
|
||||
var failedExecution = execution with
|
||||
{
|
||||
Status = "failed",
|
||||
CompletedAt = _timeProvider.GetUtcNow().ToString("O"),
|
||||
CompletedAt = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture),
|
||||
Error = ex.Message
|
||||
};
|
||||
await _executionStore.SaveAsync(failedExecution, CancellationToken.None).ConfigureAwait(false);
|
||||
@@ -269,7 +270,7 @@ internal sealed partial class ConsoleExportJobService
|
||||
// In production, this would use a proper cron parser like Cronos
|
||||
if (schedule.StartsWith("0 0 ", StringComparison.Ordinal))
|
||||
{
|
||||
return from.AddDays(1).ToString("O");
|
||||
return from.AddDays(1).ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (schedule.StartsWith("0 */", StringComparison.Ordinal))
|
||||
@@ -277,11 +278,11 @@ internal sealed partial class ConsoleExportJobService
|
||||
var hourMatch = Regex.Match(schedule, @"\*/(\d+)");
|
||||
if (hourMatch.Success && int.TryParse(hourMatch.Groups[1].Value, out var hours))
|
||||
{
|
||||
return from.AddHours(hours).ToString("O");
|
||||
return from.AddHours(hours).ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
return from.AddDays(1).ToString("O");
|
||||
return from.AddDays(1).ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private static string GenerateId(string prefix)
|
||||
|
||||
@@ -21,6 +21,9 @@ public static class DeterminizationEngineExtensions
|
||||
// Add determinization library services
|
||||
services.AddDeterminization();
|
||||
|
||||
// Add metrics
|
||||
services.TryAddSingleton<DeterminizationGateMetrics>();
|
||||
|
||||
// Add gate
|
||||
services.TryAddSingleton<IDeterminizationGate, DeterminizationGate>();
|
||||
|
||||
|
||||
@@ -294,7 +294,7 @@ public static class PolicyEngineServiceCollectionExtensions
|
||||
/// Adds all Policy Engine services with default configuration.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Includes core services, event pipeline, worker, explainer, and Evidence-Weighted Score services.
|
||||
/// Includes core services, event pipeline, worker, explainer, determinization gate, and Evidence-Weighted Score services.
|
||||
/// EWS services are registered but only activate when <see cref="PolicyEvidenceWeightedScoreOptions.Enabled"/> is true.
|
||||
/// </remarks>
|
||||
public static IServiceCollection AddPolicyEngine(this IServiceCollection services)
|
||||
@@ -304,6 +304,9 @@ public static class PolicyEngineServiceCollectionExtensions
|
||||
services.AddPolicyEngineWorker();
|
||||
services.AddPolicyEngineExplainer();
|
||||
|
||||
// Determinization gate and policy services (Sprint 20260106_001_003)
|
||||
services.AddDeterminizationEngine();
|
||||
|
||||
// Evidence-Weighted Score services (Sprint 8200.0012.0003)
|
||||
// Always registered; activation controlled by PolicyEvidenceWeightedScoreOptions.Enabled
|
||||
services.AddEvidenceWeightedScore();
|
||||
@@ -342,6 +345,9 @@ public static class PolicyEngineServiceCollectionExtensions
|
||||
services.AddPolicyEngineWorker();
|
||||
services.AddPolicyEngineExplainer();
|
||||
|
||||
// Determinization gate and policy services (Sprint 20260106_001_003)
|
||||
services.AddDeterminizationEngine();
|
||||
|
||||
// Conditional EWS registration based on configuration
|
||||
services.AddEvidenceWeightedScoreIfEnabled(configuration);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -544,7 +545,7 @@ internal sealed class MessagingExceptionEffectiveCache : IExceptionEffectiveCach
|
||||
var statsKey = GetStatsKey(tenantId);
|
||||
var stats = new Dictionary<string, string>
|
||||
{
|
||||
["lastWarmAt"] = warmAt.ToString("O"),
|
||||
["lastWarmAt"] = warmAt.ToString("O", CultureInfo.InvariantCulture),
|
||||
["lastWarmCount"] = count.ToString(),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -642,7 +643,7 @@ internal sealed class RedisExceptionEffectiveCache : IExceptionEffectiveCache
|
||||
|
||||
var stats = new Dictionary<string, string>
|
||||
{
|
||||
["lastWarmAt"] = warmAt.ToString("O"),
|
||||
["lastWarmAt"] = warmAt.ToString("O", CultureInfo.InvariantCulture),
|
||||
["lastWarmCount"] = count.ToString(),
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Policy;
|
||||
using StellaOps.Policy.Determinization;
|
||||
using StellaOps.Policy.Determinization.Models;
|
||||
using StellaOps.Policy.Determinization.Scoring;
|
||||
using StellaOps.Policy.Engine.Gates.Determinization;
|
||||
using StellaOps.Policy.Engine.Policies;
|
||||
using StellaOps.Policy.Gates;
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Metrics;
|
||||
using StellaOps.Policy.Determinization.Models;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Gates.Determinization;
|
||||
|
||||
/// <summary>
|
||||
/// OpenTelemetry metrics for determinization gate and observation state tracking.
|
||||
/// </summary>
|
||||
public sealed class DeterminizationGateMetrics : IDisposable
|
||||
{
|
||||
private readonly Meter _meter;
|
||||
private readonly Counter<long> _evaluationsTotal;
|
||||
private readonly Counter<long> _ruleMatchesTotal;
|
||||
private readonly Counter<long> _stateTransitionsTotal;
|
||||
private readonly Histogram<double> _entropyDistribution;
|
||||
private readonly Histogram<double> _trustScoreDistribution;
|
||||
private readonly Histogram<double> _evaluationDurationMs;
|
||||
|
||||
public const string MeterName = "StellaOps.Policy.Engine.DeterminizationGate";
|
||||
|
||||
public DeterminizationGateMetrics()
|
||||
{
|
||||
_meter = new Meter(MeterName, "1.0.0");
|
||||
|
||||
_evaluationsTotal = _meter.CreateCounter<long>(
|
||||
"stellaops_policy_determinization_evaluations_total",
|
||||
unit: "{evaluations}",
|
||||
description: "Total number of determinization gate evaluations");
|
||||
|
||||
_ruleMatchesTotal = _meter.CreateCounter<long>(
|
||||
"stellaops_policy_determinization_rule_matches_total",
|
||||
unit: "{matches}",
|
||||
description: "Total number of determinization rule matches by rule name");
|
||||
|
||||
_stateTransitionsTotal = _meter.CreateCounter<long>(
|
||||
"stellaops_policy_observation_state_transitions_total",
|
||||
unit: "{transitions}",
|
||||
description: "Total number of observation state transitions");
|
||||
|
||||
_entropyDistribution = _meter.CreateHistogram<double>(
|
||||
"stellaops_policy_determinization_entropy",
|
||||
unit: "1",
|
||||
description: "Distribution of entropy scores evaluated");
|
||||
|
||||
_trustScoreDistribution = _meter.CreateHistogram<double>(
|
||||
"stellaops_policy_determinization_trust_score",
|
||||
unit: "1",
|
||||
description: "Distribution of trust scores evaluated");
|
||||
|
||||
_evaluationDurationMs = _meter.CreateHistogram<double>(
|
||||
"stellaops_policy_determinization_evaluation_duration_ms",
|
||||
unit: "ms",
|
||||
description: "Duration of determinization gate evaluations");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record a gate evaluation.
|
||||
/// </summary>
|
||||
public void RecordEvaluation(
|
||||
PolicyVerdictStatus status,
|
||||
string environment,
|
||||
string? matchedRule)
|
||||
{
|
||||
_evaluationsTotal.Add(1,
|
||||
new KeyValuePair<string, object?>("status", status.ToString().ToLowerInvariant()),
|
||||
new KeyValuePair<string, object?>("environment", environment),
|
||||
new KeyValuePair<string, object?>("rule", matchedRule ?? "none"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record a rule match.
|
||||
/// </summary>
|
||||
public void RecordRuleMatch(
|
||||
string ruleName,
|
||||
PolicyVerdictStatus status,
|
||||
string environment)
|
||||
{
|
||||
_ruleMatchesTotal.Add(1,
|
||||
new KeyValuePair<string, object?>("rule", ruleName),
|
||||
new KeyValuePair<string, object?>("status", status.ToString().ToLowerInvariant()),
|
||||
new KeyValuePair<string, object?>("environment", environment));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record an observation state transition.
|
||||
/// </summary>
|
||||
public void RecordStateTransition(
|
||||
ObservationState fromState,
|
||||
ObservationState toState,
|
||||
string trigger,
|
||||
string environment)
|
||||
{
|
||||
_stateTransitionsTotal.Add(1,
|
||||
new KeyValuePair<string, object?>("from_state", fromState.ToString().ToLowerInvariant()),
|
||||
new KeyValuePair<string, object?>("to_state", toState.ToString().ToLowerInvariant()),
|
||||
new KeyValuePair<string, object?>("trigger", trigger),
|
||||
new KeyValuePair<string, object?>("environment", environment));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record entropy value from evaluation.
|
||||
/// </summary>
|
||||
public void RecordEntropy(double entropy, string environment)
|
||||
{
|
||||
_entropyDistribution.Record(
|
||||
entropy,
|
||||
new KeyValuePair<string, object?>("environment", environment));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record trust score from evaluation.
|
||||
/// </summary>
|
||||
public void RecordTrustScore(double trustScore, string environment)
|
||||
{
|
||||
_trustScoreDistribution.Record(
|
||||
trustScore,
|
||||
new KeyValuePair<string, object?>("environment", environment));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Record evaluation duration.
|
||||
/// </summary>
|
||||
public void RecordDuration(TimeSpan duration, string environment)
|
||||
{
|
||||
_evaluationDurationMs.Record(
|
||||
duration.TotalMilliseconds,
|
||||
new KeyValuePair<string, object?>("environment", environment));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a timer scope for measuring evaluation duration.
|
||||
/// </summary>
|
||||
public IDisposable StartEvaluationTimer(string environment)
|
||||
{
|
||||
return new DurationScope(this, environment);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_meter.Dispose();
|
||||
}
|
||||
|
||||
private sealed class DurationScope : IDisposable
|
||||
{
|
||||
private readonly DeterminizationGateMetrics _metrics;
|
||||
private readonly string _environment;
|
||||
private readonly Stopwatch _stopwatch;
|
||||
|
||||
public DurationScope(DeterminizationGateMetrics metrics, string environment)
|
||||
{
|
||||
_metrics = metrics;
|
||||
_environment = environment;
|
||||
_stopwatch = Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_stopwatch.Stop();
|
||||
_metrics.RecordDuration(_stopwatch.Elapsed, _environment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
@@ -396,7 +397,7 @@ public sealed class IncrementalPolicyOrchestrator
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.Append(tenantId).Append('|');
|
||||
builder.Append(createdAt.ToString("O")).Append('|');
|
||||
builder.Append(createdAt.ToString("O", CultureInfo.InvariantCulture)).Append('|');
|
||||
|
||||
foreach (var evt in events.OrderBy(e => e.EventId, StringComparer.Ordinal))
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using StellaOps.Policy.Engine.Orchestration;
|
||||
|
||||
@@ -55,7 +56,7 @@ internal sealed class LedgerExportService
|
||||
AdvisoryId: item.AdvisoryId,
|
||||
Status: item.Status,
|
||||
TraceRef: item.TraceRef,
|
||||
OccurredAt: result.CompletedAt.ToString("O")));
|
||||
OccurredAt: result.CompletedAt.ToString("O", CultureInfo.InvariantCulture)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +67,7 @@ internal sealed class LedgerExportService
|
||||
.ThenBy(r => r.AdvisoryId, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
|
||||
var generatedAt = _timeProvider.GetUtcNow().ToString("O");
|
||||
var generatedAt = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture);
|
||||
var exportId = StableIdGenerator.CreateUlid($"{request.TenantId}|{generatedAt}|{ordered.Count}");
|
||||
|
||||
var recordLines = ordered.Select(r => JsonSerializer.Serialize(r, SerializerOptions)).ToList();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Orchestration;
|
||||
@@ -95,7 +96,7 @@ internal sealed class OrchestratorJobService
|
||||
.Append(request.ContextId).Append('|')
|
||||
.Append(request.PolicyProfileHash).Append('|')
|
||||
.Append(priority).Append('|')
|
||||
.Append(requestedAt.ToString("O"));
|
||||
.Append(requestedAt.ToString("O", CultureInfo.InvariantCulture));
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Overlay;
|
||||
@@ -36,7 +37,7 @@ internal sealed class OverlayChangeEventPublisher
|
||||
string correlationId,
|
||||
PathDecisionDelta? delta = null)
|
||||
{
|
||||
var emittedAt = _timeProvider.GetUtcNow().ToString("O");
|
||||
var emittedAt = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture);
|
||||
return new OverlayChangeEvent(
|
||||
Tenant: tenant,
|
||||
RuleId: projection.RuleId,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
using StellaOps.Policy.Engine.Streaming;
|
||||
@@ -40,7 +41,7 @@ internal sealed class OverlayProjectionService
|
||||
|
||||
var projections = new List<OverlayProjection>(orderedTargets.Count);
|
||||
var version = 1;
|
||||
var effectiveAt = _timeProvider.GetUtcNow().ToString("O");
|
||||
var effectiveAt = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture);
|
||||
|
||||
foreach (var target in orderedTargets)
|
||||
{
|
||||
|
||||
@@ -197,7 +197,7 @@ public sealed class DeterminizationRuleSet
|
||||
ReevalAfter = TimeSpan.FromDays(3),
|
||||
Notes = $"Strict guardrails: entropy={ctx.UncertaintyScore.Entropy:F2}, trust={ctx.TrustScore:F2}, env={ctx.Environment}"
|
||||
},
|
||||
_ => GuardRails.Default()
|
||||
_ => GuardRails.Default
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Policy.RiskProfile.Scope;
|
||||
|
||||
@@ -155,7 +156,7 @@ internal sealed class EffectivePolicyAuditor : IEffectivePolicyAuditor
|
||||
var scope = new Dictionary<string, object?>
|
||||
{
|
||||
["event"] = eventType,
|
||||
["timestamp"] = _timeProvider.GetUtcNow().ToString("O")
|
||||
["timestamp"] = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(actorId))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using StellaOps.Policy.Engine.Ledger;
|
||||
using StellaOps.Policy.Engine.Orchestration;
|
||||
|
||||
@@ -40,7 +41,7 @@ internal sealed class SnapshotService
|
||||
.GroupBy(r => r.Status)
|
||||
.ToDictionary(g => g.Key, g => g.Count(), StringComparer.Ordinal);
|
||||
|
||||
var generatedAt = _timeProvider.GetUtcNow().ToString("O");
|
||||
var generatedAt = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture);
|
||||
var snapshotId = StableIdGenerator.CreateUlid($"{export.Manifest.ExportId}|{request.OverlayHash}");
|
||||
|
||||
var snapshot = new SnapshotDetail(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using OpenTelemetry.Trace;
|
||||
@@ -62,7 +63,7 @@ public sealed class IncidentModeService
|
||||
_logger.LogWarning(
|
||||
"Incident mode ENABLED. Reason: {Reason}, ExpiresAt: {ExpiresAt}",
|
||||
reason,
|
||||
expiresAt?.ToString("O") ?? "never");
|
||||
expiresAt?.ToString("O", CultureInfo.InvariantCulture) ?? "never");
|
||||
|
||||
PolicyEngineTelemetry.RecordError("incident_mode_enabled", null);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -48,7 +49,7 @@ internal sealed class TrustWeightingService
|
||||
|
||||
private IReadOnlyList<TrustWeightingEntry> Normalize(IReadOnlyList<TrustWeightingEntry> entries)
|
||||
{
|
||||
var now = _timeProvider.GetUtcNow().ToString("O");
|
||||
var now = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture);
|
||||
|
||||
var normalized = entries
|
||||
.Where(e => !string.IsNullOrWhiteSpace(e.Source))
|
||||
@@ -65,7 +66,7 @@ internal sealed class TrustWeightingService
|
||||
|
||||
private static IReadOnlyList<TrustWeightingEntry> DefaultWeights()
|
||||
{
|
||||
var now = TimeProvider.System.GetUtcNow().ToString("O");
|
||||
var now = TimeProvider.System.GetUtcNow().ToString("O", CultureInfo.InvariantCulture);
|
||||
return new[]
|
||||
{
|
||||
new TrustWeightingEntry("cartographer", 1.000m, null, now),
|
||||
|
||||
Reference in New Issue
Block a user