stabilizaiton work - projects rework for maintenanceability and ui livening

This commit is contained in:
master
2026-02-03 23:40:04 +02:00
parent 074ce117ba
commit 557feefdc3
3305 changed files with 186813 additions and 107843 deletions

View File

@@ -8,8 +8,10 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection.Extensions;
using StellaOps.Artifact.Core;
using StellaOps.Concelier.SbomIntegration.Parsing;
using StellaOps.Determinism;
using StellaOps.Infrastructure.Postgres.Options;
namespace StellaOps.Artifact.Infrastructure;
@@ -31,32 +33,23 @@ public static class ServiceCollectionExtensions
IConfiguration configuration,
string sectionName = "ArtifactStore")
{
ArgumentNullException.ThrowIfNull(configuration);
// Configure S3 store options
services.Configure<S3UnifiedArtifactStoreOptions>(configuration.GetSection($"{sectionName}:S3"));
// Configure PostgreSQL options for index
services.Configure<PostgresOptions>("Artifact", configuration.GetSection($"{sectionName}:Postgres"));
services.Configure<PostgresOptions>(ArtifactDataSource.OptionsName, configuration.GetSection($"{sectionName}:Postgres"));
services.TryAddSingleton(TimeProvider.System);
services.TryAddSingleton<IGuidProvider, SystemGuidProvider>();
services.TryAddScoped<IArtifactTenantContext, ArtifactTenantContext>();
// Register data source
services.AddSingleton<ArtifactDataSource>(sp =>
{
var options = sp.GetRequiredService<IOptionsSnapshot<PostgresOptions>>().Get("Artifact");
var logger = sp.GetRequiredService<Microsoft.Extensions.Logging.ILogger<ArtifactDataSource>>();
return new ArtifactDataSource(Options.Create(options), logger);
});
services.AddSingleton<ArtifactDataSource>();
// Register core services
services.AddSingleton<IParsedSbomParser, ParsedSbomParser>();
services.AddSingleton<ICycloneDxExtractor, CycloneDxExtractor>();
// Register index repository
services.AddScoped<IArtifactIndexRepository>(sp =>
{
var dataSource = sp.GetRequiredService<ArtifactDataSource>();
var logger = sp.GetRequiredService<Microsoft.Extensions.Logging.ILogger<PostgresArtifactIndexRepository>>();
// TODO: Get tenant ID from context
return new PostgresArtifactIndexRepository(dataSource, logger, "default");
});
services.AddScoped<IArtifactIndexRepository, PostgresArtifactIndexRepository>();
// Register S3 artifact store
services.AddScoped<IArtifactStore, S3UnifiedArtifactStore>();
@@ -70,6 +63,10 @@ public static class ServiceCollectionExtensions
/// <returns>Service collection for chaining.</returns>
public static IServiceCollection AddInMemoryArtifactStore(this IServiceCollection services)
{
services.TryAddSingleton(TimeProvider.System);
services.TryAddSingleton<IGuidProvider, SystemGuidProvider>();
services.TryAddScoped<IArtifactTenantContext, ArtifactTenantContext>();
services.AddSingleton<IParsedSbomParser, ParsedSbomParser>();
services.AddSingleton<ICycloneDxExtractor, CycloneDxExtractor>();
services.AddSingleton<IArtifactIndexRepository, InMemoryArtifactIndexRepository>();
services.AddSingleton<IArtifactStore, InMemoryArtifactStore>();
@@ -90,113 +87,11 @@ public static class ServiceCollectionExtensions
var options = new ArtifactMigrationOptions();
configure?.Invoke(options);
services.AddSingleton(options);
services.TryAddSingleton(TimeProvider.System);
services.TryAddSingleton<IGuidProvider, SystemGuidProvider>();
services.AddScoped<ArtifactMigrationService>();
return services;
}
}
/// <summary>
/// In-memory artifact store for testing.
/// </summary>
public sealed class InMemoryArtifactStore : IArtifactStore
{
private readonly Dictionary<string, (byte[] Content, ArtifactMetadata Metadata)> _artifacts = new();
private readonly object _lock = new();
public Task<ArtifactStoreResult> StoreAsync(ArtifactStoreRequest request, CancellationToken ct = default)
{
var key = $"{request.BomRef}/{request.SerialNumber}/{request.ArtifactId}";
using var ms = new MemoryStream();
request.Content.CopyTo(ms);
var content = ms.ToArray();
using var sha = System.Security.Cryptography.SHA256.Create();
var hash = sha.ComputeHash(content);
var sha256 = Convert.ToHexStringLower(hash);
var metadata = new ArtifactMetadata
{
StorageKey = key,
BomRef = request.BomRef,
SerialNumber = request.SerialNumber,
ArtifactId = request.ArtifactId,
ContentType = request.ContentType,
SizeBytes = content.Length,
Sha256 = sha256,
CreatedAt = DateTimeOffset.UtcNow,
Type = request.Type,
TenantId = request.TenantId
};
lock (_lock)
{
var wasCreated = !_artifacts.ContainsKey(key);
_artifacts[key] = (content, metadata);
return Task.FromResult(ArtifactStoreResult.Succeeded(key, sha256, content.Length, wasCreated));
}
}
public Task<ArtifactReadResult> ReadAsync(string bomRef, string? serialNumber, string? artifactId, CancellationToken ct = default)
{
lock (_lock)
{
var matching = _artifacts
.Where(kvp => kvp.Value.Metadata.BomRef == bomRef)
.Where(kvp => serialNumber == null || kvp.Value.Metadata.SerialNumber == serialNumber)
.Where(kvp => artifactId == null || kvp.Value.Metadata.ArtifactId == artifactId)
.FirstOrDefault();
if (matching.Value.Content == null)
{
return Task.FromResult(ArtifactReadResult.NotFound());
}
return Task.FromResult(ArtifactReadResult.Succeeded(
new MemoryStream(matching.Value.Content),
matching.Value.Metadata));
}
}
public Task<IReadOnlyList<ArtifactMetadata>> ListAsync(string bomRef, string? serialNumber = null, CancellationToken ct = default)
{
lock (_lock)
{
var result = _artifacts.Values
.Where(x => x.Metadata.BomRef == bomRef)
.Where(x => serialNumber == null || x.Metadata.SerialNumber == serialNumber)
.Select(x => x.Metadata)
.ToList();
return Task.FromResult<IReadOnlyList<ArtifactMetadata>>(result);
}
}
public Task<bool> ExistsAsync(string bomRef, string serialNumber, string artifactId, CancellationToken ct = default)
{
var key = $"{bomRef}/{serialNumber}/{artifactId}";
lock (_lock)
{
return Task.FromResult(_artifacts.ContainsKey(key));
}
}
public Task<ArtifactMetadata?> GetMetadataAsync(string bomRef, string serialNumber, string artifactId, CancellationToken ct = default)
{
var key = $"{bomRef}/{serialNumber}/{artifactId}";
lock (_lock)
{
return Task.FromResult(_artifacts.TryGetValue(key, out var entry) ? entry.Metadata : null);
}
}
public Task<bool> DeleteAsync(string bomRef, string serialNumber, string artifactId, CancellationToken ct = default)
{
var key = $"{bomRef}/{serialNumber}/{artifactId}";
lock (_lock)
{
return Task.FromResult(_artifacts.Remove(key));
}
}
}