up
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
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
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
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
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
This commit is contained in:
@@ -1,39 +1,39 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using StellaOps.Concelier.WebService.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Tests;
|
||||
|
||||
public sealed class ConcelierOptionsPostConfigureTests
|
||||
{
|
||||
[Fact]
|
||||
using System;
|
||||
using System.IO;
|
||||
using StellaOps.Concelier.WebService.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Tests;
|
||||
|
||||
public sealed class ConcelierOptionsPostConfigureTests
|
||||
{
|
||||
[Fact]
|
||||
public void Apply_LoadsClientSecretFromRelativeFile()
|
||||
{
|
||||
var tempDirectory = Directory.CreateTempSubdirectory();
|
||||
try
|
||||
{
|
||||
var secretPath = Path.Combine(tempDirectory.FullName, "authority.secret");
|
||||
File.WriteAllText(secretPath, " concelier-secret ");
|
||||
|
||||
var options = new ConcelierOptions
|
||||
{
|
||||
Authority = new ConcelierOptions.AuthorityOptions
|
||||
{
|
||||
ClientSecretFile = "authority.secret"
|
||||
}
|
||||
};
|
||||
|
||||
ConcelierOptionsPostConfigure.Apply(options, tempDirectory.FullName);
|
||||
|
||||
Assert.Equal("concelier-secret", options.Authority.ClientSecret);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(tempDirectory.FullName))
|
||||
{
|
||||
Directory.Delete(tempDirectory.FullName, recursive: true);
|
||||
}
|
||||
var secretPath = Path.Combine(tempDirectory.FullName, "authority.secret");
|
||||
File.WriteAllText(secretPath, " concelier-secret ");
|
||||
|
||||
var options = new ConcelierOptions
|
||||
{
|
||||
Authority = new ConcelierOptions.AuthorityOptions
|
||||
{
|
||||
ClientSecretFile = "authority.secret"
|
||||
}
|
||||
};
|
||||
|
||||
ConcelierOptionsPostConfigure.Apply(options, tempDirectory.FullName);
|
||||
|
||||
Assert.Equal("concelier-secret", options.Authority.ClientSecret);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(tempDirectory.FullName))
|
||||
{
|
||||
Directory.Delete(tempDirectory.FullName, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,15 +50,15 @@ public sealed class ConcelierOptionsPostConfigureTests
|
||||
{
|
||||
var options = new ConcelierOptions
|
||||
{
|
||||
Authority = new ConcelierOptions.AuthorityOptions
|
||||
{
|
||||
ClientSecretFile = "missing.secret"
|
||||
}
|
||||
};
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() =>
|
||||
ConcelierOptionsPostConfigure.Apply(options, AppContext.BaseDirectory));
|
||||
|
||||
Assert.Contains("Authority client secret file", exception.Message);
|
||||
}
|
||||
}
|
||||
Authority = new ConcelierOptions.AuthorityOptions
|
||||
{
|
||||
ClientSecretFile = "missing.secret"
|
||||
}
|
||||
};
|
||||
|
||||
var exception = Assert.Throws<InvalidOperationException>(() =>
|
||||
ConcelierOptionsPostConfigure.Apply(options, AppContext.BaseDirectory));
|
||||
|
||||
Assert.Contains("Authority client secret file", exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Text.Json;
|
||||
using StellaOps.Concelier.Bson.Serialization.Attributes;
|
||||
using StellaOps.Concelier.Documents.Serialization.Attributes;
|
||||
using StellaOps.Concelier.RawModels;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Tests.Fixtures;
|
||||
@@ -344,31 +344,31 @@ public sealed record AdvisoryChunkSeedSet(
|
||||
/// </summary>
|
||||
public sealed class AdvisorySeedDocument
|
||||
{
|
||||
[BsonElement("tenantId")]
|
||||
[DocumentElement("tenantId")]
|
||||
public string TenantId { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("advisoryKey")]
|
||||
[DocumentElement("advisoryKey")]
|
||||
public string AdvisoryKey { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("source")]
|
||||
[DocumentElement("source")]
|
||||
public string Source { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("severity")]
|
||||
[DocumentElement("severity")]
|
||||
public string Severity { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("title")]
|
||||
[DocumentElement("title")]
|
||||
public string Title { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("description")]
|
||||
[DocumentElement("description")]
|
||||
public string Description { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("published")]
|
||||
[DocumentElement("published")]
|
||||
public DateTime Published { get; init; }
|
||||
|
||||
[BsonElement("modified")]
|
||||
[DocumentElement("modified")]
|
||||
public DateTime Modified { get; init; }
|
||||
|
||||
[BsonElement("fingerprint")]
|
||||
[DocumentElement("fingerprint")]
|
||||
public string Fingerprint { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
@@ -377,25 +377,25 @@ public sealed class AdvisorySeedDocument
|
||||
/// </summary>
|
||||
public sealed class ObservationSeedDocument
|
||||
{
|
||||
[BsonElement("tenantId")]
|
||||
[DocumentElement("tenantId")]
|
||||
public string TenantId { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("observationId")]
|
||||
[DocumentElement("observationId")]
|
||||
public string ObservationId { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("advisoryKey")]
|
||||
[DocumentElement("advisoryKey")]
|
||||
public string AdvisoryKey { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("source")]
|
||||
[DocumentElement("source")]
|
||||
public string Source { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("format")]
|
||||
[DocumentElement("format")]
|
||||
public string Format { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("rawContent")]
|
||||
[DocumentElement("rawContent")]
|
||||
public string RawContent { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("createdAt")]
|
||||
[DocumentElement("createdAt")]
|
||||
public DateTime CreatedAt { get; init; }
|
||||
}
|
||||
|
||||
@@ -404,15 +404,15 @@ public sealed class ObservationSeedDocument
|
||||
/// </summary>
|
||||
public sealed class AliasSeedDocument
|
||||
{
|
||||
[BsonElement("tenantId")]
|
||||
[DocumentElement("tenantId")]
|
||||
public string TenantId { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("alias")]
|
||||
[DocumentElement("alias")]
|
||||
public string Alias { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("canonicalId")]
|
||||
[DocumentElement("canonicalId")]
|
||||
public string CanonicalId { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("aliases")]
|
||||
[DocumentElement("aliases")]
|
||||
public IReadOnlyList<string> Aliases { get; init; } = Array.Empty<string>();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using StellaOps.Concelier.Bson.Serialization.Attributes;
|
||||
using StellaOps.Concelier.Documents.Serialization.Attributes;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Tests;
|
||||
|
||||
@@ -10,31 +10,31 @@ namespace StellaOps.Concelier.WebService.Tests;
|
||||
/// </summary>
|
||||
internal sealed class AdvisoryLinksetDocument
|
||||
{
|
||||
[BsonElement("tenantId")]
|
||||
[DocumentElement("tenantId")]
|
||||
public string TenantId { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("source")]
|
||||
[DocumentElement("source")]
|
||||
public string Source { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("advisoryId")]
|
||||
[DocumentElement("advisoryId")]
|
||||
public string AdvisoryId { get; init; } = string.Empty;
|
||||
|
||||
[BsonElement("observations")]
|
||||
[DocumentElement("observations")]
|
||||
public IReadOnlyList<string> Observations { get; init; } = Array.Empty<string>();
|
||||
|
||||
[BsonElement("createdAt")]
|
||||
[DocumentElement("createdAt")]
|
||||
public DateTime CreatedAt { get; init; }
|
||||
|
||||
[BsonElement("normalized")]
|
||||
[DocumentElement("normalized")]
|
||||
public AdvisoryLinksetNormalizedDocument Normalized { get; init; } = new();
|
||||
}
|
||||
|
||||
internal sealed class AdvisoryLinksetNormalizedDocument
|
||||
{
|
||||
[BsonElement("purls")]
|
||||
[DocumentElement("purls")]
|
||||
public IReadOnlyList<string> Purls { get; init; } = Array.Empty<string>();
|
||||
|
||||
[BsonElement("versions")]
|
||||
[DocumentElement("versions")]
|
||||
public IReadOnlyList<string> Versions { get; init; } = Array.Empty<string>();
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ public sealed class OrchestratorTestWebAppFactory : WebApplicationFactory<Progra
|
||||
services.AddSingleton<IOptions<ConcelierOptions>>(_ => Microsoft.Extensions.Options.Options.Create(forcedOptions));
|
||||
|
||||
// Force Mongo storage options to a deterministic in-memory test DSN.
|
||||
services.PostConfigure<MongoStorageOptions>(opts =>
|
||||
services.PostConfigure<StorageOptions>(opts =>
|
||||
{
|
||||
opts.ConnectionString = "mongodb://localhost:27017/orch-tests";
|
||||
opts.DatabaseName = "orch-tests";
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
using StellaOps.Plugin;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Tests;
|
||||
|
||||
public class PluginLoaderTests
|
||||
{
|
||||
private sealed class NullServices : IServiceProvider
|
||||
{
|
||||
public object? GetService(Type serviceType) => null;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScansConnectorPluginsDirectory()
|
||||
{
|
||||
var services = new NullServices();
|
||||
using StellaOps.Plugin;
|
||||
|
||||
namespace StellaOps.Concelier.WebService.Tests;
|
||||
|
||||
public class PluginLoaderTests
|
||||
{
|
||||
private sealed class NullServices : IServiceProvider
|
||||
{
|
||||
public object? GetService(Type serviceType) => null;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScansConnectorPluginsDirectory()
|
||||
{
|
||||
var services = new NullServices();
|
||||
var catalog = new PluginCatalog().AddFromDirectory(Path.Combine(AppContext.BaseDirectory, "StellaOps.Concelier.PluginBinaries"));
|
||||
var plugins = catalog.GetAvailableConnectorPlugins(services);
|
||||
Assert.NotNull(plugins);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScansExporterPluginsDirectory()
|
||||
{
|
||||
var services = new NullServices();
|
||||
var plugins = catalog.GetAvailableConnectorPlugins(services);
|
||||
Assert.NotNull(plugins);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ScansExporterPluginsDirectory()
|
||||
{
|
||||
var services = new NullServices();
|
||||
var catalog = new PluginCatalog().AddFromDirectory(Path.Combine(AppContext.BaseDirectory, "StellaOps.Concelier.PluginBinaries"));
|
||||
var plugins = catalog.GetAvailableExporterPlugins(services);
|
||||
Assert.NotNull(plugins);
|
||||
}
|
||||
}
|
||||
var plugins = catalog.GetAvailableExporterPlugins(services);
|
||||
Assert.NotNull(plugins);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,10 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Mongo2Go;
|
||||
using StellaOps.Concelier.Bson;
|
||||
using StellaOps.Concelier.Bson.IO;
|
||||
using MongoDB.Driver;
|
||||
using StellaOps.Concelier.InMemoryRunner;
|
||||
using StellaOps.Concelier.Documents;
|
||||
using StellaOps.Concelier.Documents.IO;
|
||||
using StellaOps.Concelier.InMemoryDriver;
|
||||
using StellaOps.Concelier.Core.Attestation;
|
||||
using static StellaOps.Concelier.WebService.Program;
|
||||
using StellaOps.Concelier.Core.Events;
|
||||
@@ -63,7 +63,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
private static readonly SymmetricSecurityKey TestSigningKey = new(Encoding.UTF8.GetBytes(TestSigningSecret));
|
||||
|
||||
private readonly ITestOutputHelper _output;
|
||||
private MongoDbRunner _runner = null!;
|
||||
private InMemoryDbRunner _runner = null!;
|
||||
private Process? _externalMongo;
|
||||
private string? _externalMongoDataPath;
|
||||
private ConcelierApplicationFactory _factory = null!;
|
||||
@@ -377,7 +377,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
[Fact]
|
||||
public async Task AdvisoryChunksEndpoint_ReturnsParagraphAnchors()
|
||||
{
|
||||
var newestRaw = BsonDocument.Parse(
|
||||
var newestRaw = DocumentObject.Parse(
|
||||
"""
|
||||
{
|
||||
"summary": {
|
||||
@@ -391,7 +391,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
]
|
||||
}
|
||||
""");
|
||||
var olderRaw = BsonDocument.Parse(
|
||||
var olderRaw = DocumentObject.Parse(
|
||||
"""
|
||||
{
|
||||
"summary": {
|
||||
@@ -423,8 +423,8 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
|
||||
await SeedObservationDocumentsAsync(documents);
|
||||
await SeedAdvisoryRawDocumentsAsync(
|
||||
CreateAdvisoryRawDocument("tenant-a", "nvd", "tenant-a:chunk:newest", newerHash, newestRaw.DeepClone().AsBsonDocument),
|
||||
CreateAdvisoryRawDocument("tenant-a", "nvd", "tenant-a:chunk:older", olderHash, olderRaw.DeepClone().AsBsonDocument));
|
||||
CreateAdvisoryRawDocument("tenant-a", "nvd", "tenant-a:chunk:newest", newerHash, newestRaw.DeepClone().AsDocumentObject),
|
||||
CreateAdvisoryRawDocument("tenant-a", "nvd", "tenant-a:chunk:older", olderHash, olderRaw.DeepClone().AsDocumentObject));
|
||||
|
||||
await SeedCanonicalAdvisoriesAsync(
|
||||
CreateStructuredAdvisory("CVE-2025-0001", "GHSA-2025-0001", "tenant-a:chunk:newest", newerCreatedAt));
|
||||
@@ -580,7 +580,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
vendor: "osv",
|
||||
upstreamId: "GHSA-VERIFY-ERR",
|
||||
contentHash: "sha256:verify-err",
|
||||
raw: new BsonDocument
|
||||
raw: new DocumentObject
|
||||
{
|
||||
{ "id", "GHSA-VERIFY-ERR" },
|
||||
{ "severity", "critical" }
|
||||
@@ -643,9 +643,9 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
public async Task AdvisoryEvidenceEndpoint_ReturnsDocumentsForCanonicalKey()
|
||||
{
|
||||
await SeedAdvisoryRawDocumentsAsync(
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-x", "GHSA-2025-0001", "sha256:001", new BsonDocument("id", "GHSA-2025-0001:1")),
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-y", "GHSA-2025-0001", "sha256:002", new BsonDocument("id", "GHSA-2025-0001:2")),
|
||||
CreateAdvisoryRawDocument("tenant-b", "vendor-x", "GHSA-2025-0001", "sha256:003", new BsonDocument("id", "GHSA-2025-0001:3")));
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-x", "GHSA-2025-0001", "sha256:001", new DocumentObject("id", "GHSA-2025-0001:1")),
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-y", "GHSA-2025-0001", "sha256:002", new DocumentObject("id", "GHSA-2025-0001:2")),
|
||||
CreateAdvisoryRawDocument("tenant-b", "vendor-x", "GHSA-2025-0001", "sha256:003", new DocumentObject("id", "GHSA-2025-0001:3")));
|
||||
|
||||
using var client = _factory.CreateClient();
|
||||
var response = await client.GetAsync("/vuln/evidence/advisories/ghsa-2025-0001?tenant=tenant-a");
|
||||
@@ -664,7 +664,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
public async Task AdvisoryEvidenceEndpoint_AttachesAttestationWhenBundleProvided()
|
||||
{
|
||||
await SeedAdvisoryRawDocumentsAsync(
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-x", "GHSA-2025-0003", "sha256:201", new BsonDocument("id", "GHSA-2025-0003:1")));
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-x", "GHSA-2025-0003", "sha256:201", new DocumentObject("id", "GHSA-2025-0003:1")));
|
||||
|
||||
var repoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..", "..", "..", ".."));
|
||||
var sampleDir = Path.Combine(repoRoot, "docs", "samples", "evidence-bundle");
|
||||
@@ -750,8 +750,8 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
public async Task AdvisoryEvidenceEndpoint_FiltersByVendor()
|
||||
{
|
||||
await SeedAdvisoryRawDocumentsAsync(
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-x", "GHSA-2025-0002", "sha256:101", new BsonDocument("id", "GHSA-2025-0002:1")),
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-y", "GHSA-2025-0002", "sha256:102", new BsonDocument("id", "GHSA-2025-0002:2")));
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-x", "GHSA-2025-0002", "sha256:101", new DocumentObject("id", "GHSA-2025-0002:1")),
|
||||
CreateAdvisoryRawDocument("tenant-a", "vendor-y", "GHSA-2025-0002", "sha256:102", new DocumentObject("id", "GHSA-2025-0002:2")));
|
||||
|
||||
using var client = _factory.CreateClient();
|
||||
var response = await client.GetAsync("/vuln/evidence/advisories/GHSA-2025-0002?tenant=tenant-a&vendor=vendor-y");
|
||||
@@ -852,7 +852,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
[Fact]
|
||||
public async Task AdvisoryChunksEndpoint_EmitsGuardrailMetrics()
|
||||
{
|
||||
var raw = BsonDocument.Parse("{\"details\":\"tiny\"}");
|
||||
var raw = DocumentObject.Parse("{\"details\":\"tiny\"}");
|
||||
var document = CreateChunkObservationDocument(
|
||||
"tenant-a:chunk:1",
|
||||
"tenant-a",
|
||||
@@ -1734,7 +1734,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
|
||||
private async Task SeedObservationDocumentsAsync(IEnumerable<AdvisoryObservationDocument> documents)
|
||||
{
|
||||
var client = new MongoClient(_runner.ConnectionString);
|
||||
var client = new InMemoryClient(_runner.ConnectionString);
|
||||
var database = client.GetDatabase(MongoStorageDefaults.DefaultDatabaseName);
|
||||
var collection = database.GetCollection<AdvisoryObservationDocument>(MongoStorageDefaults.Collections.AdvisoryObservations);
|
||||
|
||||
@@ -1742,7 +1742,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
{
|
||||
await database.DropCollectionAsync(MongoStorageDefaults.Collections.AdvisoryObservations);
|
||||
}
|
||||
catch (MongoCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
|
||||
catch (StorageCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Collection does not exist yet; ignore.
|
||||
}
|
||||
@@ -1762,7 +1762,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
doc.Source.Vendor,
|
||||
doc.Id,
|
||||
doc.Upstream.ContentHash,
|
||||
doc.Content.Raw.DeepClone().AsBsonDocument))
|
||||
doc.Content.Raw.DeepClone().AsDocumentObject))
|
||||
.ToArray();
|
||||
|
||||
await SeedAdvisoryRawDocumentsAsync(rawDocuments);
|
||||
@@ -1770,7 +1770,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
|
||||
private async Task SeedLinksetDocumentsAsync(IEnumerable<AdvisoryLinksetDocument> documents)
|
||||
{
|
||||
var client = new MongoClient(_runner.ConnectionString);
|
||||
var client = new InMemoryClient(_runner.ConnectionString);
|
||||
var database = client.GetDatabase(MongoStorageDefaults.DefaultDatabaseName);
|
||||
var collection = database.GetCollection<AdvisoryLinksetDocument>(MongoStorageDefaults.Collections.AdvisoryLinksets);
|
||||
|
||||
@@ -1778,7 +1778,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
{
|
||||
await database.DropCollectionAsync(MongoStorageDefaults.Collections.AdvisoryLinksets);
|
||||
}
|
||||
catch (MongoCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
|
||||
catch (StorageCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Collection not created yet; safe to ignore.
|
||||
}
|
||||
@@ -1882,7 +1882,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
{
|
||||
Format = "csaf",
|
||||
SpecVersion = "2.0",
|
||||
Raw = BsonDocument.Parse("""{"observation":"%ID%"}""".Replace("%ID%", id)),
|
||||
Raw = DocumentObject.Parse("""{"observation":"%ID%"}""".Replace("%ID%", id)),
|
||||
Metadata = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
},
|
||||
Linkset = new AdvisoryObservationLinksetDocument
|
||||
@@ -1909,14 +1909,14 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
string tenant,
|
||||
DateTime createdAt,
|
||||
string alias,
|
||||
BsonDocument rawDocument)
|
||||
DocumentObject rawDocument)
|
||||
{
|
||||
var document = CreateObservationDocument(
|
||||
id,
|
||||
tenant,
|
||||
createdAt,
|
||||
aliases: new[] { alias });
|
||||
var clone = rawDocument.DeepClone().AsBsonDocument;
|
||||
var clone = rawDocument.DeepClone().AsDocumentObject;
|
||||
document.Content.Raw = clone;
|
||||
document.Upstream.ContentHash = ComputeContentHash(clone);
|
||||
return document;
|
||||
@@ -1925,7 +1925,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
private static readonly DateTimeOffset DefaultIngestTimestamp = new(2025, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
private static readonly ICryptoHash Hash = CryptoHashFactory.CreateDefault();
|
||||
|
||||
private static string ComputeContentHash(BsonDocument rawDocument)
|
||||
private static string ComputeContentHash(DocumentObject rawDocument)
|
||||
{
|
||||
var canonical = rawDocument.ToJson(new JsonWriterSettings
|
||||
{
|
||||
@@ -2363,16 +2363,16 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
|
||||
using var validationScope = _factory.Services.CreateScope();
|
||||
var database = validationScope.ServiceProvider.GetRequiredService<IMongoDatabase>();
|
||||
var statements = database.GetCollection<BsonDocument>(MongoStorageDefaults.Collections.AdvisoryStatements);
|
||||
var statements = database.GetCollection<DocumentObject>(MongoStorageDefaults.Collections.AdvisoryStatements);
|
||||
|
||||
var stored = await statements
|
||||
.Find(Builders<BsonDocument>.Filter.Eq("_id", statementId.ToString()))
|
||||
.Find(Builders<DocumentObject>.Filter.Eq("_id", statementId.ToString()))
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
Assert.NotNull(stored);
|
||||
var dsse = stored!["provenance"].AsBsonDocument["dsse"].AsBsonDocument;
|
||||
var dsse = stored!["provenance"].AsDocumentObject["dsse"].AsDocumentObject;
|
||||
Assert.Equal("sha256:feedface", dsse["envelopeDigest"].AsString);
|
||||
var trustDoc = stored["trust"].AsBsonDocument;
|
||||
var trustDoc = stored["trust"].AsDocumentObject;
|
||||
Assert.True(trustDoc["verified"].AsBoolean);
|
||||
Assert.Equal("Authority@stella", trustDoc["verifier"].AsString);
|
||||
}
|
||||
@@ -2380,8 +2380,8 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
{
|
||||
using var cleanupScope = _factory.Services.CreateScope();
|
||||
var database = cleanupScope.ServiceProvider.GetRequiredService<IMongoDatabase>();
|
||||
var statements = database.GetCollection<BsonDocument>(MongoStorageDefaults.Collections.AdvisoryStatements);
|
||||
await statements.DeleteOneAsync(Builders<BsonDocument>.Filter.Eq("_id", statementId.ToString()));
|
||||
var statements = database.GetCollection<DocumentObject>(MongoStorageDefaults.Collections.AdvisoryStatements);
|
||||
await statements.DeleteOneAsync(Builders<DocumentObject>.Filter.Eq("_id", statementId.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2484,7 +2484,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
{
|
||||
await database.DropCollectionAsync(collectionName);
|
||||
}
|
||||
catch (MongoCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
|
||||
catch (StorageCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -2573,34 +2573,34 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
return advisory;
|
||||
}
|
||||
|
||||
private async Task SeedAdvisoryRawDocumentsAsync(params BsonDocument[] documents)
|
||||
private async Task SeedAdvisoryRawDocumentsAsync(params DocumentObject[] documents)
|
||||
{
|
||||
var client = new MongoClient(_runner.ConnectionString);
|
||||
var client = new InMemoryClient(_runner.ConnectionString);
|
||||
var database = client.GetDatabase(MongoStorageDefaults.DefaultDatabaseName);
|
||||
var collection = database.GetCollection<BsonDocument>(MongoStorageDefaults.Collections.AdvisoryRaw);
|
||||
await collection.DeleteManyAsync(FilterDefinition<BsonDocument>.Empty);
|
||||
var collection = database.GetCollection<DocumentObject>(MongoStorageDefaults.Collections.AdvisoryRaw);
|
||||
await collection.DeleteManyAsync(FilterDefinition<DocumentObject>.Empty);
|
||||
if (documents.Length > 0)
|
||||
{
|
||||
await collection.InsertManyAsync(documents);
|
||||
}
|
||||
}
|
||||
|
||||
private static BsonDocument CreateAdvisoryRawDocument(
|
||||
private static DocumentObject CreateAdvisoryRawDocument(
|
||||
string tenant,
|
||||
string vendor,
|
||||
string upstreamId,
|
||||
string contentHash,
|
||||
BsonDocument? raw = null,
|
||||
DocumentObject? raw = null,
|
||||
string? supersedes = null)
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
return new BsonDocument
|
||||
return new DocumentObject
|
||||
{
|
||||
{ "_id", BuildRawDocumentId(vendor, upstreamId, contentHash) },
|
||||
{ "tenant", tenant },
|
||||
{
|
||||
"source",
|
||||
new BsonDocument
|
||||
new DocumentObject
|
||||
{
|
||||
{ "vendor", vendor },
|
||||
{ "connector", "test-connector" },
|
||||
@@ -2609,57 +2609,57 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
},
|
||||
{
|
||||
"upstream",
|
||||
new BsonDocument
|
||||
new DocumentObject
|
||||
{
|
||||
{ "upstream_id", upstreamId },
|
||||
{ "document_version", "1" },
|
||||
{ "retrieved_at", now },
|
||||
{ "content_hash", contentHash },
|
||||
{ "signature", new BsonDocument { { "present", false } } },
|
||||
{ "provenance", new BsonDocument { { "api", "https://example.test" } } }
|
||||
{ "signature", new DocumentObject { { "present", false } } },
|
||||
{ "provenance", new DocumentObject { { "api", "https://example.test" } } }
|
||||
}
|
||||
},
|
||||
{
|
||||
"content",
|
||||
new BsonDocument
|
||||
new DocumentObject
|
||||
{
|
||||
{ "format", "osv" },
|
||||
{ "raw", raw ?? new BsonDocument("id", upstreamId) }
|
||||
{ "raw", raw ?? new DocumentObject("id", upstreamId) }
|
||||
}
|
||||
},
|
||||
{
|
||||
"identifiers",
|
||||
new BsonDocument
|
||||
new DocumentObject
|
||||
{
|
||||
{ "aliases", new BsonArray(new[] { upstreamId }) },
|
||||
{ "aliases", new DocumentArray(new[] { upstreamId }) },
|
||||
{ "primary", upstreamId }
|
||||
}
|
||||
},
|
||||
{
|
||||
"linkset",
|
||||
new BsonDocument
|
||||
new DocumentObject
|
||||
{
|
||||
{ "aliases", new BsonArray() },
|
||||
{ "purls", new BsonArray() },
|
||||
{ "cpes", new BsonArray() },
|
||||
{ "references", new BsonArray() },
|
||||
{ "reconciled_from", new BsonArray() },
|
||||
{ "notes", new BsonDocument() }
|
||||
{ "aliases", new DocumentArray() },
|
||||
{ "purls", new DocumentArray() },
|
||||
{ "cpes", new DocumentArray() },
|
||||
{ "references", new DocumentArray() },
|
||||
{ "reconciled_from", new DocumentArray() },
|
||||
{ "notes", new DocumentObject() }
|
||||
}
|
||||
},
|
||||
{ "advisory_key", upstreamId.ToUpperInvariant() },
|
||||
{
|
||||
"links",
|
||||
new BsonArray
|
||||
new DocumentArray
|
||||
{
|
||||
new BsonDocument
|
||||
new DocumentObject
|
||||
{
|
||||
{ "scheme", "PRIMARY" },
|
||||
{ "value", upstreamId.ToUpperInvariant() }
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "supersedes", supersedes is null ? BsonNull.Value : supersedes },
|
||||
{ "supersedes", supersedes is null ? DocumentNull.Value : supersedes },
|
||||
{ "ingested_at", now },
|
||||
{ "created_at", now }
|
||||
};
|
||||
@@ -2883,21 +2883,21 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
|
||||
}
|
||||
|
||||
// Small ping loop to ensure mongod is ready
|
||||
var client = new MongoClient($"mongodb://127.0.0.1:{port}");
|
||||
var client = new InMemoryClient($"mongodb://127.0.0.1:{port}");
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
while (sw.Elapsed < TimeSpan.FromSeconds(5))
|
||||
{
|
||||
try
|
||||
{
|
||||
client.GetDatabase("admin").RunCommand<BsonDocument>("{ ping: 1 }");
|
||||
client.GetDatabase("admin").RunCommand<DocumentObject>("{ ping: 1 }");
|
||||
// Initiate single-node replica set so features expecting replset work.
|
||||
client.GetDatabase("admin").RunCommand<BsonDocument>(BsonDocument.Parse("{ replSetInitiate: { _id: \"rs0\", members: [ { _id: 0, host: \"127.0.0.1:" + port + "\" } ] } }"));
|
||||
client.GetDatabase("admin").RunCommand<DocumentObject>(DocumentObject.Parse("{ replSetInitiate: { _id: \"rs0\", members: [ { _id: 0, host: \"127.0.0.1:" + port + "\" } ] } }"));
|
||||
// Wait for primary
|
||||
var readySw = System.Diagnostics.Stopwatch.StartNew();
|
||||
while (readySw.Elapsed < TimeSpan.FromSeconds(5))
|
||||
{
|
||||
var status = client.GetDatabase("admin").RunCommand<BsonDocument>(BsonDocument.Parse("{ replSetGetStatus: 1 }"));
|
||||
var myState = status["members"].AsBsonArray.FirstOrDefault(x => x["self"].AsBoolean);
|
||||
var status = client.GetDatabase("admin").RunCommand<DocumentObject>(DocumentObject.Parse("{ replSetGetStatus: 1 }"));
|
||||
var myState = status["members"].AsDocumentArray.FirstOrDefault(x => x["self"].AsBoolean);
|
||||
if (myState != null && myState["state"].ToInt32() == 1)
|
||||
{
|
||||
connectionString = $"mongodb://127.0.0.1:{port}/?replicaSet=rs0";
|
||||
|
||||
Reference in New Issue
Block a user