sprints work
This commit is contained in:
@@ -11,6 +11,7 @@ using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Concelier.BackportProof.Models;
|
||||
using StellaOps.Concelier.BackportProof.Repositories;
|
||||
using StellaOps.Determinism;
|
||||
|
||||
namespace StellaOps.Concelier.BackportProof.Services;
|
||||
|
||||
@@ -22,6 +23,8 @@ public sealed class FixIndexService : IFixIndexService
|
||||
{
|
||||
private readonly IFixRuleRepository _repository;
|
||||
private readonly ILogger<FixIndexService> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
|
||||
// Active in-memory index
|
||||
private FixIndexState? _activeIndex;
|
||||
@@ -32,10 +35,14 @@ public sealed class FixIndexService : IFixIndexService
|
||||
|
||||
public FixIndexService(
|
||||
IFixRuleRepository repository,
|
||||
ILogger<FixIndexService> logger)
|
||||
ILogger<FixIndexService> logger,
|
||||
TimeProvider? timeProvider = null,
|
||||
IGuidProvider? guidProvider = null)
|
||||
{
|
||||
_repository = repository;
|
||||
_logger = logger;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
}
|
||||
|
||||
public ValueTask<string?> GetActiveSnapshotIdAsync(CancellationToken ct = default)
|
||||
@@ -52,7 +59,7 @@ public sealed class FixIndexService : IFixIndexService
|
||||
{
|
||||
_logger.LogInformation("Creating fix index snapshot: {Label}", sourceLabel);
|
||||
|
||||
var startTime = DateTimeOffset.UtcNow;
|
||||
var startTime = _timeProvider.GetUtcNow();
|
||||
|
||||
// Load all rules from repository
|
||||
// In a real implementation, this would need pagination for large datasets
|
||||
@@ -66,7 +73,7 @@ public sealed class FixIndexService : IFixIndexService
|
||||
var index = BuildIndex(allRules);
|
||||
|
||||
// Generate snapshot ID and digest
|
||||
var snapshotId = $"fix-index-{DateTimeOffset.UtcNow:yyyyMMddHHmmss}-{Guid.NewGuid():N}";
|
||||
var snapshotId = $"fix-index-{_timeProvider.GetUtcNow():yyyyMMddHHmmss}-{_guidProvider.NewGuid():N}";
|
||||
var digest = ComputeIndexDigest(allRules);
|
||||
|
||||
var snapshot = new FixIndexSnapshot(
|
||||
@@ -84,7 +91,7 @@ public sealed class FixIndexService : IFixIndexService
|
||||
// Store snapshot
|
||||
_snapshots[snapshotId] = indexState;
|
||||
|
||||
var elapsed = DateTimeOffset.UtcNow - startTime;
|
||||
var elapsed = _timeProvider.GetUtcNow() - startTime;
|
||||
_logger.LogInformation(
|
||||
"Created snapshot {SnapshotId} with {Count} rules in {Elapsed}ms",
|
||||
snapshotId, allRules.Count, elapsed.TotalMilliseconds);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.Determinism.Abstractions/StellaOps.Determinism.Abstractions.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.Infrastructure.Postgres/StellaOps.Infrastructure.Postgres.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.VersionComparison/StellaOps.VersionComparison.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.DistroIntel/StellaOps.DistroIntel.csproj" />
|
||||
|
||||
@@ -20,15 +20,18 @@ public sealed partial class ProvenanceScopeService : IProvenanceScopeService
|
||||
private readonly IProvenanceScopeStore _store;
|
||||
private readonly IBackportEvidenceResolver? _evidenceResolver;
|
||||
private readonly ILogger<ProvenanceScopeService> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public ProvenanceScopeService(
|
||||
IProvenanceScopeStore store,
|
||||
ILogger<ProvenanceScopeService> logger,
|
||||
IBackportEvidenceResolver? evidenceResolver = null)
|
||||
IBackportEvidenceResolver? evidenceResolver = null,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_store = store ?? throw new ArgumentNullException(nameof(store));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_evidenceResolver = evidenceResolver; // Optional - if not provided, uses advisory data only
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -89,8 +92,8 @@ public sealed partial class ProvenanceScopeService : IProvenanceScopeService
|
||||
PatchOrigin = evidence?.PatchOrigin ?? DeterminePatchOrigin(request.Source),
|
||||
EvidenceRef = null, // Will be linked separately
|
||||
Confidence = evidence?.Confidence ?? DetermineDefaultConfidence(request.Source),
|
||||
CreatedAt = existing?.CreatedAt ?? DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
CreatedAt = existing?.CreatedAt ?? _timeProvider.GetUtcNow(),
|
||||
UpdatedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
|
||||
// 5. Upsert scope
|
||||
@@ -154,8 +157,8 @@ public sealed partial class ProvenanceScopeService : IProvenanceScopeService
|
||||
PatchOrigin = evidence.PatchOrigin,
|
||||
EvidenceRef = null,
|
||||
Confidence = evidence.Confidence,
|
||||
CreatedAt = existing?.CreatedAt ?? DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
CreatedAt = existing?.CreatedAt ?? _timeProvider.GetUtcNow(),
|
||||
UpdatedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
|
||||
var scopeId = await _store.UpsertAsync(scope, ct).ConfigureAwait(false);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Persistence.Postgres.Models;
|
||||
using StellaOps.Determinism;
|
||||
|
||||
namespace StellaOps.Concelier.Persistence.Postgres.Conversion;
|
||||
|
||||
@@ -15,6 +16,20 @@ public sealed class AdvisoryConverter
|
||||
WriteIndented = false
|
||||
};
|
||||
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AdvisoryConverter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="timeProvider">Time provider for deterministic timestamps.</param>
|
||||
/// <param name="guidProvider">GUID provider for deterministic ID generation.</param>
|
||||
public AdvisoryConverter(TimeProvider? timeProvider = null, IGuidProvider? guidProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an Advisory domain model to PostgreSQL entities.
|
||||
/// </summary>
|
||||
@@ -22,8 +37,8 @@ public sealed class AdvisoryConverter
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(advisory);
|
||||
|
||||
var advisoryId = Guid.NewGuid();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var advisoryId = _guidProvider.NewGuid();
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
|
||||
var primaryVulnId = advisory.Aliases
|
||||
.FirstOrDefault(a => a.StartsWith("CVE-", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -62,7 +77,7 @@ public sealed class AdvisoryConverter
|
||||
|
||||
aliasEntities.Add(new AdvisoryAliasEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
AdvisoryId = advisoryId,
|
||||
AliasType = aliasType,
|
||||
AliasValue = alias,
|
||||
@@ -78,7 +93,7 @@ public sealed class AdvisoryConverter
|
||||
{
|
||||
cvssEntities.Add(new AdvisoryCvssEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
AdvisoryId = advisoryId,
|
||||
CvssVersion = metric.Version,
|
||||
VectorString = metric.Vector,
|
||||
@@ -103,7 +118,7 @@ public sealed class AdvisoryConverter
|
||||
|
||||
affectedEntities.Add(new AdvisoryAffectedEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
AdvisoryId = advisoryId,
|
||||
Ecosystem = ecosystem,
|
||||
PackageName = pkg.Identifier,
|
||||
@@ -119,7 +134,7 @@ public sealed class AdvisoryConverter
|
||||
// References
|
||||
var referenceEntities = advisory.References.Select(reference => new AdvisoryReferenceEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
AdvisoryId = advisoryId,
|
||||
RefType = reference.Kind ?? "web",
|
||||
Url = reference.Url,
|
||||
@@ -129,7 +144,7 @@ public sealed class AdvisoryConverter
|
||||
// Credits
|
||||
var creditEntities = advisory.Credits.Select(credit => new AdvisoryCreditEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
AdvisoryId = advisoryId,
|
||||
Name = credit.DisplayName,
|
||||
Contact = credit.Contacts.FirstOrDefault(),
|
||||
@@ -140,7 +155,7 @@ public sealed class AdvisoryConverter
|
||||
// Weaknesses
|
||||
var weaknessEntities = advisory.Cwes.Select(weakness => new AdvisoryWeaknessEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
AdvisoryId = advisoryId,
|
||||
CweId = weakness.Identifier,
|
||||
Description = weakness.Name,
|
||||
@@ -157,7 +172,7 @@ public sealed class AdvisoryConverter
|
||||
{
|
||||
kevFlags.Add(new KevFlagEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
AdvisoryId = advisoryId,
|
||||
CveId = cveId,
|
||||
VendorProject = null,
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Globalization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Npgsql;
|
||||
using StellaOps.Concelier.Persistence.Postgres.Models;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Infrastructure.Postgres.Repositories;
|
||||
|
||||
namespace StellaOps.Concelier.Persistence.Postgres.Repositories;
|
||||
@@ -19,10 +20,18 @@ namespace StellaOps.Concelier.Persistence.Postgres.Repositories;
|
||||
public sealed class SyncLedgerRepository : RepositoryBase<ConcelierDataSource>, ISyncLedgerRepository
|
||||
{
|
||||
private const string SystemTenantId = "_system";
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
|
||||
public SyncLedgerRepository(ConcelierDataSource dataSource, ILogger<SyncLedgerRepository> logger)
|
||||
public SyncLedgerRepository(
|
||||
ConcelierDataSource dataSource,
|
||||
ILogger<SyncLedgerRepository> logger,
|
||||
TimeProvider? timeProvider = null,
|
||||
IGuidProvider? guidProvider = null)
|
||||
: base(dataSource, logger)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
}
|
||||
|
||||
#region Ledger Operations
|
||||
@@ -93,7 +102,7 @@ public sealed class SyncLedgerRepository : RepositoryBase<ConcelierDataSource>,
|
||||
RETURNING id
|
||||
""";
|
||||
|
||||
var id = entry.Id == Guid.Empty ? Guid.NewGuid() : entry.Id;
|
||||
var id = entry.Id == Guid.Empty ? _guidProvider.NewGuid() : entry.Id;
|
||||
|
||||
await ExecuteAsync(
|
||||
SystemTenantId,
|
||||
@@ -106,7 +115,7 @@ public sealed class SyncLedgerRepository : RepositoryBase<ConcelierDataSource>,
|
||||
AddParameter(cmd, "bundle_hash", entry.BundleHash);
|
||||
AddParameter(cmd, "items_count", entry.ItemsCount);
|
||||
AddParameter(cmd, "signed_at", entry.SignedAt);
|
||||
AddParameter(cmd, "imported_at", entry.ImportedAt == default ? DateTimeOffset.UtcNow : entry.ImportedAt);
|
||||
AddParameter(cmd, "imported_at", entry.ImportedAt == default ? _timeProvider.GetUtcNow() : entry.ImportedAt);
|
||||
},
|
||||
ct).ConfigureAwait(false);
|
||||
|
||||
@@ -144,13 +153,13 @@ public sealed class SyncLedgerRepository : RepositoryBase<ConcelierDataSource>,
|
||||
{
|
||||
var entry = new SyncLedgerEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = _guidProvider.NewGuid(),
|
||||
SiteId = siteId,
|
||||
Cursor = newCursor,
|
||||
BundleHash = bundleHash,
|
||||
ItemsCount = itemsCount,
|
||||
SignedAt = signedAt,
|
||||
ImportedAt = DateTimeOffset.UtcNow
|
||||
ImportedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
|
||||
await InsertAsync(entry, ct).ConfigureAwait(false);
|
||||
|
||||
@@ -18,13 +18,16 @@ public sealed class SitePolicyEnforcementService
|
||||
{
|
||||
private readonly ISyncLedgerRepository _repository;
|
||||
private readonly ILogger<SitePolicyEnforcementService> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public SitePolicyEnforcementService(
|
||||
ISyncLedgerRepository repository,
|
||||
ILogger<SitePolicyEnforcementService> logger)
|
||||
ILogger<SitePolicyEnforcementService> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -301,7 +304,7 @@ public sealed class SitePolicyEnforcementService
|
||||
WindowHours: windowHours);
|
||||
}
|
||||
|
||||
var windowStart = DateTimeOffset.UtcNow.AddHours(-windowHours);
|
||||
var windowStart = _timeProvider.GetUtcNow().AddHours(-windowHours);
|
||||
var recentHistory = history.Where(h => h.ImportedAt >= windowStart).ToList();
|
||||
|
||||
return new SiteBudgetInfo(
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Determinism.Abstractions\StellaOps.Determinism.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.Postgres\StellaOps.Infrastructure.Postgres.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.EfCore\StellaOps.Infrastructure.EfCore.csproj" />
|
||||
<ProjectReference Include="..\StellaOps.Concelier.Core\StellaOps.Concelier.Core.csproj" />
|
||||
|
||||
@@ -19,19 +19,22 @@ public sealed class BackportProofService
|
||||
private readonly ISourceArtifactRepository _sourceRepo;
|
||||
private readonly IPatchRepository _patchRepo;
|
||||
private readonly BinaryFingerprintFactory _fingerprintFactory;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public BackportProofService(
|
||||
ILogger<BackportProofService> logger,
|
||||
IDistroAdvisoryRepository advisoryRepo,
|
||||
ISourceArtifactRepository sourceRepo,
|
||||
IPatchRepository patchRepo,
|
||||
BinaryFingerprintFactory fingerprintFactory)
|
||||
BinaryFingerprintFactory fingerprintFactory,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_logger = logger;
|
||||
_advisoryRepo = advisoryRepo;
|
||||
_sourceRepo = sourceRepo;
|
||||
_patchRepo = patchRepo;
|
||||
_fingerprintFactory = fingerprintFactory;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -251,7 +254,7 @@ public sealed class BackportProofService
|
||||
EvidenceId = $"evidence:binary:{matchResult.Method}:{matchResult.MatchedFingerprintId}",
|
||||
Type = EvidenceType.BinaryFingerprint,
|
||||
Source = matchResult.Method.ToString(),
|
||||
Timestamp = DateTimeOffset.UtcNow,
|
||||
Timestamp = _timeProvider.GetUtcNow(),
|
||||
Data = fingerprintData,
|
||||
DataHash = dataHash
|
||||
});
|
||||
|
||||
@@ -21,13 +21,16 @@ public sealed class SbomAdvisoryMatcher : ISbomAdvisoryMatcher
|
||||
{
|
||||
private readonly ICanonicalAdvisoryService _canonicalService;
|
||||
private readonly ILogger<SbomAdvisoryMatcher> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public SbomAdvisoryMatcher(
|
||||
ICanonicalAdvisoryService canonicalService,
|
||||
ILogger<SbomAdvisoryMatcher> logger)
|
||||
ILogger<SbomAdvisoryMatcher> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_canonicalService = canonicalService ?? throw new ArgumentNullException(nameof(canonicalService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -142,7 +145,7 @@ public sealed class SbomAdvisoryMatcher : ISbomAdvisoryMatcher
|
||||
Method = DetermineMatchMethod(purl),
|
||||
IsReachable = false,
|
||||
IsDeployed = false,
|
||||
MatchedAt = DateTimeOffset.UtcNow
|
||||
MatchedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -167,6 +170,7 @@ public sealed class SbomAdvisoryMatcher : ISbomAdvisoryMatcher
|
||||
var isReachable = reachabilityMap?.TryGetValue(purl, out var reachable) == true && reachable;
|
||||
var isDeployed = deploymentMap?.TryGetValue(purl, out var deployed) == true && deployed;
|
||||
var matchMethod = DetermineMatchMethod(purl);
|
||||
var matchedAt = _timeProvider.GetUtcNow();
|
||||
|
||||
return advisories.Select(advisory => new SbomAdvisoryMatch
|
||||
{
|
||||
@@ -178,7 +182,7 @@ public sealed class SbomAdvisoryMatcher : ISbomAdvisoryMatcher
|
||||
Method = matchMethod,
|
||||
IsReachable = isReachable,
|
||||
IsDeployed = isDeployed,
|
||||
MatchedAt = DateTimeOffset.UtcNow
|
||||
MatchedAt = matchedAt
|
||||
}).ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -21,13 +21,16 @@ public sealed class SbomAdvisoryMatcher : ISbomAdvisoryMatcher
|
||||
{
|
||||
private readonly ICanonicalAdvisoryService _canonicalService;
|
||||
private readonly ILogger<SbomAdvisoryMatcher> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public SbomAdvisoryMatcher(
|
||||
ICanonicalAdvisoryService canonicalService,
|
||||
ILogger<SbomAdvisoryMatcher> logger)
|
||||
ILogger<SbomAdvisoryMatcher> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_canonicalService = canonicalService ?? throw new ArgumentNullException(nameof(canonicalService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -142,7 +145,7 @@ public sealed class SbomAdvisoryMatcher : ISbomAdvisoryMatcher
|
||||
Method = DetermineMatchMethod(purl),
|
||||
IsReachable = false,
|
||||
IsDeployed = false,
|
||||
MatchedAt = DateTimeOffset.UtcNow
|
||||
MatchedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -168,6 +171,8 @@ public sealed class SbomAdvisoryMatcher : ISbomAdvisoryMatcher
|
||||
var isDeployed = deploymentMap?.TryGetValue(purl, out var deployed) == true && deployed;
|
||||
var matchMethod = DetermineMatchMethod(purl);
|
||||
|
||||
var matchedAt = _timeProvider.GetUtcNow();
|
||||
|
||||
return advisories.Select(advisory => new SbomAdvisoryMatch
|
||||
{
|
||||
Id = ComputeDeterministicMatchId(sbomDigest, purl, advisory.Id),
|
||||
@@ -178,7 +183,7 @@ public sealed class SbomAdvisoryMatcher : ISbomAdvisoryMatcher
|
||||
Method = matchMethod,
|
||||
IsReachable = isReachable,
|
||||
IsDeployed = isDeployed,
|
||||
MatchedAt = DateTimeOffset.UtcNow
|
||||
MatchedAt = matchedAt
|
||||
}).ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -26,19 +26,22 @@ public sealed class SbomRegistryService : ISbomRegistryService
|
||||
private readonly IInterestScoringService _scoringService;
|
||||
private readonly IEventStream<SbomLearnedEvent>? _eventStream;
|
||||
private readonly ILogger<SbomRegistryService> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public SbomRegistryService(
|
||||
ISbomRegistryRepository repository,
|
||||
ISbomAdvisoryMatcher matcher,
|
||||
IInterestScoringService scoringService,
|
||||
ILogger<SbomRegistryService> logger,
|
||||
IEventStream<SbomLearnedEvent>? eventStream = null)
|
||||
IEventStream<SbomLearnedEvent>? eventStream = null,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
|
||||
_matcher = matcher ?? throw new ArgumentNullException(nameof(matcher));
|
||||
_scoringService = scoringService ?? throw new ArgumentNullException(nameof(scoringService));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_eventStream = eventStream;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
#region Registration
|
||||
@@ -72,7 +75,7 @@ public sealed class SbomRegistryService : ISbomRegistryService
|
||||
PrimaryVersion = input.PrimaryVersion,
|
||||
ComponentCount = input.Purls.Count,
|
||||
Purls = input.Purls,
|
||||
RegisteredAt = DateTimeOffset.UtcNow,
|
||||
RegisteredAt = _timeProvider.GetUtcNow(),
|
||||
Source = input.Source,
|
||||
TenantId = input.TenantId
|
||||
};
|
||||
@@ -161,7 +164,7 @@ public sealed class SbomRegistryService : ISbomRegistryService
|
||||
// Step 4: Update registration metadata
|
||||
await _repository.UpdateAffectedCountAsync(registration.Digest, matches.Count, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await _repository.UpdateLastMatchedAsync(registration.Digest, DateTimeOffset.UtcNow, cancellationToken)
|
||||
await _repository.UpdateLastMatchedAsync(registration.Digest, _timeProvider.GetUtcNow(), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// Step 5: Update interest scores for affected canonicals
|
||||
@@ -210,7 +213,7 @@ public sealed class SbomRegistryService : ISbomRegistryService
|
||||
Registration = registration with
|
||||
{
|
||||
AffectedCount = matches.Count,
|
||||
LastMatchedAt = DateTimeOffset.UtcNow
|
||||
LastMatchedAt = _timeProvider.GetUtcNow()
|
||||
},
|
||||
Matches = matches,
|
||||
ScoresUpdated = scoresUpdated,
|
||||
@@ -270,7 +273,7 @@ public sealed class SbomRegistryService : ISbomRegistryService
|
||||
|
||||
await _repository.UpdateAffectedCountAsync(digest, matches.Count, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await _repository.UpdateLastMatchedAsync(digest, DateTimeOffset.UtcNow, cancellationToken)
|
||||
await _repository.UpdateLastMatchedAsync(digest, _timeProvider.GetUtcNow(), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
sw.Stop();
|
||||
@@ -289,7 +292,7 @@ public sealed class SbomRegistryService : ISbomRegistryService
|
||||
Registration = registration with
|
||||
{
|
||||
AffectedCount = matches.Count,
|
||||
LastMatchedAt = DateTimeOffset.UtcNow
|
||||
LastMatchedAt = _timeProvider.GetUtcNow()
|
||||
},
|
||||
Matches = matches,
|
||||
ScoresUpdated = 0, // Rematch doesn't update scores
|
||||
@@ -374,7 +377,7 @@ public sealed class SbomRegistryService : ISbomRegistryService
|
||||
|
||||
await _repository.UpdateAffectedCountAsync(digest, allMatches.Count, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
await _repository.UpdateLastMatchedAsync(digest, DateTimeOffset.UtcNow, cancellationToken)
|
||||
await _repository.UpdateLastMatchedAsync(digest, _timeProvider.GetUtcNow(), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// Update interest scores only for newly added matches
|
||||
@@ -424,7 +427,7 @@ public sealed class SbomRegistryService : ISbomRegistryService
|
||||
{
|
||||
ComponentCount = newPurls.Count,
|
||||
AffectedCount = allMatches.Count,
|
||||
LastMatchedAt = DateTimeOffset.UtcNow,
|
||||
LastMatchedAt = _timeProvider.GetUtcNow(),
|
||||
Purls = newPurls
|
||||
},
|
||||
Matches = allMatches,
|
||||
|
||||
Reference in New Issue
Block a user