finish secrets finding work and audit remarks work save
This commit is contained in:
@@ -57,11 +57,13 @@ public interface IBaselineAnalyzer
|
||||
public sealed class BaselineAnalyzer : IBaselineAnalyzer
|
||||
{
|
||||
private readonly ILogger<BaselineAnalyzer> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly Dictionary<string, Regex> _compiledPatterns = new();
|
||||
|
||||
public BaselineAnalyzer(ILogger<BaselineAnalyzer> logger)
|
||||
public BaselineAnalyzer(ILogger<BaselineAnalyzer> logger, TimeProvider? timeProvider = null)
|
||||
{
|
||||
_logger = logger;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public async Task<BaselineReport> AnalyzeAsync(
|
||||
@@ -97,7 +99,7 @@ public sealed class BaselineAnalyzer : IBaselineAnalyzer
|
||||
{
|
||||
ReportId = Guid.NewGuid(),
|
||||
ScanId = context.ScanId,
|
||||
GeneratedAt = DateTimeOffset.UtcNow,
|
||||
GeneratedAt = _timeProvider.GetUtcNow(),
|
||||
ConfigUsed = context.Config.ConfigId,
|
||||
EntryPoints = entryPoints.ToImmutableArray(),
|
||||
Statistics = statistics,
|
||||
|
||||
@@ -56,7 +56,8 @@ public sealed record BinaryAnalysisResult(
|
||||
string binaryPath,
|
||||
string binaryHash,
|
||||
BinaryArchitecture architecture = BinaryArchitecture.Unknown,
|
||||
BinaryFormat format = BinaryFormat.Unknown) => new(
|
||||
BinaryFormat format = BinaryFormat.Unknown,
|
||||
TimeProvider? timeProvider = null) => new(
|
||||
binaryPath,
|
||||
binaryHash,
|
||||
architecture,
|
||||
@@ -66,7 +67,7 @@ public sealed record BinaryAnalysisResult(
|
||||
ImmutableArray<SourceCorrelation>.Empty,
|
||||
ImmutableArray<VulnerableFunctionMatch>.Empty,
|
||||
BinaryAnalysisMetrics.Empty,
|
||||
DateTimeOffset.UtcNow);
|
||||
(timeProvider ?? TimeProvider.System).GetUtcNow());
|
||||
|
||||
/// <summary>
|
||||
/// Gets functions at high-confidence correlation.
|
||||
@@ -324,18 +325,22 @@ public sealed class BinaryAnalysisResultBuilder
|
||||
private readonly Dictionary<long, SymbolInfo> _symbols = new();
|
||||
private readonly List<SourceCorrelation> _correlations = new();
|
||||
private readonly List<VulnerableFunctionMatch> _vulnerableMatches = new();
|
||||
private readonly DateTimeOffset _startTime = DateTimeOffset.UtcNow;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly DateTimeOffset _startTime;
|
||||
|
||||
public BinaryAnalysisResultBuilder(
|
||||
string binaryPath,
|
||||
string binaryHash,
|
||||
BinaryArchitecture architecture = BinaryArchitecture.Unknown,
|
||||
BinaryFormat format = BinaryFormat.Unknown)
|
||||
BinaryFormat format = BinaryFormat.Unknown,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_binaryPath = binaryPath;
|
||||
_binaryHash = binaryHash;
|
||||
_architecture = architecture;
|
||||
_format = format;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_startTime = _timeProvider.GetUtcNow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -379,7 +384,8 @@ public sealed class BinaryAnalysisResultBuilder
|
||||
/// </summary>
|
||||
public BinaryAnalysisResult Build()
|
||||
{
|
||||
var duration = DateTimeOffset.UtcNow - _startTime;
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var duration = now - _startTime;
|
||||
|
||||
var metrics = new BinaryAnalysisMetrics(
|
||||
TotalFunctions: _functions.Count,
|
||||
@@ -401,6 +407,6 @@ public sealed class BinaryAnalysisResultBuilder
|
||||
_correlations.OrderBy(c => c.BinaryOffset).ToImmutableArray(),
|
||||
_vulnerableMatches.OrderByDescending(m => m.Severity).ToImmutableArray(),
|
||||
metrics,
|
||||
DateTimeOffset.UtcNow);
|
||||
now);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public sealed class BinaryIntelligenceAnalyzer
|
||||
private readonly ISymbolRecovery _symbolRecovery;
|
||||
private readonly VulnerableFunctionMatcher _vulnerabilityMatcher;
|
||||
private readonly BinaryIntelligenceOptions _options;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new binary intelligence analyzer.
|
||||
@@ -25,12 +26,14 @@ public sealed class BinaryIntelligenceAnalyzer
|
||||
IFingerprintIndex? fingerprintIndex = null,
|
||||
ISymbolRecovery? symbolRecovery = null,
|
||||
VulnerableFunctionMatcher? vulnerabilityMatcher = null,
|
||||
BinaryIntelligenceOptions? options = null)
|
||||
BinaryIntelligenceOptions? options = null,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_fingerprintGenerator = fingerprintGenerator ?? new CombinedFingerprintGenerator();
|
||||
_fingerprintIndex = fingerprintIndex ?? new InMemoryFingerprintIndex();
|
||||
_fingerprintIndex = fingerprintIndex ?? new InMemoryFingerprintIndex(_timeProvider);
|
||||
_symbolRecovery = symbolRecovery ?? new PatternBasedSymbolRecovery();
|
||||
_vulnerabilityMatcher = vulnerabilityMatcher ?? new VulnerableFunctionMatcher(_fingerprintIndex);
|
||||
_vulnerabilityMatcher = vulnerabilityMatcher ?? new VulnerableFunctionMatcher(_fingerprintIndex, timeProvider: _timeProvider);
|
||||
_options = options ?? BinaryIntelligenceOptions.Default;
|
||||
}
|
||||
|
||||
@@ -53,7 +56,7 @@ public sealed class BinaryIntelligenceAnalyzer
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var builder = new BinaryAnalysisResultBuilder(binaryPath, binaryHash, architecture, format);
|
||||
var builder = new BinaryAnalysisResultBuilder(binaryPath, binaryHash, architecture, format, _timeProvider);
|
||||
|
||||
// Phase 1: Generate fingerprints for all functions
|
||||
var fingerprints = new Dictionary<long, CodeFingerprint>();
|
||||
@@ -186,7 +189,7 @@ public sealed class BinaryIntelligenceAnalyzer
|
||||
SourceLine: null,
|
||||
VulnerabilityIds: vulnerabilityIds?.ToImmutableArray() ?? ImmutableArray<string>.Empty,
|
||||
Similarity: 1.0f,
|
||||
MatchedAt: DateTimeOffset.UtcNow);
|
||||
MatchedAt: _timeProvider.GetUtcNow());
|
||||
|
||||
if (await _fingerprintIndex.AddAsync(entry, cancellationToken))
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ public sealed class FingerprintCorpusBuilder
|
||||
private readonly IFingerprintGenerator _fingerprintGenerator;
|
||||
private readonly IFingerprintIndex _targetIndex;
|
||||
private readonly FingerprintCorpusOptions _options;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly List<CorpusBuildRecord> _buildHistory = new();
|
||||
|
||||
/// <summary>
|
||||
@@ -22,11 +23,13 @@ public sealed class FingerprintCorpusBuilder
|
||||
public FingerprintCorpusBuilder(
|
||||
IFingerprintIndex targetIndex,
|
||||
IFingerprintGenerator? fingerprintGenerator = null,
|
||||
FingerprintCorpusOptions? options = null)
|
||||
FingerprintCorpusOptions? options = null,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_targetIndex = targetIndex;
|
||||
_fingerprintGenerator = fingerprintGenerator ?? new CombinedFingerprintGenerator();
|
||||
_options = options ?? FingerprintCorpusOptions.Default;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,7 +44,7 @@ public sealed class FingerprintCorpusBuilder
|
||||
IReadOnlyList<FunctionSignature> functions,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var startTime = DateTimeOffset.UtcNow;
|
||||
var startTime = _timeProvider.GetUtcNow();
|
||||
var indexed = 0;
|
||||
var skipped = 0;
|
||||
var duplicates = 0;
|
||||
@@ -93,7 +96,7 @@ public sealed class FingerprintCorpusBuilder
|
||||
SourceLine: null,
|
||||
VulnerabilityIds: package.VulnerabilityIds,
|
||||
Similarity: 1.0f,
|
||||
MatchedAt: DateTimeOffset.UtcNow);
|
||||
MatchedAt: _timeProvider.GetUtcNow());
|
||||
|
||||
var added = await _targetIndex.AddAsync(entry, cancellationToken);
|
||||
|
||||
@@ -119,9 +122,9 @@ public sealed class FingerprintCorpusBuilder
|
||||
Skipped: skipped,
|
||||
Duplicates: duplicates,
|
||||
Errors: errors.ToImmutableArray(),
|
||||
Duration: DateTimeOffset.UtcNow - startTime);
|
||||
Duration: _timeProvider.GetUtcNow() - startTime);
|
||||
|
||||
_buildHistory.Add(new CorpusBuildRecord(package.Purl, package.Version, result, DateTimeOffset.UtcNow));
|
||||
_buildHistory.Add(new CorpusBuildRecord(package.Purl, package.Version, result, _timeProvider.GetUtcNow()));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -207,7 +210,7 @@ public sealed class FingerprintCorpusBuilder
|
||||
// For now, export build history as a summary
|
||||
var data = new CorpusExportData
|
||||
{
|
||||
ExportedAt = DateTimeOffset.UtcNow,
|
||||
ExportedAt = _timeProvider.GetUtcNow(),
|
||||
Statistics = _targetIndex.GetStatistics(),
|
||||
Entries = Array.Empty<CorpusEntryData>() // Full export would need index enumeration
|
||||
};
|
||||
|
||||
@@ -140,7 +140,18 @@ public sealed class InMemoryFingerprintIndex : IFingerprintIndex
|
||||
private readonly ConcurrentDictionary<FingerprintAlgorithm, List<FingerprintMatch>> _algorithmIndex = new();
|
||||
private readonly HashSet<string> _packages = new();
|
||||
private readonly object _packagesLock = new();
|
||||
private DateTimeOffset _lastUpdated = DateTimeOffset.UtcNow;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private DateTimeOffset _lastUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new in-memory fingerprint index.
|
||||
/// </summary>
|
||||
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
|
||||
public InMemoryFingerprintIndex(TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_lastUpdated = _timeProvider.GetUtcNow();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Count => _exactIndex.Count;
|
||||
@@ -182,7 +193,7 @@ public sealed class InMemoryFingerprintIndex : IFingerprintIndex
|
||||
_packages.Add(match.SourcePackage);
|
||||
}
|
||||
|
||||
_lastUpdated = DateTimeOffset.UtcNow;
|
||||
_lastUpdated = _timeProvider.GetUtcNow();
|
||||
}
|
||||
|
||||
return Task.FromResult(added);
|
||||
@@ -302,7 +313,7 @@ public sealed class InMemoryFingerprintIndex : IFingerprintIndex
|
||||
SourceLine: null,
|
||||
VulnerabilityIds: ImmutableArray<string>.Empty,
|
||||
Similarity: 1.0f,
|
||||
MatchedAt: DateTimeOffset.UtcNow);
|
||||
MatchedAt: _timeProvider.GetUtcNow());
|
||||
|
||||
return AddAsync(match, cancellationToken).ContinueWith(_ => { }, cancellationToken);
|
||||
}
|
||||
@@ -313,9 +324,20 @@ public sealed class InMemoryFingerprintIndex : IFingerprintIndex
|
||||
/// </summary>
|
||||
public sealed class VulnerableFingerprintIndex : IFingerprintIndex
|
||||
{
|
||||
private readonly InMemoryFingerprintIndex _baseIndex = new();
|
||||
private readonly InMemoryFingerprintIndex _baseIndex;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly ConcurrentDictionary<string, VulnerabilityInfo> _vulnerabilities = new();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new vulnerability-aware fingerprint index.
|
||||
/// </summary>
|
||||
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
|
||||
public VulnerableFingerprintIndex(TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_baseIndex = new InMemoryFingerprintIndex(_timeProvider);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Count => _baseIndex.Count;
|
||||
|
||||
@@ -344,7 +366,7 @@ public sealed class VulnerableFingerprintIndex : IFingerprintIndex
|
||||
SourceLine: null,
|
||||
VulnerabilityIds: ImmutableArray.Create(vulnerabilityId),
|
||||
Similarity: 1.0f,
|
||||
MatchedAt: DateTimeOffset.UtcNow);
|
||||
MatchedAt: _timeProvider.GetUtcNow());
|
||||
|
||||
var added = await _baseIndex.AddAsync(match, cancellationToken);
|
||||
|
||||
|
||||
@@ -11,16 +11,19 @@ public sealed class VulnerableFunctionMatcher
|
||||
{
|
||||
private readonly IFingerprintIndex _index;
|
||||
private readonly VulnerableMatcherOptions _options;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new vulnerable function matcher.
|
||||
/// </summary>
|
||||
public VulnerableFunctionMatcher(
|
||||
IFingerprintIndex index,
|
||||
VulnerableMatcherOptions? options = null)
|
||||
VulnerableMatcherOptions? options = null,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_index = index;
|
||||
_options = options ?? VulnerableMatcherOptions.Default;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -165,7 +168,7 @@ public sealed class VulnerableFunctionMatcher
|
||||
SourceLine: null,
|
||||
VulnerabilityIds: ImmutableArray.Create(vulnerabilityId),
|
||||
Similarity: 1.0f,
|
||||
MatchedAt: DateTimeOffset.UtcNow);
|
||||
MatchedAt: _timeProvider.GetUtcNow());
|
||||
|
||||
return await _index.AddAsync(entry, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -11,12 +11,13 @@ public sealed class CompositeRiskScorer : IRiskScorer
|
||||
{
|
||||
private readonly ImmutableArray<IRiskContributor> _contributors;
|
||||
private readonly CompositeRiskScorerOptions _options;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a composite scorer with default contributors.
|
||||
/// </summary>
|
||||
public CompositeRiskScorer(CompositeRiskScorerOptions? options = null)
|
||||
: this(GetDefaultContributors(), options)
|
||||
public CompositeRiskScorer(CompositeRiskScorerOptions? options = null, TimeProvider? timeProvider = null)
|
||||
: this(GetDefaultContributors(), options, timeProvider)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -25,10 +26,12 @@ public sealed class CompositeRiskScorer : IRiskScorer
|
||||
/// </summary>
|
||||
public CompositeRiskScorer(
|
||||
IEnumerable<IRiskContributor> contributors,
|
||||
CompositeRiskScorerOptions? options = null)
|
||||
CompositeRiskScorerOptions? options = null,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_contributors = contributors.ToImmutableArray();
|
||||
_options = options ?? CompositeRiskScorerOptions.Default;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -66,7 +69,7 @@ public sealed class CompositeRiskScorer : IRiskScorer
|
||||
Factors: allFactors.ToImmutableArray(),
|
||||
BusinessContext: businessContext,
|
||||
Recommendations: recommendations,
|
||||
AssessedAt: DateTimeOffset.UtcNow);
|
||||
AssessedAt: _timeProvider.GetUtcNow());
|
||||
}
|
||||
|
||||
private RiskScore ComputeOverallScore(
|
||||
@@ -75,7 +78,7 @@ public sealed class CompositeRiskScorer : IRiskScorer
|
||||
{
|
||||
if (factors.Count == 0)
|
||||
{
|
||||
return RiskScore.Zero;
|
||||
return RiskScore.Zero(_timeProvider);
|
||||
}
|
||||
|
||||
// Weighted average of factor contributions
|
||||
@@ -106,7 +109,7 @@ public sealed class CompositeRiskScorer : IRiskScorer
|
||||
OverallScore: baseScore,
|
||||
Category: primaryCategory,
|
||||
Confidence: confidence,
|
||||
ComputedAt: DateTimeOffset.UtcNow);
|
||||
ComputedAt: _timeProvider.GetUtcNow());
|
||||
}
|
||||
|
||||
private float ComputeConfidence(IReadOnlyList<RiskFactor> factors)
|
||||
@@ -217,6 +220,17 @@ public sealed record CompositeRiskScorerOptions(
|
||||
/// </summary>
|
||||
public sealed class RiskExplainer
|
||||
{
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new risk explainer.
|
||||
/// </summary>
|
||||
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
|
||||
public RiskExplainer(TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a summary explanation for a risk assessment.
|
||||
/// </summary>
|
||||
@@ -268,7 +282,7 @@ public sealed class RiskExplainer
|
||||
Confidence: assessment.OverallScore.Confidence,
|
||||
TopFactors: ExplainFactors(assessment),
|
||||
Recommendations: assessment.Recommendations,
|
||||
GeneratedAt: DateTimeOffset.UtcNow);
|
||||
GeneratedAt: _timeProvider.GetUtcNow());
|
||||
}
|
||||
|
||||
private static string CategoryToString(RiskCategory category) => category switch
|
||||
@@ -313,6 +327,17 @@ public sealed record RiskReport(
|
||||
/// </summary>
|
||||
public sealed class RiskAggregator
|
||||
{
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new risk aggregator.
|
||||
/// </summary>
|
||||
/// <param name="timeProvider">Optional time provider for deterministic timestamps.</param>
|
||||
public RiskAggregator(TimeProvider? timeProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates assessments for a fleet-level view.
|
||||
/// </summary>
|
||||
@@ -322,7 +347,7 @@ public sealed class RiskAggregator
|
||||
|
||||
if (assessmentList.Count == 0)
|
||||
{
|
||||
return FleetRiskSummary.Empty;
|
||||
return FleetRiskSummary.CreateEmpty(_timeProvider);
|
||||
}
|
||||
|
||||
var distribution = assessmentList
|
||||
@@ -349,7 +374,7 @@ public sealed class RiskAggregator
|
||||
Distribution: distribution.ToImmutableDictionary(),
|
||||
CategoryBreakdown: categoryBreakdown.ToImmutableDictionary(),
|
||||
TopRisks: topRisks,
|
||||
AggregatedAt: DateTimeOffset.UtcNow);
|
||||
AggregatedAt: _timeProvider.GetUtcNow());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,16 +398,22 @@ public sealed record FleetRiskSummary(
|
||||
DateTimeOffset AggregatedAt)
|
||||
{
|
||||
/// <summary>
|
||||
/// Empty summary.
|
||||
/// Empty summary with specified timestamp.
|
||||
/// </summary>
|
||||
public static FleetRiskSummary Empty => new(
|
||||
public static FleetRiskSummary CreateEmpty(TimeProvider? timeProvider = null) => new(
|
||||
TotalSubjects: 0,
|
||||
AverageScore: 0,
|
||||
AverageConfidence: 0,
|
||||
Distribution: ImmutableDictionary<RiskLevel, int>.Empty,
|
||||
CategoryBreakdown: ImmutableDictionary<RiskCategory, int>.Empty,
|
||||
TopRisks: ImmutableArray<RiskSummaryItem>.Empty,
|
||||
AggregatedAt: DateTimeOffset.UtcNow);
|
||||
AggregatedAt: (timeProvider ?? TimeProvider.System).GetUtcNow());
|
||||
|
||||
/// <summary>
|
||||
/// Empty summary (uses current time).
|
||||
/// </summary>
|
||||
[Obsolete("Use CreateEmpty(TimeProvider) for deterministic timestamps")]
|
||||
public static FleetRiskSummary Empty => CreateEmpty();
|
||||
|
||||
/// <summary>
|
||||
/// Count of critical/high risk subjects.
|
||||
|
||||
@@ -20,31 +20,32 @@ public sealed record RiskScore(
|
||||
/// <summary>
|
||||
/// Creates a zero risk score.
|
||||
/// </summary>
|
||||
public static RiskScore Zero => new(0.0f, RiskCategory.Unknown, 1.0f, DateTimeOffset.UtcNow);
|
||||
public static RiskScore Zero(TimeProvider? timeProvider = null)
|
||||
=> new(0.0f, RiskCategory.Unknown, 1.0f, (timeProvider ?? TimeProvider.System).GetUtcNow());
|
||||
|
||||
/// <summary>
|
||||
/// Creates a critical risk score.
|
||||
/// </summary>
|
||||
public static RiskScore Critical(RiskCategory category, float confidence = 0.9f)
|
||||
=> new(1.0f, category, confidence, DateTimeOffset.UtcNow);
|
||||
public static RiskScore Critical(RiskCategory category, float confidence = 0.9f, TimeProvider? timeProvider = null)
|
||||
=> new(1.0f, category, confidence, (timeProvider ?? TimeProvider.System).GetUtcNow());
|
||||
|
||||
/// <summary>
|
||||
/// Creates a high risk score.
|
||||
/// </summary>
|
||||
public static RiskScore High(RiskCategory category, float confidence = 0.85f)
|
||||
=> new(0.85f, category, confidence, DateTimeOffset.UtcNow);
|
||||
public static RiskScore High(RiskCategory category, float confidence = 0.85f, TimeProvider? timeProvider = null)
|
||||
=> new(0.85f, category, confidence, (timeProvider ?? TimeProvider.System).GetUtcNow());
|
||||
|
||||
/// <summary>
|
||||
/// Creates a medium risk score.
|
||||
/// </summary>
|
||||
public static RiskScore Medium(RiskCategory category, float confidence = 0.8f)
|
||||
=> new(0.5f, category, confidence, DateTimeOffset.UtcNow);
|
||||
public static RiskScore Medium(RiskCategory category, float confidence = 0.8f, TimeProvider? timeProvider = null)
|
||||
=> new(0.5f, category, confidence, (timeProvider ?? TimeProvider.System).GetUtcNow());
|
||||
|
||||
/// <summary>
|
||||
/// Creates a low risk score.
|
||||
/// </summary>
|
||||
public static RiskScore Low(RiskCategory category, float confidence = 0.75f)
|
||||
=> new(0.2f, category, confidence, DateTimeOffset.UtcNow);
|
||||
public static RiskScore Low(RiskCategory category, float confidence = 0.75f, TimeProvider? timeProvider = null)
|
||||
=> new(0.2f, category, confidence, (timeProvider ?? TimeProvider.System).GetUtcNow());
|
||||
|
||||
/// <summary>
|
||||
/// Descriptive risk level based on score.
|
||||
@@ -349,14 +350,18 @@ public sealed record RiskAssessment(
|
||||
/// <summary>
|
||||
/// Creates an empty assessment for a subject with no risk data.
|
||||
/// </summary>
|
||||
public static RiskAssessment Empty(string subjectId, SubjectType subjectType) => new(
|
||||
SubjectId: subjectId,
|
||||
SubjectType: subjectType,
|
||||
OverallScore: RiskScore.Zero,
|
||||
Factors: ImmutableArray<RiskFactor>.Empty,
|
||||
BusinessContext: null,
|
||||
Recommendations: ImmutableArray<string>.Empty,
|
||||
AssessedAt: DateTimeOffset.UtcNow);
|
||||
public static RiskAssessment Empty(string subjectId, SubjectType subjectType, TimeProvider? timeProvider = null)
|
||||
{
|
||||
var tp = timeProvider ?? TimeProvider.System;
|
||||
return new(
|
||||
SubjectId: subjectId,
|
||||
SubjectType: subjectType,
|
||||
OverallScore: RiskScore.Zero(tp),
|
||||
Factors: ImmutableArray<RiskFactor>.Empty,
|
||||
BusinessContext: null,
|
||||
Recommendations: ImmutableArray<string>.Empty,
|
||||
AssessedAt: tp.GetUtcNow());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -16,21 +16,25 @@ public sealed class SemanticEntryTraceAnalyzer : ISemanticEntryTraceAnalyzer
|
||||
private readonly IEntryTraceAnalyzer _baseAnalyzer;
|
||||
private readonly SemanticEntrypointOrchestrator _orchestrator;
|
||||
private readonly ILogger<SemanticEntryTraceAnalyzer> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public SemanticEntryTraceAnalyzer(
|
||||
IEntryTraceAnalyzer baseAnalyzer,
|
||||
SemanticEntrypointOrchestrator orchestrator,
|
||||
ILogger<SemanticEntryTraceAnalyzer> logger)
|
||||
ILogger<SemanticEntryTraceAnalyzer> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_baseAnalyzer = baseAnalyzer ?? throw new ArgumentNullException(nameof(baseAnalyzer));
|
||||
_orchestrator = orchestrator ?? throw new ArgumentNullException(nameof(orchestrator));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public SemanticEntryTraceAnalyzer(
|
||||
IEntryTraceAnalyzer baseAnalyzer,
|
||||
ILogger<SemanticEntryTraceAnalyzer> logger)
|
||||
: this(baseAnalyzer, new SemanticEntrypointOrchestrator(), logger)
|
||||
ILogger<SemanticEntryTraceAnalyzer> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
: this(baseAnalyzer, new SemanticEntrypointOrchestrator(), logger, timeProvider)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -52,7 +56,7 @@ public sealed class SemanticEntryTraceAnalyzer : ISemanticEntryTraceAnalyzer
|
||||
var traceResult = new EntryTraceResult(
|
||||
context.ScanId,
|
||||
context.ImageDigest,
|
||||
DateTimeOffset.UtcNow,
|
||||
_timeProvider.GetUtcNow(),
|
||||
graph,
|
||||
SerializeToNdjson(graph));
|
||||
|
||||
@@ -98,7 +102,7 @@ public sealed class SemanticEntryTraceAnalyzer : ISemanticEntryTraceAnalyzer
|
||||
TraceResult = traceResult,
|
||||
SemanticEntrypoint = semanticResult,
|
||||
AnalysisResult = analysisResult,
|
||||
AnalyzedAt = DateTimeOffset.UtcNow
|
||||
AnalyzedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user