audit work, fixed StellaOps.sln warnings/errors, fixed tests, sprints work, new advisories

This commit is contained in:
master
2026-01-07 18:49:59 +02:00
parent 04ec098046
commit 608a7f85c0
866 changed files with 56323 additions and 6231 deletions

View File

@@ -12,7 +12,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="xunit.v3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
</ItemGroup>

View File

@@ -1,5 +1,6 @@
using System.Buffers;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
@@ -311,7 +312,7 @@ public sealed class CombinedRuntimeAdapter : IExportAdapter
writer.WriteString("type", "combined.header");
writer.WriteString("version", "1.0.0");
writer.WriteString("schema", "stellaops.combined.runtime@v1");
writer.WriteString("generated_at", timestamp.UtcDateTime.ToString("O"));
writer.WriteString("generated_at", timestamp.UtcDateTime.ToString("O", CultureInfo.InvariantCulture));
writer.WriteString("tenant_id", context.TenantId.ToString("D"));
if (!string.IsNullOrEmpty(context.CorrelationId))
{
@@ -342,7 +343,7 @@ public sealed class CombinedRuntimeAdapter : IExportAdapter
writer.WriteNumber("runtime_events", runtimeEventCount);
writer.WriteNumber("total", entryTraceCount + runtimeEventCount);
writer.WriteEndObject();
writer.WriteString("completed_at", timestamp.UtcDateTime.ToString("O"));
writer.WriteString("completed_at", timestamp.UtcDateTime.ToString("O", CultureInfo.InvariantCulture));
writer.WriteEndObject();
writer.Flush();
}

View File

@@ -2,6 +2,7 @@ using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Formats.Tar;
using System.Globalization;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
@@ -217,7 +218,7 @@ public sealed class DevPortalOfflineBundleBuilder
builder.AppendLine("DevPortal Offline Bundle");
builder.AppendLine("========================");
builder.Append("Bundle ID: ").AppendLine(manifest.BundleId.ToString("D"));
builder.Append("Generated At: ").AppendLine(manifest.GeneratedAt.ToString("O"));
builder.Append("Generated At: ").AppendLine(manifest.GeneratedAt.ToString("O", CultureInfo.InvariantCulture));
if (manifest.Metadata.TryGetValue("releaseVersion", out var releaseVersion))
{

View File

@@ -1,5 +1,6 @@
using System.Buffers.Binary;
using System.Formats.Tar;
using System.Globalization;
using System.IO.Compression;
using System.Text;
using System.Text.Json;
@@ -431,8 +432,8 @@ public sealed class MirrorBundleBuilder
if (manifest.Selectors.TimeWindow is not null)
{
builder.AppendLine(" timeWindow:");
builder.Append(" from: ").AppendLine(manifest.Selectors.TimeWindow.From.ToString("O"));
builder.Append(" to: ").AppendLine(manifest.Selectors.TimeWindow.To.ToString("O"));
builder.Append(" from: ").AppendLine(manifest.Selectors.TimeWindow.From.ToString("O", CultureInfo.InvariantCulture));
builder.Append(" to: ").AppendLine(manifest.Selectors.TimeWindow.To.ToString("O", CultureInfo.InvariantCulture));
}
builder.AppendLine("counts:");

View File

@@ -1,3 +1,4 @@
using System.Globalization;
using System.Net;
using System.Net.Http.Headers;
using System.Security.Cryptography;
@@ -47,7 +48,7 @@ public sealed class ExportWebhookClient : IExportWebhookClient
// Add standard headers
request.Headers.Add(ExportNotificationHeaders.EventType, eventType);
request.Headers.Add(ExportNotificationHeaders.SentAt, sentAt.ToString("O"));
request.Headers.Add(ExportNotificationHeaders.SentAt, sentAt.ToString("O", CultureInfo.InvariantCulture));
// Add signature if signing key is configured
if (!string.IsNullOrWhiteSpace(_options.SigningKey))
@@ -118,7 +119,7 @@ public sealed class ExportWebhookClient : IExportWebhookClient
public static string ComputeSignature(string payload, DateTimeOffset sentAt, string signingKey)
{
// PAE (Pre-Authentication Encoding) style: timestamp.payload
var signatureInput = $"{sentAt:O}.{payload}";
var signatureInput = $"{sentAt.ToString("O", CultureInfo.InvariantCulture)}.{payload}";
var inputBytes = Encoding.UTF8.GetBytes(signatureInput);
byte[] keyBytes;

View File

@@ -1,4 +1,5 @@
using System.Formats.Tar;
using System.Globalization;
using System.IO.Compression;
using System.Reflection;
using System.Security.Cryptography;
@@ -273,7 +274,7 @@ public sealed class OfflineBundlePackager : IOfflineBundlePackager
alert_id = request.AlertId,
tenant_id = request.TenantId,
artifact_id = request.ArtifactId,
created_at = now.ToString("O"),
created_at = now.ToString("O", CultureInfo.InvariantCulture),
created_by = request.ActorId
};
entries.Add(await WriteJsonEntryAsync(
@@ -283,7 +284,7 @@ public sealed class OfflineBundlePackager : IOfflineBundlePackager
var artifactMetadata = new
{
artifact_id = request.ArtifactId,
captured_at = now.ToString("O")
captured_at = now.ToString("O", CultureInfo.InvariantCulture)
};
entries.Add(await WriteJsonEntryAsync(
tempDir, "metadata/artifact.json", BundleEntryTypes.Metadata, artifactMetadata, cancellationToken));
@@ -291,8 +292,8 @@ public sealed class OfflineBundlePackager : IOfflineBundlePackager
// Write timestamps
var timestamps = new
{
bundle_created_at = now.ToString("O"),
evidence_captured_at = now.ToString("O"),
bundle_created_at = now.ToString("O", CultureInfo.InvariantCulture),
evidence_captured_at = now.ToString("O", CultureInfo.InvariantCulture),
baseline_scan_id = request.BaselineScanId
};
entries.Add(await WriteJsonEntryAsync(
@@ -313,7 +314,7 @@ public sealed class OfflineBundlePackager : IOfflineBundlePackager
{
status = "pending",
alert_id = request.AlertId,
computed_at = _timeProvider.GetUtcNow().ToString("O")
computed_at = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture)
};
entries.Add(await WriteJsonEntryAsync(
tempDir, "evidence/reachability.json", BundleEntryTypes.Evidence, reachability, cancellationToken));

View File

@@ -3,6 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
// ----------------------------------------------------------------------------
using System.Globalization;
using StellaOps.Provcache;
using StellaOps.Provcache.Oci;
@@ -129,7 +130,7 @@ public sealed class ProvcacheOciExporter : IProvcacheOciExporter
{
var annotations = new Dictionary<string, string>(StringComparer.Ordinal)
{
["org.opencontainers.image.created"] = _timeProvider.GetUtcNow().ToString("O"),
["org.opencontainers.image.created"] = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture),
["org.opencontainers.image.title"] = "stellaops.provcache.decision",
["org.opencontainers.image.description"] = "Provcache decision attestation",
["stellaops.provcache.verikey"] = request.DecisionDigest.VeriKey,

View File

@@ -7,6 +7,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
@@ -264,7 +265,7 @@ public sealed class EvidencePackSigningService : IEvidencePackSigningService
MerkleRoot = pack.Manifest!.MerkleRoot,
FileCount = pack.Manifest.FileCount,
TotalSizeBytes = pack.Manifest.TotalSizeBytes,
GeneratedAt = pack.GeneratedAt.ToString("O"),
GeneratedAt = pack.GeneratedAt.ToString("O", CultureInfo.InvariantCulture),
SbomFormats = pack.SbomDocuments.Select(s => $"{s.Format}@{s.FormatVersion}").ToList(),
VexFormats = pack.VexDocuments.Select(v => $"{v.Format}@{v.FormatVersion}").ToList(),
HasPolicyVerdict = pack.PolicyVerdict is not null,

View File

@@ -8,6 +8,7 @@
using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
@@ -349,7 +350,7 @@ public sealed class LineageEvidencePackService : ILineageEvidencePackService
bomFormat = "CycloneDX",
specVersion = "1.6",
version = 1,
metadata = new { timestamp = _timeProvider.GetUtcNow().ToString("O") },
metadata = new { timestamp = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture) },
components = Array.Empty<object>()
}, JsonOptions);
@@ -385,7 +386,7 @@ public sealed class LineageEvidencePackService : ILineageEvidencePackService
dataLicense = "CC0-1.0",
name = artifactDigest,
documentNamespace = $"https://stellaops.io/spdx/{artifactDigest}",
creationInfo = new { created = _timeProvider.GetUtcNow().ToString("O") },
creationInfo = new { created = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture) },
packages = Array.Empty<object>()
}, JsonOptions);
@@ -420,7 +421,7 @@ public sealed class LineageEvidencePackService : ILineageEvidencePackService
context = "https://openvex.dev/ns/v0.2.0",
id = $"urn:stellaops:vex:{artifactDigest}",
author = "StellaOps",
timestamp = _timeProvider.GetUtcNow().ToString("O"),
timestamp = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture),
statements = Array.Empty<object>()
}, JsonOptions);
@@ -459,7 +460,7 @@ public sealed class LineageEvidencePackService : ILineageEvidencePackService
tenantId,
verdict = "pass",
policyVersion = "1.0.0",
evaluatedAt = _timeProvider.GetUtcNow().ToString("O"),
evaluatedAt = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture),
rules = new { total = 0, passed = 0, failed = 0, warned = 0 }
}, JsonOptions);
@@ -532,7 +533,7 @@ public sealed class LineageEvidencePackService : ILineageEvidencePackService
private string ComputeReplayHash(string artifactDigest, string sbomDigest, string merkleRoot)
{
var input = $"{artifactDigest}|{sbomDigest}|{merkleRoot}|{_timeProvider.GetUtcNow():O}";
var input = $"{artifactDigest}|{sbomDigest}|{merkleRoot}|{_timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture)}";
return $"sha256:{ComputeHash(input)}";
}

View File

@@ -52,7 +52,6 @@
<ItemGroup>
<PackageReference Include="xunit.v3" />
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Moq" />
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System.Globalization;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
@@ -15,15 +16,17 @@ public sealed class AuditBundleJobHandler : IAuditBundleJobHandler
{
private readonly ConcurrentDictionary<string, AuditBundleJob> _jobs = new();
private readonly ILogger<AuditBundleJobHandler> _logger;
private readonly TimeProvider _timeProvider;
private static readonly JsonSerializerOptions JsonOptions = new()
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
public AuditBundleJobHandler(ILogger<AuditBundleJobHandler> logger)
public AuditBundleJobHandler(ILogger<AuditBundleJobHandler> logger, TimeProvider? timeProvider = null)
{
_logger = logger;
_timeProvider = timeProvider ?? TimeProvider.System;
}
public Task<AuditBundleCreateResult> CreateBundleAsync(
@@ -48,7 +51,7 @@ public sealed class AuditBundleJobHandler : IAuditBundleJobHandler
}
var bundleId = $"bndl-{Guid.NewGuid():N}";
var now = DateTimeOffset.UtcNow;
var now = _timeProvider.GetUtcNow();
var job = new AuditBundleJob
{
@@ -246,7 +249,7 @@ public sealed class AuditBundleJobHandler : IAuditBundleJobHandler
"stella.ops/v1",
"AuditBundleIndex",
job.BundleId,
DateTimeOffset.UtcNow,
_timeProvider.GetUtcNow(),
job.CreatedBy,
job.Subject,
job.TimeWindow,
@@ -271,7 +274,7 @@ public sealed class AuditBundleJobHandler : IAuditBundleJobHandler
job.Status = "Completed";
job.Progress = 100;
job.CompletedAt = DateTimeOffset.UtcNow;
job.CompletedAt = _timeProvider.GetUtcNow();
_logger.LogInformation(
"Completed audit bundle {BundleId} with hash {BundleHash}",
@@ -286,12 +289,12 @@ public sealed class AuditBundleJobHandler : IAuditBundleJobHandler
}
}
private static string CreateSampleVulnReport(BundleSubjectRefDto subject)
private string CreateSampleVulnReport(BundleSubjectRefDto subject)
{
var report = new
{
subject = subject.Name,
scanDate = DateTimeOffset.UtcNow.ToString("O"),
scanDate = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture),
findings = new[]
{
new { id = "CVE-2023-12345", severity = "HIGH", package = "sample-pkg", version = "1.0.0" }

View File

@@ -1,3 +1,4 @@
using System.Globalization;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using StellaOps.ExportCenter.Core.Domain;
@@ -162,7 +163,7 @@ public sealed class ExportDistributionLifecycle : IExportDistributionLifecycle
["location"] = location,
["etag"] = etag,
["versionId"] = versionId,
["distributedAt"] = _timeProvider.GetUtcNow().ToString("O")
["distributedAt"] = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture)
};
return await UpdateDistributionStatusAsync(
@@ -189,7 +190,7 @@ public sealed class ExportDistributionLifecycle : IExportDistributionLifecycle
{
["code"] = errorCode,
["message"] = errorMessage,
["timestamp"] = _timeProvider.GetUtcNow().ToString("O")
["timestamp"] = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture)
};
return await UpdateDistributionStatusAsync(
@@ -231,7 +232,7 @@ public sealed class ExportDistributionLifecycle : IExportDistributionLifecycle
existingMetadata ??= new Dictionary<string, object?>();
existingMetadata["verified"] = verified;
existingMetadata["verifiedAt"] = now.ToString("O");
existingMetadata["verifiedAt"] = now.ToString("O", CultureInfo.InvariantCulture);
if (!string.IsNullOrEmpty(verificationDetails))
{
existingMetadata["verificationDetails"] = verificationDetails;

View File

@@ -1,3 +1,4 @@
using System.Globalization;
using System.Net;
using System.Net.Http.Headers;
using System.Security.Cryptography;
@@ -464,7 +465,7 @@ public sealed class OciDistributionClient : IOciDistributionClient
{
var annotations = new Dictionary<string, string>
{
[OciAnnotations.Created] = _timeProvider.GetUtcNow().ToString("O"),
[OciAnnotations.Created] = _timeProvider.GetUtcNow().ToString("O", CultureInfo.InvariantCulture),
[OciAnnotations.Vendor] = "StellaOps"
};

View File

@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
@@ -307,7 +308,7 @@ public sealed class SimulationReportExporter : ISimulationReportExporter
yield return new SimulationExportLine
{
Type = "complete",
Data = new { exported_at = now.ToString("O") }
Data = new { exported_at = now.ToString("O", CultureInfo.InvariantCulture) }
};
}