feat: add Reachability Center and Why Drawer components with tests
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled

- Implemented ReachabilityCenterComponent for displaying asset reachability status with summary and filtering options.
- Added ReachabilityWhyDrawerComponent to show detailed reachability evidence and call paths.
- Created unit tests for both components to ensure functionality and correctness.
- Updated accessibility test results for the new components.
This commit is contained in:
master
2025-12-12 18:50:35 +02:00
parent efaf3cb789
commit 3f3473ee3a
320 changed files with 10635 additions and 3677 deletions

View File

@@ -3,7 +3,7 @@ using System.Text.Json;
using Microsoft.Extensions.Logging;
using StellaOps.Concelier.Models;
using StellaOps.Concelier.Storage.Postgres.Conversion;
using MongoContracts = StellaOps.Concelier.Storage.Mongo.Advisories;
using MongoContracts = StellaOps.Concelier.Storage.Advisories;
using StellaOps.Concelier.Storage.Postgres.Models;
using StellaOps.Concelier.Storage.Postgres.Repositories;

View File

@@ -1,9 +1,9 @@
using System;
using System.Text.Json;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using StellaOps.Concelier.Bson;
using StellaOps.Concelier.Bson.IO;
using Contracts = StellaOps.Concelier.Storage.Contracts;
using MongoContracts = StellaOps.Concelier.Storage.Mongo;
using MongoContracts = StellaOps.Concelier.Storage;
namespace StellaOps.Concelier.Storage.Postgres;

View File

@@ -1,5 +1,5 @@
using System.Text.Json;
using StellaOps.Concelier.Storage.Mongo;
using StellaOps.Concelier.Storage;
using Contracts = StellaOps.Concelier.Storage.Contracts;
using StellaOps.Concelier.Storage.Postgres.Models;
using StellaOps.Concelier.Storage.Postgres.Repositories;
@@ -35,9 +35,7 @@ public sealed class PostgresDocumentStore : IDocumentStore, Contracts.IStorageDo
public async Task<DocumentRecord> UpsertAsync(DocumentRecord record, CancellationToken cancellationToken)
{
// Ensure source exists
var source = await _sourceRepository.GetByKeyAsync(record.SourceName, cancellationToken).ConfigureAwait(false)
?? throw new InvalidOperationException($"Source '{record.SourceName}' not provisioned.");
var source = await EnsureSourceAsync(record.SourceName, cancellationToken).ConfigureAwait(false);
var entity = new DocumentRecordEntity(
Id: record.Id == Guid.Empty ? Guid.NewGuid() : record.Id,
@@ -99,4 +97,29 @@ public sealed class PostgresDocumentStore : IDocumentStore, Contracts.IStorageDo
ExpiresAt: row.ExpiresAt,
Payload: row.Payload);
}
private async Task<SourceEntity> EnsureSourceAsync(string sourceName, CancellationToken cancellationToken)
{
var existing = await _sourceRepository.GetByKeyAsync(sourceName, cancellationToken).ConfigureAwait(false);
if (existing is not null)
{
return existing;
}
var now = DateTimeOffset.UtcNow;
return await _sourceRepository.UpsertAsync(new SourceEntity
{
Id = Guid.NewGuid(),
Key = sourceName,
Name = sourceName,
SourceType = sourceName,
Url = null,
Priority = 0,
Enabled = true,
Config = "{}",
Metadata = "{}",
CreatedAt = now,
UpdatedAt = now,
}, cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -1,6 +1,6 @@
using System.Text.Json;
using Dapper;
using StellaOps.Concelier.Storage.Mongo.ChangeHistory;
using StellaOps.Concelier.Storage.ChangeHistory;
namespace StellaOps.Concelier.Storage.Postgres.Repositories;

View File

@@ -1,7 +1,7 @@
using System.Linq;
using System.Text.Json;
using Dapper;
using StellaOps.Concelier.Storage.Mongo;
using StellaOps.Concelier.Storage;
using Contracts = StellaOps.Concelier.Storage.Contracts;
using StellaOps.Concelier.Storage.Postgres;
@@ -83,7 +83,7 @@ internal sealed class PostgresDtoStore : IDtoStore, Contracts.IStorageDtoStore
private DtoRecord ToRecord(DtoRow row)
{
var payload = MongoDB.Bson.BsonDocument.Parse(row.PayloadJson);
var payload = StellaOps.Concelier.Bson.BsonDocument.Parse(row.PayloadJson);
return new DtoRecord(
row.Id,
row.DocumentId,

View File

@@ -1,6 +1,6 @@
using System.Text.Json;
using Dapper;
using StellaOps.Concelier.Storage.Mongo.Exporting;
using StellaOps.Concelier.Storage.Exporting;
namespace StellaOps.Concelier.Storage.Postgres.Repositories;

View File

@@ -1,5 +1,5 @@
using Dapper;
using StellaOps.Concelier.Storage.Mongo.JpFlags;
using StellaOps.Concelier.Storage.JpFlags;
namespace StellaOps.Concelier.Storage.Postgres.Repositories;

View File

@@ -1,5 +1,5 @@
using Dapper;
using StellaOps.Concelier.Storage.Mongo.PsirtFlags;
using StellaOps.Concelier.Storage.PsirtFlags;
namespace StellaOps.Concelier.Storage.Postgres.Repositories;

View File

@@ -5,12 +5,12 @@ using StellaOps.Concelier.Storage.Postgres.Advisories;
using StellaOps.Infrastructure.Postgres;
using StellaOps.Infrastructure.Postgres.Options;
using StellaOps.Concelier.Core.Linksets;
using MongoContracts = StellaOps.Concelier.Storage.Mongo;
using MongoAdvisories = StellaOps.Concelier.Storage.Mongo.Advisories;
using MongoExporting = StellaOps.Concelier.Storage.Mongo.Exporting;
using MongoJpFlags = StellaOps.Concelier.Storage.Mongo.JpFlags;
using MongoPsirt = StellaOps.Concelier.Storage.Mongo.PsirtFlags;
using MongoHistory = StellaOps.Concelier.Storage.Mongo.ChangeHistory;
using MongoContracts = StellaOps.Concelier.Storage;
using MongoAdvisories = StellaOps.Concelier.Storage.Advisories;
using MongoExporting = StellaOps.Concelier.Storage.Exporting;
using MongoJpFlags = StellaOps.Concelier.Storage.JpFlags;
using MongoPsirt = StellaOps.Concelier.Storage.PsirtFlags;
using MongoHistory = StellaOps.Concelier.Storage.ChangeHistory;
namespace StellaOps.Concelier.Storage.Postgres;
@@ -45,7 +45,7 @@ public static class ServiceCollectionExtensions
services.AddScoped<IAdvisoryCreditRepository, AdvisoryCreditRepository>();
services.AddScoped<IAdvisoryWeaknessRepository, AdvisoryWeaknessRepository>();
services.AddScoped<IKevFlagRepository, KevFlagRepository>();
services.AddScoped<ISourceStateRepository, SourceStateRepository>();
services.AddScoped<StellaOps.Concelier.Storage.Postgres.Repositories.ISourceStateRepository, SourceStateRepository>();
services.AddScoped<MongoAdvisories.IAdvisoryStore, PostgresAdvisoryStore>();
services.AddScoped<IDocumentRepository, DocumentRepository>();
services.AddScoped<MongoContracts.ISourceStateRepository, PostgresSourceStateAdapter>();
@@ -88,7 +88,7 @@ public static class ServiceCollectionExtensions
services.AddScoped<IAdvisoryCreditRepository, AdvisoryCreditRepository>();
services.AddScoped<IAdvisoryWeaknessRepository, AdvisoryWeaknessRepository>();
services.AddScoped<IKevFlagRepository, KevFlagRepository>();
services.AddScoped<ISourceStateRepository, SourceStateRepository>();
services.AddScoped<StellaOps.Concelier.Storage.Postgres.Repositories.ISourceStateRepository, SourceStateRepository>();
services.AddScoped<MongoAdvisories.IAdvisoryStore, PostgresAdvisoryStore>();
services.AddScoped<IDocumentRepository, DocumentRepository>();
services.AddScoped<MongoContracts.ISourceStateRepository, PostgresSourceStateAdapter>();

View File

@@ -1,11 +1,11 @@
using System;
using System.Text.Json;
using System.Collections.Generic;
using MongoDB.Bson;
using StellaOps.Concelier.Bson;
using StellaOps.Concelier.Storage.Postgres.Models;
using StellaOps.Concelier.Storage.Postgres.Repositories;
using Contracts = StellaOps.Concelier.Storage.Contracts;
using MongoContracts = StellaOps.Concelier.Storage.Mongo;
using MongoContracts = StellaOps.Concelier.Storage;
namespace StellaOps.Concelier.Storage.Postgres;
@@ -45,6 +45,7 @@ public sealed class PostgresSourceStateAdapter : MongoContracts.ISourceStateRepo
}
var cursor = string.IsNullOrWhiteSpace(state.Cursor) ? null : BsonDocument.Parse(state.Cursor);
var backoffUntil = TryParseBackoffUntil(state.Metadata);
return new MongoContracts.SourceStateRecord(
sourceName,
Enabled: true,
@@ -53,7 +54,7 @@ public sealed class PostgresSourceStateAdapter : MongoContracts.ISourceStateRepo
LastSuccess: state.LastSuccessAt,
LastFailure: state.LastError is null ? null : state.LastSyncAt,
FailCount: state.ErrorCount,
BackoffUntil: null,
BackoffUntil: backoffUntil,
UpdatedAt: state.UpdatedAt,
LastFailureReason: state.LastError);
}
@@ -183,4 +184,32 @@ public sealed class PostgresSourceStateAdapter : MongoContracts.ISourceStateRepo
return delta < TimeSpan.Zero ? DateTimeOffset.MinValue : DateTimeOffset.MaxValue;
}
}
private static DateTimeOffset? TryParseBackoffUntil(string? metadata)
{
if (string.IsNullOrWhiteSpace(metadata))
{
return null;
}
try
{
using var document = JsonDocument.Parse(metadata);
if (!document.RootElement.TryGetProperty("backoffUntil", out var backoffProperty))
{
return null;
}
if (backoffProperty.ValueKind == JsonValueKind.String
&& DateTimeOffset.TryParse(backoffProperty.GetString(), out var parsed))
{
return parsed;
}
}
catch
{
}
return null;
}
}