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

This commit is contained in:
StellaOps Bot
2025-12-13 00:20:26 +02:00
parent e1f1bef4c1
commit 564df71bfb
2376 changed files with 334389 additions and 328032 deletions

View File

@@ -1,72 +0,0 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Mongo2Go;
using MongoDB.Driver;
using StellaOps.Concelier.Core.Linksets;
using StellaOps.Concelier.Storage.Mongo.Linksets;
namespace StellaOps.Concelier.Storage.Mongo.Tests;
public sealed class AdvisoryLinksetStoreTests : IAsyncLifetime
{
private MongoDbRunner _runner = null!;
private IMongoDatabase _database = null!;
public Task InitializeAsync()
{
_runner = MongoDbRunner.Start(singleNodeReplSet: true);
var client = new MongoClient(_runner.ConnectionString);
_database = client.GetDatabase("lnm-store-tests");
return Task.CompletedTask;
}
public Task DisposeAsync()
{
_runner.Dispose();
return Task.CompletedTask;
}
[Fact]
public async Task UpsertAndFetch_RetainsCpesInNormalizedShape()
{
var collection = _database.GetCollection<AdvisoryLinksetDocument>(MongoStorageDefaults.Collections.AdvisoryLinksets);
var store = new ConcelierMongoLinksetStore(collection);
var linkset = new AdvisoryLinkset(
TenantId: "TenantA",
Source: "source-A",
AdvisoryId: "ADV-1234",
ObservationIds: ImmutableArray.Create("obs-1"),
Normalized: new AdvisoryLinksetNormalized(
Purls: new List<string> { "pkg:npm/lodash@4.17.21" },
Cpes: new List<string> { "cpe:2.3:a:lodash:lodash:4.17.21:*:*:*:*:*:*:*" },
Versions: new List<string> { "4.17.21" },
Ranges: new List<Dictionary<string, object?>>(),
Severities: null),
Provenance: null,
Confidence: null,
Conflicts: null,
CreatedAt: DateTimeOffset.Parse("2025-11-24T00:00:00Z"),
BuiltByJobId: "job-001");
await store.UpsertAsync(linkset, CancellationToken.None);
var result = await store.FindByTenantAsync(
tenantId: "TenantA",
advisoryIds: new[] { "ADV-1234" },
sources: new[] { "source-A" },
cursor: null,
limit: 10,
cancellationToken: CancellationToken.None);
result.Should().ContainSingle();
var returned = result.Single();
returned.Normalized.Should().NotBeNull();
returned.Normalized!.Cpes.Should().ContainSingle()
.Which.Should().Be("cpe:2.3:a:lodash:lodash:4.17.21:*:*:*:*:*:*:*");
}
}

View File

@@ -1,70 +0,0 @@
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Mongo2Go;
using MongoDB.Bson;
using MongoDB.Driver;
using StellaOps.Concelier.Storage.Mongo.Migrations;
namespace StellaOps.Concelier.Storage.Mongo.Tests;
public sealed class EnsureLinkNotMergeCollectionsMigrationTests : IAsyncLifetime
{
private MongoDbRunner _runner = null!;
private IMongoDatabase _database = null!;
public Task InitializeAsync()
{
_runner = MongoDbRunner.Start(singleNodeReplSet: true);
var client = new MongoClient(_runner.ConnectionString);
_database = client.GetDatabase("lnm-migration-tests");
return Task.CompletedTask;
}
public Task DisposeAsync()
{
_runner.Dispose();
return Task.CompletedTask;
}
[Fact]
public async Task CreatesCollectionsAndIndexesIdempotently()
{
var migration = new EnsureLinkNotMergeCollectionsMigration();
await migration.ApplyAsync(_database, CancellationToken.None);
await migration.ApplyAsync(_database, CancellationToken.None); // idempotent second run
var collections = await _database.ListCollectionNames().ToListAsync();
collections.Should().Contain(new[]
{
MongoStorageDefaults.Collections.AdvisoryObservations,
MongoStorageDefaults.Collections.AdvisoryLinksets
});
var linksetIndexes = await _database
.GetCollection<BsonDocument>(MongoStorageDefaults.Collections.AdvisoryLinksets)
.Indexes.List()
.ToListAsync();
linksetIndexes.Should().ContainSingle(i => i["name"] == "linkset_tenant_advisory_source" && i["unique"].AsBoolean);
var obsIndexes = await _database
.GetCollection<BsonDocument>(MongoStorageDefaults.Collections.AdvisoryObservations)
.Indexes.List()
.ToListAsync();
obsIndexes.Should().Contain(i => i["name"] == "obs_prov_sourceArtifactSha_unique" && i["unique"].AsBoolean);
var linksetValidator = await GetValidatorAsync(MongoStorageDefaults.Collections.AdvisoryLinksets);
linksetValidator.Should().NotBeNull();
}
private async Task<BsonDocument?> GetValidatorAsync(string collection)
{
var filter = new BsonDocument("name", collection);
var cursor = await _database.ListCollectionsAsync(new ListCollectionsOptions { Filter = filter });
var doc = await cursor.FirstOrDefaultAsync();
return doc?"options"?"validator"?.AsBsonDocument;
}
}

View File

@@ -1,67 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Mongo2Go;
using MongoDB.Bson;
using MongoDB.Driver;
using StellaOps.Concelier.Storage.Mongo.Migrations;
namespace StellaOps.Concelier.Storage.Mongo.Tests;
public sealed class EnsureOrchestratorCollectionsMigrationTests : IAsyncLifetime
{
private MongoDbRunner _runner = null!;
private IMongoDatabase _database = null!;
public Task InitializeAsync()
{
_runner = MongoDbRunner.Start(singleNodeReplSet: true);
var client = new MongoClient(_runner.ConnectionString);
_database = client.GetDatabase("orch-migration-tests");
return Task.CompletedTask;
}
public Task DisposeAsync()
{
_runner.Dispose();
return Task.CompletedTask;
}
[Fact]
public async Task CreatesOrchestratorCollectionsAndIndexes()
{
var migration = new EnsureOrchestratorCollectionsMigration();
await migration.ApplyAsync(_database, CancellationToken.None);
var collections = await _database.ListCollectionNames().ToListAsync();
collections.Should().Contain(
new[]
{
MongoStorageDefaults.Collections.OrchestratorRegistry,
MongoStorageDefaults.Collections.OrchestratorCommands,
MongoStorageDefaults.Collections.OrchestratorHeartbeats,
});
var registryIndexes = await GetIndexNamesAsync(MongoStorageDefaults.Collections.OrchestratorRegistry);
registryIndexes.Should().Contain("orch_registry_tenant_connector");
var commandIndexes = await GetIndexNamesAsync(MongoStorageDefaults.Collections.OrchestratorCommands);
commandIndexes.Should().Contain("orch_cmd_tenant_connector_run_seq");
commandIndexes.Should().Contain("orch_cmd_expiresAt_ttl");
var heartbeatIndexes = await GetIndexNamesAsync(MongoStorageDefaults.Collections.OrchestratorHeartbeats);
heartbeatIndexes.Should().Contain("orch_hb_tenant_connector_run_seq");
}
private async Task<IReadOnlyCollection<string>> GetIndexNamesAsync(string collection)
{
var docs = await _database.GetCollection<BsonDocument>(collection)
.Indexes
.List()
.ToListAsync();
return docs.Select(d => d["name"].AsString).ToArray();
}
}

View File

@@ -1,130 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using FluentAssertions;
using Mongo2Go;
using MongoDB.Driver;
using StellaOps.Concelier.Storage.Mongo.Migrations;
using StellaOps.Concelier.Storage.Mongo.Orchestrator;
namespace StellaOps.Concelier.Storage.Mongo.Tests;
public sealed class MongoOrchestratorRegistryStoreTests : IAsyncLifetime
{
private MongoDbRunner _runner = null!;
private IMongoDatabase _database = null!;
private MongoOrchestratorRegistryStore _store = null!;
public Task InitializeAsync()
{
_runner = MongoDbRunner.Start(singleNodeReplSet: true);
var client = new MongoClient(_runner.ConnectionString);
_database = client.GetDatabase("orch-store-tests");
// ensure collections/indexes present
var migration = new EnsureOrchestratorCollectionsMigration();
migration.ApplyAsync(_database, CancellationToken.None).GetAwaiter().GetResult();
_store = new MongoOrchestratorRegistryStore(
_database.GetCollection<OrchestratorRegistryDocument>(MongoStorageDefaults.Collections.OrchestratorRegistry),
_database.GetCollection<OrchestratorCommandDocument>(MongoStorageDefaults.Collections.OrchestratorCommands),
_database.GetCollection<OrchestratorHeartbeatDocument>(MongoStorageDefaults.Collections.OrchestratorHeartbeats));
return Task.CompletedTask;
}
public Task DisposeAsync()
{
_runner.Dispose();
return Task.CompletedTask;
}
[Fact]
public async Task UpsertAndFetchRegistryRoundTrips()
{
var record = new OrchestratorRegistryRecord(
Tenant: "tenant-a",
ConnectorId: "icscisa",
Source: "icscisa",
Capabilities: new[] { "observations", "linksets" },
AuthRef: "secret:concelier/icscisa/api-key",
Schedule: new OrchestratorSchedule("*/30 * * * *", "UTC", 1, 120),
RatePolicy: new OrchestratorRatePolicy(60, 10, 30),
ArtifactKinds: new[] { "raw-advisory", "linkset" },
LockKey: "concelier:tenant-a:icscisa",
EgressGuard: new OrchestratorEgressGuard(new[] { "icscert.kisa.or.kr" }, true),
CreatedAt: DateTimeOffset.Parse("2025-11-20T00:00:00Z"),
UpdatedAt: DateTimeOffset.Parse("2025-11-21T00:00:00Z"));
await _store.UpsertAsync(record, CancellationToken.None);
var fetched = await _store.GetAsync("tenant-a", "icscisa", CancellationToken.None);
fetched.Should().NotBeNull();
fetched!.ConnectorId.Should().Be("icscisa");
fetched.Schedule.Cron.Should().Be("*/30 * * * *");
fetched.RatePolicy.Burst.Should().Be(10);
fetched.EgressGuard.AirgapMode.Should().BeTrue();
}
[Fact]
public async Task EnqueueAndReadCommandsOrdersBySequence()
{
var runId = Guid.NewGuid();
var first = new OrchestratorCommandRecord(
Tenant: "tenant-a",
ConnectorId: "icscisa",
RunId: runId,
Sequence: 1,
Command: OrchestratorCommandKind.Pause,
Throttle: null,
Backfill: null,
CreatedAt: DateTimeOffset.Parse("2025-11-20T00:00:00Z"),
ExpiresAt: null);
var second = new OrchestratorCommandRecord(
Tenant: "tenant-a",
ConnectorId: "icscisa",
RunId: runId,
Sequence: 2,
Command: OrchestratorCommandKind.Backfill,
Throttle: null,
Backfill: new OrchestratorBackfillRange("2024-01-01T00:00:00Z", "2024-02-01T00:00:00Z"),
CreatedAt: DateTimeOffset.Parse("2025-11-20T00:01:00Z"),
ExpiresAt: null);
await _store.EnqueueCommandAsync(second, CancellationToken.None);
await _store.EnqueueCommandAsync(first, CancellationToken.None);
var commands = await _store.GetPendingCommandsAsync("tenant-a", "icscisa", runId, afterSequence: 0, CancellationToken.None);
commands.Select(c => c.Sequence).Should().ContainInOrder(1, 2);
commands.Last().Backfill!.FromCursor.Should().Be("2024-01-01T00:00:00Z");
}
[Fact]
public async Task AppendsHeartbeats()
{
var heartbeat = new OrchestratorHeartbeatRecord(
Tenant: "tenant-a",
ConnectorId: "icscisa",
RunId: Guid.NewGuid(),
Sequence: 5,
Status: OrchestratorHeartbeatStatus.Running,
Progress: 42,
QueueDepth: 7,
LastArtifactHash: "abc",
LastArtifactKind: "normalized",
ErrorCode: null,
RetryAfterSeconds: null,
TimestampUtc: DateTimeOffset.Parse("2025-11-21T00:00:00Z"));
await _store.AppendHeartbeatAsync(heartbeat, CancellationToken.None);
var count = await _database
.GetCollection<OrchestratorHeartbeatDocument>(MongoStorageDefaults.Collections.OrchestratorHeartbeats)
.CountDocumentsAsync(FilterDefinition<OrchestratorHeartbeatDocument>.Empty);
count.Should().Be(1);
}
}

View File

@@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
<PackageReference Include="Mongo2Go" Version="4.1.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../../src/Concelier/__Libraries/StellaOps.Concelier.Models/StellaOps.Concelier.Models.csproj" />
</ItemGroup>
</Project>