save progress
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
@@ -48,12 +49,15 @@ internal sealed record RedHatCursor(
|
||||
document["lastReleasedOn"] = LastReleasedOn.Value.UtcDateTime;
|
||||
}
|
||||
|
||||
document["processedAdvisories"] = new DocumentArray(ProcessedAdvisoryIds);
|
||||
document["pendingDocuments"] = new DocumentArray(PendingDocuments.Select(id => id.ToString()));
|
||||
document["pendingMappings"] = new DocumentArray(PendingMappings.Select(id => id.ToString()));
|
||||
document["processedAdvisories"] = new DocumentArray(
|
||||
ProcessedAdvisoryIds.OrderBy(id => id, StringComparer.OrdinalIgnoreCase));
|
||||
document["pendingDocuments"] = new DocumentArray(
|
||||
PendingDocuments.OrderBy(id => id).Select(id => id.ToString()));
|
||||
document["pendingMappings"] = new DocumentArray(
|
||||
PendingMappings.OrderBy(id => id).Select(id => id.ToString()));
|
||||
|
||||
var cacheArray = new DocumentArray();
|
||||
foreach (var (key, metadata) in FetchCache)
|
||||
foreach (var (key, metadata) in FetchCache.OrderBy(entry => entry.Key, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
var cacheDoc = new DocumentObject
|
||||
{
|
||||
@@ -82,6 +86,7 @@ internal sealed record RedHatCursor(
|
||||
var normalizedIds = advisoryIds?.Where(static id => !string.IsNullOrWhiteSpace(id))
|
||||
.Select(static id => id.Trim())
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(static id => id, StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray() ?? Array.Empty<string>();
|
||||
|
||||
return this with
|
||||
@@ -107,18 +112,21 @@ internal sealed record RedHatCursor(
|
||||
}
|
||||
}
|
||||
|
||||
return this with { ProcessedAdvisoryIds = set.ToArray() };
|
||||
return this with
|
||||
{
|
||||
ProcessedAdvisoryIds = set.OrderBy(static id => id, StringComparer.OrdinalIgnoreCase).ToArray()
|
||||
};
|
||||
}
|
||||
|
||||
public RedHatCursor WithPendingDocuments(IEnumerable<Guid> ids)
|
||||
{
|
||||
var list = ids?.Distinct().ToArray() ?? Array.Empty<Guid>();
|
||||
var list = ids?.Distinct().OrderBy(static id => id).ToArray() ?? Array.Empty<Guid>();
|
||||
return this with { PendingDocuments = list };
|
||||
}
|
||||
|
||||
public RedHatCursor WithPendingMappings(IEnumerable<Guid> ids)
|
||||
{
|
||||
var list = ids?.Distinct().ToArray() ?? Array.Empty<Guid>();
|
||||
var list = ids?.Distinct().OrderBy(static id => id).ToArray() ?? Array.Empty<Guid>();
|
||||
return this with { PendingMappings = list };
|
||||
}
|
||||
|
||||
@@ -245,7 +253,11 @@ internal sealed record RedHatCursor(
|
||||
return value.DocumentType switch
|
||||
{
|
||||
DocumentType.DateTime => DateTime.SpecifyKind(value.ToUniversalTime(), DateTimeKind.Utc),
|
||||
DocumentType.String when DateTimeOffset.TryParse(value.AsString, out var parsed) => parsed.ToUniversalTime(),
|
||||
DocumentType.String when DateTimeOffset.TryParse(
|
||||
value.AsString,
|
||||
CultureInfo.InvariantCulture,
|
||||
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
|
||||
out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ using StellaOps.Concelier.Normalization.Distro;
|
||||
using StellaOps.Concelier.Normalization.Identifiers;
|
||||
using StellaOps.Concelier.Normalization.Text;
|
||||
using StellaOps.Concelier.Storage;
|
||||
using StellaOps.Concelier.Storage;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Distro.RedHat.Internal;
|
||||
|
||||
@@ -102,7 +101,7 @@ internal static class RedHatMapper
|
||||
}
|
||||
}
|
||||
|
||||
return aliases;
|
||||
return aliases.OrderBy(static alias => alias, StringComparer.OrdinalIgnoreCase).ToArray();
|
||||
}
|
||||
|
||||
private static NormalizedDescription NormalizeSummary(RedHatDocumentSection documentSection)
|
||||
@@ -288,7 +287,7 @@ internal static class RedHatMapper
|
||||
|
||||
var affected = new List<AffectedPackage>(rpmPackages.Count + baseProducts.Count);
|
||||
|
||||
foreach (var rpm in rpmPackages.Values)
|
||||
foreach (var rpm in rpmPackages.OrderBy(static entry => entry.Key, StringComparer.OrdinalIgnoreCase).Select(static entry => entry.Value))
|
||||
{
|
||||
if (rpm.Statuses.Count == 0)
|
||||
{
|
||||
@@ -359,7 +358,7 @@ internal static class RedHatMapper
|
||||
new[] { provenance }));
|
||||
}
|
||||
|
||||
foreach (var baseEntry in baseProducts.Values)
|
||||
foreach (var baseEntry in baseProducts.OrderBy(static entry => entry.Key, StringComparer.OrdinalIgnoreCase).Select(static entry => entry.Value))
|
||||
{
|
||||
if (baseEntry.Statuses.Count == 0)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Distro.RedHat.Internal;
|
||||
@@ -44,7 +45,11 @@ internal readonly record struct RedHatSummaryItem(string AdvisoryId, DateTimeOff
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DateTimeOffset.TryParse(releasedProperty.GetString(), out var releasedOn))
|
||||
if (!DateTimeOffset.TryParse(
|
||||
releasedProperty.GetString(),
|
||||
CultureInfo.InvariantCulture,
|
||||
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
|
||||
out var releasedOn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -12,10 +14,8 @@ using StellaOps.Concelier.Connector.Common;
|
||||
using StellaOps.Concelier.Connector.Common.Fetch;
|
||||
using StellaOps.Concelier.Connector.Distro.RedHat.Configuration;
|
||||
using StellaOps.Concelier.Connector.Distro.RedHat.Internal;
|
||||
using StellaOps.Concelier.Storage;
|
||||
using StellaOps.Concelier.Storage.Advisories;
|
||||
using StellaOps.Concelier.Storage;
|
||||
using StellaOps.Concelier.Storage;
|
||||
using StellaOps.Concelier.Core.Canonical;
|
||||
using StellaOps.Plugin;
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace StellaOps.Concelier.Connector.Distro.RedHat;
|
||||
|
||||
public sealed class RedHatConnector : IFeedConnector
|
||||
{
|
||||
private const string DtoSchemaVersion = "redhat.csaf.v2";
|
||||
private readonly SourceFetchService _fetchService;
|
||||
private readonly RawDocumentStorage _rawDocumentStorage;
|
||||
private readonly IDocumentStore _documentStore;
|
||||
@@ -293,6 +294,8 @@ public sealed class RedHatConnector : IFeedConnector
|
||||
|
||||
foreach (var documentId in cursor.PendingDocuments)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
DocumentRecord? document = null;
|
||||
|
||||
try
|
||||
@@ -319,12 +322,13 @@ public sealed class RedHatConnector : IFeedConnector
|
||||
var payload = DocumentObject.Parse(sanitized);
|
||||
|
||||
var dtoRecord = new DtoRecord(
|
||||
Guid.NewGuid(),
|
||||
CreateDeterministicGuid($"redhat:dto:{document.Id}:{DtoSchemaVersion}"),
|
||||
document.Id,
|
||||
SourceName,
|
||||
"redhat.csaf.v2",
|
||||
DtoSchemaVersion,
|
||||
payload,
|
||||
_timeProvider.GetUtcNow());
|
||||
_timeProvider.GetUtcNow(),
|
||||
SchemaVersion: DtoSchemaVersion);
|
||||
|
||||
await _dtoStore.UpsertAsync(dtoRecord, cancellationToken).ConfigureAwait(false);
|
||||
await _documentStore.UpdateStatusAsync(document.Id, DocumentStatuses.PendingMap, cancellationToken).ConfigureAwait(false);
|
||||
@@ -365,6 +369,8 @@ public sealed class RedHatConnector : IFeedConnector
|
||||
|
||||
foreach (var documentId in cursor.PendingMappings)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
var dto = await _dtoStore.FindByDocumentIdAsync(documentId, cancellationToken).ConfigureAwait(false);
|
||||
@@ -385,6 +391,7 @@ public sealed class RedHatConnector : IFeedConnector
|
||||
var advisory = RedHatMapper.Map(SourceName, dto, document, jsonDocument);
|
||||
if (advisory is null)
|
||||
{
|
||||
await _documentStore.UpdateStatusAsync(documentId, DocumentStatuses.Failed, cancellationToken).ConfigureAwait(false);
|
||||
pendingMappings.Remove(documentId);
|
||||
continue;
|
||||
}
|
||||
@@ -403,6 +410,8 @@ public sealed class RedHatConnector : IFeedConnector
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Red Hat map failed for document {DocumentId}", documentId);
|
||||
await _documentStore.UpdateStatusAsync(documentId, DocumentStatuses.Failed, cancellationToken).ConfigureAwait(false);
|
||||
pendingMappings.Remove(documentId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,4 +537,12 @@ public sealed class RedHatConnector : IFeedConnector
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Guid CreateDeterministicGuid(string value)
|
||||
{
|
||||
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(value ?? string.Empty));
|
||||
bytes[6] = (byte)((bytes[6] & 0x0F) | 0x50);
|
||||
bytes[8] = (byte)((bytes[8] & 0x3F) | 0x80);
|
||||
return new Guid(bytes.AsSpan(0, 16));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
|
||||
|
||||
@@ -7,4 +7,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0167-M | DONE | Maintainability audit for StellaOps.Concelier.Connector.Distro.RedHat. |
|
||||
| AUDIT-0167-T | DONE | Test coverage audit for StellaOps.Concelier.Connector.Distro.RedHat. |
|
||||
| AUDIT-0167-A | TODO | Pending approval for changes. |
|
||||
| AUDIT-0167-A | DONE | Applied audit remediations. |
|
||||
|
||||
Reference in New Issue
Block a user