feat(graph-api): Add schema review notes for upcoming Graph API changes
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
feat(sbomservice): Add placeholder for SHA256SUMS in LNM v1 fixtures docs(devportal): Create README for SDK archives in public directory build(devportal): Implement offline bundle build script test(devportal): Add link checker script for validating links in documentation test(devportal): Create performance check script for dist folder size test(devportal): Implement accessibility check script using Playwright and Axe docs(devportal): Add SDK quickstart guide with examples for Node.js, Python, and cURL feat(excititor): Implement MongoDB storage for airgap import records test(findings): Add unit tests for export filters hash determinism feat(findings): Define attestation contracts for ledger web service feat(graph): Add MongoDB options and service collection extensions for graph indexing test(graph): Implement integration tests for MongoDB provider and service collection extensions feat(zastava): Define configuration options for Zastava surface secrets build(tests): Create script to run Concelier linkset tests with TRX output
This commit is contained in:
@@ -140,11 +140,13 @@ app.MapHealthChecks("/excititor/health");
|
||||
|
||||
app.MapPost("/airgap/v1/vex/import", async (
|
||||
[FromServices] AirgapImportValidator validator,
|
||||
[FromServices] IAirgapImportStore store,
|
||||
[FromServices] TimeProvider timeProvider,
|
||||
[FromBody] AirgapImportRequest request,
|
||||
CancellationToken cancellationToken) =>
|
||||
{
|
||||
var errors = validator.Validate(request, timeProvider.GetUtcNow());
|
||||
var nowUtc = timeProvider.GetUtcNow();
|
||||
var errors = validator.Validate(request, nowUtc);
|
||||
if (errors.Count > 0)
|
||||
{
|
||||
var first = errors[0];
|
||||
@@ -158,6 +160,22 @@ app.MapPost("/airgap/v1/vex/import", async (
|
||||
});
|
||||
}
|
||||
|
||||
var record = new AirgapImportRecord
|
||||
{
|
||||
Id = $"{request.BundleId}:{request.MirrorGeneration}",
|
||||
BundleId = request.BundleId!,
|
||||
MirrorGeneration = request.MirrorGeneration!,
|
||||
SignedAt = request.SignedAt!.Value,
|
||||
Publisher = request.Publisher!,
|
||||
PayloadHash = request.PayloadHash!,
|
||||
PayloadUrl = request.PayloadUrl,
|
||||
Signature = request.Signature!,
|
||||
TransparencyLog = request.TransparencyLog,
|
||||
ImportedAt = nowUtc
|
||||
};
|
||||
|
||||
await store.SaveAsync(record, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
return Results.Accepted($"/airgap/v1/vex/import/{request.BundleId}", new
|
||||
{
|
||||
bundleId = request.BundleId,
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MongoDB.Driver;
|
||||
|
||||
namespace StellaOps.Excititor.Storage.Mongo;
|
||||
|
||||
public interface IAirgapImportStore
|
||||
{
|
||||
Task SaveAsync(AirgapImportRecord record, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
internal sealed class MongoAirgapImportStore : IAirgapImportStore
|
||||
{
|
||||
private readonly IMongoCollection<AirgapImportRecord> _collection;
|
||||
|
||||
public MongoAirgapImportStore(IMongoDatabase database)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(database);
|
||||
VexMongoMappingRegistry.Register();
|
||||
_collection = database.GetCollection<AirgapImportRecord>(VexMongoCollectionNames.AirgapImports);
|
||||
}
|
||||
|
||||
public Task SaveAsync(AirgapImportRecord record, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(record);
|
||||
return _collection.InsertOneAsync(record, cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,7 @@ public static class VexMongoServiceCollectionExtensions
|
||||
services.AddScoped<IVexCacheIndex, MongoVexCacheIndex>();
|
||||
services.AddScoped<IVexCacheMaintenance, MongoVexCacheMaintenance>();
|
||||
services.AddScoped<IVexConnectorStateRepository, MongoVexConnectorStateRepository>();
|
||||
services.AddScoped<IAirgapImportStore, MongoAirgapImportStore>();
|
||||
services.AddScoped<VexStatementBackfillService>();
|
||||
services.AddScoped<IVexObservationLookup, MongoVexObservationLookup>();
|
||||
services.AddSingleton<IVexMongoMigration, VexInitialIndexMigration>();
|
||||
|
||||
@@ -1,69 +1,70 @@
|
||||
using System.Threading;
|
||||
using MongoDB.Bson.Serialization;
|
||||
using MongoDB.Bson.Serialization.Serializers;
|
||||
|
||||
namespace StellaOps.Excititor.Storage.Mongo;
|
||||
|
||||
public static class VexMongoMappingRegistry
|
||||
{
|
||||
private static int _initialized;
|
||||
|
||||
public static void Register()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _initialized, 1) == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
BsonSerializer.RegisterSerializer(typeof(byte[]), new ByteArraySerializer());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// serializer already registered – safe to ignore
|
||||
}
|
||||
|
||||
RegisterClassMaps();
|
||||
}
|
||||
|
||||
private static void RegisterClassMaps()
|
||||
{
|
||||
RegisterClassMap<VexProviderRecord>();
|
||||
RegisterClassMap<VexProviderDiscoveryDocument>();
|
||||
RegisterClassMap<VexProviderTrustDocument>();
|
||||
RegisterClassMap<VexCosignTrustDocument>();
|
||||
RegisterClassMap<VexConsensusRecord>();
|
||||
RegisterClassMap<VexProductDocument>();
|
||||
RegisterClassMap<VexConsensusSourceDocument>();
|
||||
RegisterClassMap<VexConsensusConflictDocument>();
|
||||
RegisterClassMap<VexConfidenceDocument>();
|
||||
RegisterClassMap<VexSignalDocument>();
|
||||
RegisterClassMap<VexSeveritySignalDocument>();
|
||||
RegisterClassMap<VexClaimDocumentRecord>();
|
||||
RegisterClassMap<VexSignatureMetadataDocument>();
|
||||
RegisterClassMap<VexStatementRecord>();
|
||||
using System.Threading;
|
||||
using MongoDB.Bson.Serialization;
|
||||
using MongoDB.Bson.Serialization.Serializers;
|
||||
|
||||
namespace StellaOps.Excititor.Storage.Mongo;
|
||||
|
||||
public static class VexMongoMappingRegistry
|
||||
{
|
||||
private static int _initialized;
|
||||
|
||||
public static void Register()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _initialized, 1) == 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
BsonSerializer.RegisterSerializer(typeof(byte[]), new ByteArraySerializer());
|
||||
}
|
||||
catch
|
||||
{
|
||||
// serializer already registered – safe to ignore
|
||||
}
|
||||
|
||||
RegisterClassMaps();
|
||||
}
|
||||
|
||||
private static void RegisterClassMaps()
|
||||
{
|
||||
RegisterClassMap<VexProviderRecord>();
|
||||
RegisterClassMap<VexProviderDiscoveryDocument>();
|
||||
RegisterClassMap<VexProviderTrustDocument>();
|
||||
RegisterClassMap<VexCosignTrustDocument>();
|
||||
RegisterClassMap<VexConsensusRecord>();
|
||||
RegisterClassMap<VexProductDocument>();
|
||||
RegisterClassMap<VexConsensusSourceDocument>();
|
||||
RegisterClassMap<VexConsensusConflictDocument>();
|
||||
RegisterClassMap<VexConfidenceDocument>();
|
||||
RegisterClassMap<VexSignalDocument>();
|
||||
RegisterClassMap<VexSeveritySignalDocument>();
|
||||
RegisterClassMap<VexClaimDocumentRecord>();
|
||||
RegisterClassMap<VexSignatureMetadataDocument>();
|
||||
RegisterClassMap<VexStatementRecord>();
|
||||
RegisterClassMap<VexCacheEntryRecord>();
|
||||
RegisterClassMap<VexConnectorStateDocument>();
|
||||
RegisterClassMap<VexConsensusHoldRecord>();
|
||||
}
|
||||
|
||||
private static void RegisterClassMap<TDocument>()
|
||||
where TDocument : class
|
||||
{
|
||||
if (BsonClassMap.IsClassMapRegistered(typeof(TDocument)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BsonClassMap.RegisterClassMap<TDocument>(classMap =>
|
||||
{
|
||||
classMap.AutoMap();
|
||||
classMap.SetIgnoreExtraElements(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
RegisterClassMap<AirgapImportRecord>();
|
||||
}
|
||||
|
||||
private static void RegisterClassMap<TDocument>()
|
||||
where TDocument : class
|
||||
{
|
||||
if (BsonClassMap.IsClassMapRegistered(typeof(TDocument)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BsonClassMap.RegisterClassMap<TDocument>(classMap =>
|
||||
{
|
||||
classMap.AutoMap();
|
||||
classMap.SetIgnoreExtraElements(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class VexMongoCollectionNames
|
||||
{
|
||||
public const string Migrations = "vex.migrations";
|
||||
@@ -79,4 +80,5 @@ public static class VexMongoCollectionNames
|
||||
public const string Attestations = "vex.attestations";
|
||||
public const string Observations = "vex.observations";
|
||||
public const string Linksets = "vex.linksets";
|
||||
public const string AirgapImports = "vex.airgap_imports";
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@ internal static class TestServiceOverrides
|
||||
services.RemoveAll<IVexCacheMaintenance>();
|
||||
services.RemoveAll<IVexAttestationClient>();
|
||||
services.RemoveAll<IVexSigner>();
|
||||
services.RemoveAll<IAirgapImportStore>();
|
||||
|
||||
services.AddSingleton<IVexIngestOrchestrator, StubIngestOrchestrator>();
|
||||
services.AddSingleton<IVexConnectorStateRepository, StubConnectorStateRepository>();
|
||||
@@ -45,6 +46,7 @@ internal static class TestServiceOverrides
|
||||
services.AddSingleton<IVexCacheMaintenance, StubCacheMaintenance>();
|
||||
services.AddSingleton<IVexAttestationClient, StubAttestationClient>();
|
||||
services.AddSingleton<IVexSigner, StubSigner>();
|
||||
services.AddSingleton<IAirgapImportStore, StubAirgapImportStore>();
|
||||
|
||||
services.RemoveAll<IHostedService>();
|
||||
services.AddSingleton<IHostedService, NoopHostedService>();
|
||||
@@ -200,6 +202,17 @@ internal static class TestServiceOverrides
|
||||
public ValueTask<VexSignedPayload> SignAsync(ReadOnlyMemory<byte> payload, CancellationToken cancellationToken)
|
||||
=> ValueTask.FromResult(new VexSignedPayload("stub-signature", "stub-key"));
|
||||
}
|
||||
|
||||
private sealed class StubAirgapImportStore : IAirgapImportStore
|
||||
{
|
||||
private readonly List<AirgapImportRecord> _records = new();
|
||||
|
||||
public Task SaveAsync(AirgapImportRecord record, CancellationToken cancellationToken)
|
||||
{
|
||||
_records.Add(record);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class StubIngestOrchestrator : IVexIngestOrchestrator
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user