audit work, fixed StellaOps.sln warnings/errors, fixed tests, sprints work, new advisories
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Core.Linksets;
|
||||
using StellaOps.Concelier.WebService.Contracts;
|
||||
@@ -35,7 +36,7 @@ internal static class AdvisorySummaryMapper
|
||||
ObservationIds: linkset.ObservationIds.ToArray(),
|
||||
Schema: "lnm-1.0"),
|
||||
Aliases: aliases.ToArray(),
|
||||
ObservedAt: linkset.CreatedAt.UtcDateTime.ToString("O"));
|
||||
ObservedAt: linkset.CreatedAt.UtcDateTime.ToString("O", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
public static AdvisorySummaryResponse ToResponse(
|
||||
|
||||
@@ -226,7 +226,7 @@ internal static class FeedSnapshotEndpointExtensions
|
||||
exportOptions,
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (metadata is null)
|
||||
if (metadata is null || metadata.ExportPath is null)
|
||||
{
|
||||
return ConcelierProblemResultFactory.SnapshotNotFound(context, snapshotId);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using StellaOps.Concelier.WebService.Options;
|
||||
|
||||
@@ -76,8 +77,8 @@ internal static class IncidentFileStore
|
||||
payload.AdvisoryKey,
|
||||
payload.Tenant,
|
||||
payload.Reason,
|
||||
payload.ActivatedAt.ToUniversalTime().ToString("O"),
|
||||
payload.CooldownUntil.ToUniversalTime().ToString("O"),
|
||||
payload.ActivatedAt.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture),
|
||||
payload.CooldownUntil.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture),
|
||||
payload.PipelineVersion,
|
||||
active);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
|
||||
<PackageReference Include="StackExchange.Redis" />
|
||||
<PackageReference Include="System.Diagnostics.DiagnosticSource" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -660,7 +660,7 @@ public sealed class AcscConnector : IFeedConnector
|
||||
|
||||
if (cursor.LastPublishedByFeed.TryGetValue(feed.Slug, out var published) && published.HasValue)
|
||||
{
|
||||
metadata["acsc.cursor.lastPublished"] = published.Value.ToString("O");
|
||||
metadata["acsc.cursor.lastPublished"] = published.Value.ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return metadata;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -270,7 +271,7 @@ internal static class AcscMapper
|
||||
entry.Link ?? string.Empty,
|
||||
entry.Title ?? string.Empty,
|
||||
entry.Summary ?? string.Empty,
|
||||
entry.Published?.ToUniversalTime().ToString("O") ?? string.Empty);
|
||||
entry.Published?.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) ?? string.Empty);
|
||||
identifier = CreateHash(seed);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.CertBund.Internal;
|
||||
|
||||
@@ -11,7 +12,7 @@ internal static class CertBundDocumentMetadata
|
||||
{
|
||||
["certbund.advisoryId"] = item.AdvisoryId,
|
||||
["certbund.portalUri"] = item.PortalUri.ToString(),
|
||||
["certbund.published"] = item.Published.ToString("O"),
|
||||
["certbund.published"] = item.Published.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(item.Category))
|
||||
|
||||
@@ -70,7 +70,7 @@ internal sealed record CertFrDocumentMetadata(
|
||||
{
|
||||
[AdvisoryIdKey] = item.AdvisoryId,
|
||||
[TitleKey] = item.Title ?? item.AdvisoryId,
|
||||
[PublishedKey] = item.Published.ToString("O"),
|
||||
[PublishedKey] = item.Published.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(item.Summary))
|
||||
|
||||
@@ -121,7 +121,7 @@ public sealed class CertInConnector : IFeedConnector
|
||||
["certin.advisoryId"] = listing.AdvisoryId,
|
||||
["certin.title"] = listing.Title,
|
||||
["certin.link"] = listing.DetailUri.ToString(),
|
||||
["certin.published"] = listing.Published.ToString("O")
|
||||
["certin.published"] = listing.Published.ToString("O", CultureInfo.InvariantCulture)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(listing.Summary))
|
||||
|
||||
@@ -151,7 +151,7 @@ public sealed class SourceFetchService
|
||||
? new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
: new Dictionary<string, string>(request.Metadata, StringComparer.Ordinal);
|
||||
metadata["attempts"] = sendResult.Attempts.ToString(CultureInfo.InvariantCulture);
|
||||
metadata["fetchedAt"] = fetchedAt.ToString("O");
|
||||
metadata["fetchedAt"] = fetchedAt.ToString("O", CultureInfo.InvariantCulture);
|
||||
|
||||
var guardDocument = CreateRawAdvisoryDocument(
|
||||
request,
|
||||
@@ -319,7 +319,7 @@ public sealed class SourceFetchService
|
||||
ReconciledFrom = ImmutableArray<string>.Empty,
|
||||
Notes = ImmutableDictionary<string, string>.Empty
|
||||
},
|
||||
supersedes);
|
||||
Supersedes: supersedes);
|
||||
|
||||
var mappedLinkset = _linksetMapper.Map(rawDocument);
|
||||
rawDocument = rawDocument with { Linkset = mappedLinkset };
|
||||
@@ -404,10 +404,10 @@ public sealed class SourceFetchService
|
||||
|
||||
if (response.Content.Headers.LastModified is { } lastModified)
|
||||
{
|
||||
builder["http.last_modified"] = lastModified.ToString("O");
|
||||
builder["http.last_modified"] = lastModified.ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
builder["fetch.fetched_at"] = fetchedAt.ToString("O");
|
||||
builder["fetch.fetched_at"] = fetchedAt.ToString("O", CultureInfo.InvariantCulture);
|
||||
builder["fetch.content_hash"] = contentHash;
|
||||
builder["source.client"] = request.ClientName;
|
||||
|
||||
@@ -525,7 +525,7 @@ public sealed class SourceFetchService
|
||||
|
||||
if (response.Content.Headers.LastModified is { } lastModified)
|
||||
{
|
||||
return lastModified.ToString("O");
|
||||
return lastModified.ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (response.Headers.TryGetValues("Last-Modified", out var values))
|
||||
@@ -537,7 +537,7 @@ public sealed class SourceFetchService
|
||||
}
|
||||
}
|
||||
|
||||
return fetchedAt.ToString("O");
|
||||
return fetchedAt.ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private static RawSignatureMetadata CreateSignatureMetadata(ImmutableDictionary<string, string> metadata)
|
||||
|
||||
@@ -116,7 +116,7 @@ public static class ServiceCollectionExtensions
|
||||
|
||||
foreach (var root in options.TrustedRootCertificates)
|
||||
{
|
||||
trustedRootCopies.Add(new X509Certificate2(root.RawData));
|
||||
trustedRootCopies.Add(X509CertificateLoader.LoadCertificate(root.RawData));
|
||||
}
|
||||
|
||||
using var customChain = new X509Chain();
|
||||
|
||||
@@ -121,8 +121,8 @@ public sealed class CveConnector : IFeedConnector
|
||||
var requestUri = BuildListRequestUri(since, windowEnd, page, _options.PageSize);
|
||||
var metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["since"] = since.ToString("O"),
|
||||
["until"] = windowEnd.ToString("O"),
|
||||
["since"] = since.ToString("O", CultureInfo.InvariantCulture),
|
||||
["until"] = windowEnd.ToString("O", CultureInfo.InvariantCulture),
|
||||
["page"] = page.ToString(CultureInfo.InvariantCulture),
|
||||
["pageSize"] = _options.PageSize.ToString(CultureInfo.InvariantCulture),
|
||||
};
|
||||
@@ -197,8 +197,8 @@ public sealed class CveConnector : IFeedConnector
|
||||
{
|
||||
["cveId"] = item.CveId,
|
||||
["page"] = page.ToString(CultureInfo.InvariantCulture),
|
||||
["since"] = since.ToString("O"),
|
||||
["until"] = windowEnd.ToString("O"),
|
||||
["since"] = since.ToString("O", CultureInfo.InvariantCulture),
|
||||
["until"] = windowEnd.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
SourceFetchResult detailResult;
|
||||
@@ -298,10 +298,10 @@ public sealed class CveConnector : IFeedConnector
|
||||
var nextWindowStart = hasMorePages ? since : maxModified ?? windowEnd;
|
||||
DateTimeOffset? nextWindowEnd = hasMorePages ? windowEnd : null;
|
||||
var nextPage = hasMorePages ? page : 1;
|
||||
var windowStartString = since.ToString("O");
|
||||
var windowEndString = windowEnd.ToString("O");
|
||||
var nextWindowStartString = nextWindowStart.ToString("O");
|
||||
var nextWindowEndString = nextWindowEnd?.ToString("O") ?? "(none)";
|
||||
var windowStartString = since.ToString("O", CultureInfo.InvariantCulture);
|
||||
var windowEndString = windowEnd.ToString("O", CultureInfo.InvariantCulture);
|
||||
var nextWindowStartString = nextWindowStart.ToString("O", CultureInfo.InvariantCulture);
|
||||
var nextWindowEndString = nextWindowEnd?.ToString("O", CultureInfo.InvariantCulture) ?? "(none)";
|
||||
|
||||
_logger.LogInformation(
|
||||
"CVEs fetch window {WindowStart}->{WindowEnd} pages={PagesFetched} listSuccess={ListSuccess} detailDocuments={DocumentsFetched} detailFailures={DetailFailures} detailUnchanged={DetailUnchanged} pendingDocuments={PendingDocumentsBefore}->{PendingDocumentsAfter} pendingMappings={PendingMappingsBefore}->{PendingMappingsAfter} hasMorePages={HasMorePages} nextWindowStart={NextWindowStart} nextWindowEnd={NextWindowEnd} nextPage={NextPage}",
|
||||
@@ -596,7 +596,7 @@ public sealed class CveConnector : IFeedConnector
|
||||
|
||||
private static Uri BuildListRequestUri(DateTimeOffset since, DateTimeOffset until, int page, int pageSize)
|
||||
{
|
||||
var query = $"time_modified.gte={Uri.EscapeDataString(since.ToString("O"))}&time_modified.lte={Uri.EscapeDataString(until.ToString("O"))}&page={page}&size={pageSize}";
|
||||
var query = $"time_modified.gte={Uri.EscapeDataString(since.ToString("O", CultureInfo.InvariantCulture))}&time_modified.lte={Uri.EscapeDataString(until.ToString("O", CultureInfo.InvariantCulture))}&page={page}&size={pageSize}";
|
||||
return new Uri($"cve?{query}", UriKind.Relative);
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ public sealed class UbuntuConnector : IFeedConnector
|
||||
var metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["ubuntu.id"] = notice.NoticeId,
|
||||
["ubuntu.published"] = notice.Published.ToString("O")
|
||||
["ubuntu.published"] = notice.Published.ToString("O", CultureInfo.InvariantCulture)
|
||||
};
|
||||
|
||||
var dtoDocument = ToDocument(notice);
|
||||
|
||||
@@ -109,8 +109,8 @@ public sealed class GhsaConnector : IFeedConnector
|
||||
var listUri = BuildListUri(since, until, page, _options.PageSize);
|
||||
var metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["since"] = since.ToString("O"),
|
||||
["until"] = until.ToString("O"),
|
||||
["since"] = since.ToString("O", CultureInfo.InvariantCulture),
|
||||
["until"] = until.ToString("O", CultureInfo.InvariantCulture),
|
||||
["page"] = page.ToString(CultureInfo.InvariantCulture),
|
||||
["pageSize"] = _options.PageSize.ToString(CultureInfo.InvariantCulture),
|
||||
};
|
||||
@@ -172,8 +172,8 @@ public sealed class GhsaConnector : IFeedConnector
|
||||
{
|
||||
["ghsaId"] = item.GhsaId,
|
||||
["page"] = page.ToString(CultureInfo.InvariantCulture),
|
||||
["since"] = since.ToString("O"),
|
||||
["until"] = until.ToString("O"),
|
||||
["since"] = since.ToString("O", CultureInfo.InvariantCulture),
|
||||
["until"] = until.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
SourceFetchResult detailResult;
|
||||
@@ -425,7 +425,7 @@ public sealed class GhsaConnector : IFeedConnector
|
||||
|
||||
private static Uri BuildListUri(DateTimeOffset since, DateTimeOffset until, int page, int pageSize)
|
||||
{
|
||||
var query = $"updated_since={Uri.EscapeDataString(since.ToString("O"))}&updated_until={Uri.EscapeDataString(until.ToString("O"))}&page={page}&per_page={pageSize}";
|
||||
var query = $"updated_since={Uri.EscapeDataString(since.ToString("O", CultureInfo.InvariantCulture))}&updated_until={Uri.EscapeDataString(until.ToString("O", CultureInfo.InvariantCulture))}&page={page}&per_page={pageSize}";
|
||||
return new Uri($"security/advisories?{query}", UriKind.Relative);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -15,8 +16,6 @@ using StellaOps.Concelier.Connector.Ics.Kaspersky.Configuration;
|
||||
using StellaOps.Concelier.Connector.Ics.Kaspersky.Internal;
|
||||
using StellaOps.Concelier.Storage;
|
||||
using StellaOps.Concelier.Storage.Advisories;
|
||||
using StellaOps.Concelier.Storage;
|
||||
using StellaOps.Concelier.Storage;
|
||||
using StellaOps.Cryptography;
|
||||
using StellaOps.Plugin;
|
||||
|
||||
@@ -128,7 +127,7 @@ public sealed class KasperskyConnector : IFeedConnector
|
||||
{
|
||||
["kaspersky.title"] = item.Title,
|
||||
["kaspersky.link"] = item.Link.ToString(),
|
||||
["kaspersky.published"] = item.Published.ToString("O"),
|
||||
["kaspersky.published"] = item.Published.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(item.Summary))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -128,12 +129,12 @@ public sealed class JvnConnector : IFeedConnector
|
||||
|
||||
if (item.DateFirstPublished.HasValue)
|
||||
{
|
||||
metadata["jvn.firstPublished"] = item.DateFirstPublished.Value.ToString("O");
|
||||
metadata["jvn.firstPublished"] = item.DateFirstPublished.Value.ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (item.DateLastUpdated.HasValue)
|
||||
{
|
||||
metadata["jvn.lastUpdated"] = item.DateLastUpdated.Value.ToString("O");
|
||||
metadata["jvn.lastUpdated"] = item.DateLastUpdated.Value.ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
var result = await _fetchService.FetchAsync(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
@@ -73,7 +74,7 @@ internal sealed record KevCursor(
|
||||
=> 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.RoundtripKind, out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -97,7 +98,7 @@ public sealed class KevConnector : IFeedConnector
|
||||
Metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["kev.cursor.catalogVersion"] = cursor.CatalogVersion ?? string.Empty,
|
||||
["kev.cursor.catalogReleased"] = cursor.CatalogReleased?.ToString("O") ?? string.Empty,
|
||||
["kev.cursor.catalogReleased"] = cursor.CatalogReleased?.ToString("O", CultureInfo.InvariantCulture) ?? string.Empty,
|
||||
},
|
||||
ETag = existing?.Etag,
|
||||
LastModified = existing?.LastModified,
|
||||
@@ -139,7 +140,7 @@ public sealed class KevConnector : IFeedConnector
|
||||
.WithPendingMappings(pendingMappings);
|
||||
|
||||
var document = result.Document;
|
||||
var lastModified = document.LastModified?.ToUniversalTime().ToString("O") ?? "(unknown)";
|
||||
var lastModified = document.LastModified?.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) ?? "(unknown)";
|
||||
_logger.LogInformation(
|
||||
"Fetched KEV catalog document {DocumentId} (etag={Etag}, lastModified={LastModified}) pendingDocuments={PendingDocumentsBefore}->{PendingDocumentsAfter} pendingMappings={PendingMappingsBefore}->{PendingMappingsAfter}",
|
||||
document.Id,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
@@ -114,7 +115,7 @@ internal sealed record KisaCursor(
|
||||
=> 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.RoundtripKind, out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Kisa.Internal;
|
||||
|
||||
@@ -12,7 +13,7 @@ internal static class KisaDocumentMetadata
|
||||
["kisa.idx"] = item.AdvisoryId,
|
||||
["kisa.detailApi"] = item.DetailApiUri.ToString(),
|
||||
["kisa.detailPage"] = item.DetailPageUri.ToString(),
|
||||
["kisa.published"] = item.Published.ToString("O"),
|
||||
["kisa.published"] = item.Published.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(item.Title))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -146,7 +147,7 @@ internal static class NvdMapper
|
||||
return null;
|
||||
}
|
||||
|
||||
return DateTimeOffset.TryParse(property.GetString(), out var parsed) ? parsed : null;
|
||||
return DateTimeOffset.TryParse(property.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var parsed) ? parsed : null;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<AdvisoryReference> GetReferences(
|
||||
|
||||
@@ -93,8 +93,8 @@ public sealed class NvdConnector : IFeedConnector
|
||||
|
||||
var metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["windowStart"] = window.Start.ToString("O"),
|
||||
["windowEnd"] = window.End.ToString("O"),
|
||||
["windowStart"] = window.Start.ToString("O", CultureInfo.InvariantCulture),
|
||||
["windowEnd"] = window.End.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
metadata["startIndex"] = "0";
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
@@ -281,7 +282,7 @@ internal sealed record OsvCursor(
|
||||
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.RoundtripKind, out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
@@ -440,7 +441,7 @@ public sealed class OsvConnector : IFeedConnector
|
||||
{
|
||||
["osv.ecosystem"] = ecosystem,
|
||||
["osv.id"] = dto.Id,
|
||||
["osv.modified"] = modified.ToString("O"),
|
||||
["osv.modified"] = modified.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
var record = new DocumentRecord(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
@@ -794,7 +795,7 @@ public sealed class RuNkckiConnector : IFeedConnector
|
||||
private string GetBulletinCachePath(string bulletinId)
|
||||
{
|
||||
var fileStem = string.IsNullOrWhiteSpace(bulletinId)
|
||||
? ComputeDeterministicSlug("unknown-bulletin", _timeProvider.GetUtcNow().ToString("O"))
|
||||
? ComputeDeterministicSlug("unknown-bulletin", _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture))
|
||||
: Uri.EscapeDataString(bulletinId);
|
||||
return Path.Combine(_cacheDirectory, $"{fileStem}.json.zip");
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
@@ -67,7 +68,7 @@ internal sealed record StellaOpsMirrorCursor(
|
||||
generatedAt = generatedValue.DocumentType switch
|
||||
{
|
||||
DocumentType.DateTime => DateTime.SpecifyKind(generatedValue.ToUniversalTime(), DateTimeKind.Utc),
|
||||
DocumentType.String when DateTimeOffset.TryParse(generatedValue.AsString, out var parsed) => parsed.ToUniversalTime(),
|
||||
DocumentType.String when DateTimeOffset.TryParse(generatedValue.AsString, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -373,7 +374,7 @@ public sealed class AdobeConnector : IFeedConnector
|
||||
var metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["advisoryId"] = entry.AdvisoryId,
|
||||
["published"] = entry.PublishedUtc.ToString("O"),
|
||||
["published"] = entry.PublishedUtc.ToString("O", CultureInfo.InvariantCulture),
|
||||
["title"] = entry.Title ?? string.Empty,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
@@ -102,7 +103,7 @@ internal sealed record AdobeCursor(
|
||||
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.RoundtripKind, out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using StellaOps.Concelier.Storage;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Vndr.Adobe.Internal;
|
||||
@@ -32,7 +33,7 @@ internal sealed record AdobeDocumentMetadata(
|
||||
var title = document.Metadata.TryGetValue(TitleKey, out var titleValue) ? titleValue : null;
|
||||
DateTimeOffset? published = null;
|
||||
if (document.Metadata.TryGetValue(PublishedKey, out var publishedValue)
|
||||
&& DateTimeOffset.TryParse(publishedValue, out var parsedPublished))
|
||||
&& DateTimeOffset.TryParse(publishedValue, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var parsedPublished))
|
||||
{
|
||||
published = parsedPublished.ToUniversalTime();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
@@ -369,7 +370,7 @@ public sealed class AppleConnector : IFeedConnector
|
||||
metadata.TryGetValue("apple.rapidResponse", out var rapidRaw);
|
||||
metadata.TryGetValue("apple.products", out var productsJson);
|
||||
|
||||
if (!DateTimeOffset.TryParse(postingDateRaw, out var postingDate))
|
||||
if (!DateTimeOffset.TryParse(postingDateRaw, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var postingDate))
|
||||
{
|
||||
postingDate = document.FetchedAt;
|
||||
}
|
||||
@@ -416,7 +417,7 @@ public sealed class AppleConnector : IFeedConnector
|
||||
["apple.articleId"] = entry.ArticleId,
|
||||
["apple.updateId"] = entry.UpdateId,
|
||||
["apple.title"] = entry.Title,
|
||||
["apple.postingDate"] = entry.PostingDate.ToString("O"),
|
||||
["apple.postingDate"] = entry.PostingDate.ToString("O", CultureInfo.InvariantCulture),
|
||||
["apple.detailUri"] = entry.DetailUri.ToString(),
|
||||
["apple.rapidResponse"] = entry.IsRapidSecurityResponse ? "true" : "false",
|
||||
["apple.products"] = JsonSerializer.Serialize(entry.Products, SerializerOptions),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
@@ -108,7 +109,7 @@ internal sealed record AppleCursor(
|
||||
=> 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.RoundtripKind, out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using AngleSharp.Dom;
|
||||
@@ -115,7 +116,7 @@ internal static class AppleDetailParser
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DateTimeOffset.TryParse(raw, out var parsed))
|
||||
if (!DateTimeOffset.TryParse(raw, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var parsed))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
@@ -87,7 +88,7 @@ internal static class AppleIndexParser
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!DateTimeOffset.TryParse(dto.PostingDate, out var postingDate))
|
||||
if (!DateTimeOffset.TryParse(dto.PostingDate, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var postingDate))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using StellaOps.Concelier.Storage;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Vndr.Chromium.Internal;
|
||||
@@ -60,12 +61,12 @@ internal sealed record ChromiumDocumentMetadata(
|
||||
{
|
||||
[PostIdKey] = postId,
|
||||
[TitleKey] = title,
|
||||
[PublishedKey] = published.ToUniversalTime().ToString("O"),
|
||||
[PublishedKey] = published.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
if (updated.HasValue)
|
||||
{
|
||||
dictionary[UpdatedKey] = updated.Value.ToUniversalTime().ToString("O");
|
||||
dictionary[UpdatedKey] = updated.Value.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(summary))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
@@ -115,8 +116,8 @@ public sealed class MsrcApiClient
|
||||
builder.Append(_options.BaseUri.ToString().TrimEnd('/'));
|
||||
builder.Append("/vulnerabilities?");
|
||||
builder.Append("$top=").Append(_options.PageSize);
|
||||
builder.Append("&lastModifiedStartDateTime=").Append(Uri.EscapeDataString(fromInclusive.ToUniversalTime().ToString("O")));
|
||||
builder.Append("&lastModifiedEndDateTime=").Append(Uri.EscapeDataString(toExclusive.ToUniversalTime().ToString("O")));
|
||||
builder.Append("&lastModifiedStartDateTime=").Append(Uri.EscapeDataString(fromInclusive.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture)));
|
||||
builder.Append("&lastModifiedEndDateTime=").Append(Uri.EscapeDataString(toExclusive.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture)));
|
||||
builder.Append("&$orderby=lastModifiedDate");
|
||||
builder.Append("&locale=").Append(Uri.EscapeDataString(_options.Locale));
|
||||
builder.Append("&api-version=").Append(Uri.EscapeDataString(_options.ApiVersion));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
@@ -81,7 +82,7 @@ internal sealed record MsrcCursor(
|
||||
=> 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.RoundtripKind, out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Vndr.Msrc.Internal;
|
||||
|
||||
@@ -15,12 +16,12 @@ internal static class MsrcDocumentMetadata
|
||||
|
||||
if (summary.LastModifiedDate.HasValue)
|
||||
{
|
||||
metadata["msrc.lastModified"] = summary.LastModifiedDate.Value.ToString("O");
|
||||
metadata["msrc.lastModified"] = summary.LastModifiedDate.Value.ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (summary.ReleaseDate.HasValue)
|
||||
{
|
||||
metadata["msrc.releaseDate"] = summary.ReleaseDate.Value.ToString("O");
|
||||
metadata["msrc.releaseDate"] = summary.ReleaseDate.Value.ToString("O", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(summary.CvrfUrl))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net.Http;
|
||||
@@ -424,7 +425,7 @@ public sealed class MsrcConnector : IFeedConnector
|
||||
return true;
|
||||
}
|
||||
|
||||
return !string.Equals(stored, summary.LastModifiedDate.Value.ToString("O"), StringComparison.OrdinalIgnoreCase);
|
||||
return !string.Equals(stored, summary.LastModifiedDate.Value.ToString("O", CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private async Task<MsrcCursor> GetCursorAsync(CancellationToken cancellationToken)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using StellaOps.Concelier.Storage;
|
||||
|
||||
namespace StellaOps.Concelier.Connector.Vndr.Oracle.Internal;
|
||||
@@ -19,7 +20,7 @@ internal sealed record OracleDocumentMetadata(
|
||||
{
|
||||
[AdvisoryIdKey] = advisoryId,
|
||||
[TitleKey] = title,
|
||||
[PublishedKey] = published.ToString("O"),
|
||||
[PublishedKey] = published.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
public static OracleDocumentMetadata FromDocument(DocumentRecord document)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using StellaOps.Concelier.Documents;
|
||||
|
||||
@@ -166,7 +167,7 @@ internal sealed record VmwareCursor(
|
||||
=> 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.RoundtripKind, out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using StellaOps.Concelier.Documents;
|
||||
using StellaOps.Concelier.Storage;
|
||||
using StellaOps.Concelier.Storage.Contracts;
|
||||
@@ -44,7 +45,7 @@ internal sealed record VmwareFetchCacheEntry(string? Sha256, string? ETag, DateT
|
||||
lastModified = lastModifiedValue.DocumentType switch
|
||||
{
|
||||
DocumentType.DateTime => DateTime.SpecifyKind(lastModifiedValue.ToUniversalTime(), DateTimeKind.Utc),
|
||||
DocumentType.String when DateTimeOffset.TryParse(lastModifiedValue.AsString, out var parsed) => parsed.ToUniversalTime(),
|
||||
DocumentType.String when DateTimeOffset.TryParse(lastModifiedValue.AsString, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var parsed) => parsed.ToUniversalTime(),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
@@ -170,7 +171,7 @@ public sealed class VmwareConnector : IFeedConnector
|
||||
var metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["vmware.id"] = item.Id,
|
||||
["vmware.modified"] = modified.ToString("O"),
|
||||
["vmware.modified"] = modified.ToString("O", CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
SourceFetchResult result;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -188,7 +189,7 @@ public sealed class LoggingBundleTimelineEventSink : IBundleTimelineEventSink
|
||||
timelineEvent.Stats.DurationMs,
|
||||
timelineEvent.ContentHash,
|
||||
timelineEvent.TraceId,
|
||||
timelineEvent.OccurredAt.ToString("O"));
|
||||
timelineEvent.OccurredAt.ToString("O", CultureInfo.InvariantCulture));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace StellaOps.Concelier.Core.Risk;
|
||||
@@ -243,7 +244,7 @@ public static class VendorRiskSignalExtractor
|
||||
if (element.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
var str = element.GetString();
|
||||
if (DateTimeOffset.TryParse(str, out var date))
|
||||
if (DateTimeOffset.TryParse(str, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var date))
|
||||
{
|
||||
return date;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Options" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
|
||||
<PackageReference Include="Cronos" />
|
||||
<PackageReference Include="System.Diagnostics.DiagnosticSource" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StellaOps.Concelier.Models\StellaOps.Concelier.Models.csproj" />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Concelier.Core.Canonical;
|
||||
@@ -36,7 +37,7 @@ public sealed class DeltaQueryService : IDeltaQueryService
|
||||
_logger.LogInformation(
|
||||
"Querying changes since {Cursor} (timestamp: {Since})",
|
||||
sinceCursor ?? "beginning",
|
||||
sinceTimestamp?.ToString("O") ?? "null");
|
||||
sinceTimestamp?.ToString("O", CultureInfo.InvariantCulture) ?? "null");
|
||||
|
||||
return new DeltaChangeSet
|
||||
{
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
||||
<PackageReference Include="System.Diagnostics.DiagnosticSource" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
@@ -182,8 +183,8 @@ public sealed class AdvisoryMergeService
|
||||
var feedId = ExtractPrimaryFeedId(inputs) ?? "canonical";
|
||||
|
||||
// Compute epochs based on modification timestamps
|
||||
var previousEpoch = before?.Modified?.ToString("O") ?? "initial";
|
||||
var newEpoch = merged.Modified?.ToString("O") ?? _timeProvider.GetUtcNow().ToString("O");
|
||||
var previousEpoch = before?.Modified?.ToString("O", CultureInfo.InvariantCulture) ?? "initial";
|
||||
var newEpoch = merged.Modified?.ToString("O", CultureInfo.InvariantCulture) ?? _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture);
|
||||
var effectiveAt = _timeProvider.GetUtcNow();
|
||||
|
||||
var @event = FeedEpochAdvancedEvent.Create(
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// Description: PostgreSQL repository for federation sync ledger operations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Npgsql;
|
||||
using StellaOps.Concelier.Persistence.Postgres.Models;
|
||||
@@ -357,8 +358,8 @@ public static class CursorFormat
|
||||
public static (DateTimeOffset Timestamp, int Sequence) Parse(string cursor)
|
||||
{
|
||||
var parts = cursor.Split('#');
|
||||
var timestamp = DateTimeOffset.Parse(parts[0]);
|
||||
var sequence = parts.Length > 1 ? int.Parse(parts[1]) : 0;
|
||||
var timestamp = DateTimeOffset.Parse(parts[0], CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
|
||||
var sequence = parts.Length > 1 ? int.Parse(parts[1], CultureInfo.InvariantCulture) : 0;
|
||||
return (timestamp, sequence);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Collections.Generic;
|
||||
using StellaOps.Concelier.Documents;
|
||||
@@ -94,7 +95,7 @@ public sealed class PostgresSourceStateAdapter : LegacyContracts.ISourceStateRep
|
||||
|
||||
var metadata = new Dictionary<string, object?>(StringComparer.Ordinal)
|
||||
{
|
||||
["backoffUntil"] = backoffUntil.ToString("O"),
|
||||
["backoffUntil"] = backoffUntil.ToString("O", CultureInfo.InvariantCulture),
|
||||
["reason"] = reason
|
||||
};
|
||||
|
||||
@@ -201,7 +202,7 @@ public sealed class PostgresSourceStateAdapter : LegacyContracts.ISourceStateRep
|
||||
}
|
||||
|
||||
if (backoffProperty.ValueKind == JsonValueKind.String
|
||||
&& DateTimeOffset.TryParse(backoffProperty.GetString(), out var parsed))
|
||||
&& DateTimeOffset.TryParse(backoffProperty.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var parsed))
|
||||
{
|
||||
return parsed;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ public sealed class SbomRegistryService : ISbomRegistryService
|
||||
|
||||
var registration = new SbomRegistration
|
||||
{
|
||||
Id = ComputeDeterministicRegistrationId(input.Digest, input.TenantId),
|
||||
Id = ComputeDeterministicRegistrationId(input.Digest, input.TenantId ?? "default"),
|
||||
Digest = input.Digest,
|
||||
Format = input.Format,
|
||||
SpecVersion = input.SpecVersion,
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
||||
<PackageReference Include="System.Diagnostics.DiagnosticSource" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
namespace StellaOps.Concelier.SourceIntel;
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
/// <summary>
|
||||
@@ -290,21 +291,21 @@ public static partial class ChangelogParser
|
||||
private static DateTimeOffset ParseDebianDate(string dateStr)
|
||||
{
|
||||
// "Mon, 15 Jan 2024 10:30:00 +0000"
|
||||
if (DateTimeOffset.TryParse(dateStr, out var date))
|
||||
if (DateTimeOffset.TryParse(dateStr, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var date))
|
||||
{
|
||||
return date;
|
||||
}
|
||||
return DateTimeOffset.UtcNow;
|
||||
return DateTimeOffset.MinValue;
|
||||
}
|
||||
|
||||
private static DateTimeOffset ParseRpmDate(string dateStr)
|
||||
{
|
||||
// "Mon Jan 15 2024"
|
||||
if (DateTimeOffset.TryParse(dateStr, out var date))
|
||||
if (DateTimeOffset.TryParse(dateStr, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var date))
|
||||
{
|
||||
return date;
|
||||
}
|
||||
return DateTimeOffset.UtcNow;
|
||||
return DateTimeOffset.MinValue;
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"^(\S+) \(([^)]+)\)")]
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Concelier ConfigDiff Tests Charter
|
||||
|
||||
## Mission
|
||||
- Validate config diff behaviors for Concelier configuration surfaces.
|
||||
|
||||
## Responsibilities
|
||||
- Exercise configuration comparison logic and determinism.
|
||||
- Cover edge cases (missing keys, ordering, default values).
|
||||
|
||||
## Required Reading
|
||||
- docs/README.md
|
||||
- docs/07_HIGH_LEVEL_ARCHITECTURE.md
|
||||
- docs/modules/platform/architecture-overview.md
|
||||
- docs/modules/concelier/architecture.md
|
||||
- docs/modules/concelier/link-not-merge-schema.md
|
||||
|
||||
## Working Agreement
|
||||
- Use fixed times and IDs in tests.
|
||||
- Assert deterministic ordering and invariant formatting.
|
||||
- Avoid network dependencies in tests.
|
||||
|
||||
## Testing Strategy
|
||||
- Unit tests for config diff logic and normalization.
|
||||
- Regression tests for deterministic output.
|
||||
@@ -13,9 +13,6 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" />
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="xunit.v3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Fixtures\*.xml">
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
<PackageReference Include="FluentAssertions" />
|
||||
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />
|
||||
<PackageReference Include="NSubstitute" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" >
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../__Libraries/StellaOps.Concelier.Connector.Common/StellaOps.Concelier.Connector.Common.csproj" />
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentAssertions" />
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="xunit.v3" />
|
||||
</ItemGroup> <ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
||||
<PackageReference Include="Npgsql" />
|
||||
<PackageReference Include="Dapper" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" >
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" >
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit.runner.visualstudio" >
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" >
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Concelier SchemaEvolution Tests Charter
|
||||
|
||||
## Mission
|
||||
- Validate schema evolution rules and backward compatibility for Concelier data.
|
||||
|
||||
## Responsibilities
|
||||
- Exercise schema upgrade paths and compatibility checks.
|
||||
- Verify deterministic normalization of schema artifacts.
|
||||
|
||||
## Required Reading
|
||||
- docs/README.md
|
||||
- docs/07_HIGH_LEVEL_ARCHITECTURE.md
|
||||
- docs/modules/platform/architecture-overview.md
|
||||
- docs/modules/concelier/architecture.md
|
||||
- docs/modules/concelier/link-not-merge-schema.md
|
||||
|
||||
## Working Agreement
|
||||
- Use fixed times and IDs in tests.
|
||||
- Avoid network dependencies in tests.
|
||||
- Keep snapshots deterministic and invariant.
|
||||
|
||||
## Testing Strategy
|
||||
- Unit tests for schema diff and upgrade logic.
|
||||
- Regression tests for compatibility guards.
|
||||
Reference in New Issue
Block a user