using FluentAssertions; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using StellaOps.Auth.Abstractions; using StellaOps.Concelier.Core.Federation; using StellaOps.Concelier.Core.Jobs; using StellaOps.Concelier.Core.Observations; using StellaOps.Concelier.Core.Orchestration; using StellaOps.Concelier.Core.Raw; using StellaOps.Concelier.Core.Signals; using StellaOps.Concelier.Persistence.Postgres.Repositories; using StellaOps.Replay.Core.FeedSnapshot; using StellaOps.Concelier.WebService.Extensions; using StellaOps.Concelier.WebService.Services; using Moq; using System.Net.Http.Json; using System.Security.Cryptography; using System.Security.Claims; using System.Text.Json; using System.Text.Encodings.Web; using Xunit; namespace StellaOps.Concelier.WebService.Tests; public sealed class UnsupportedRuntimeWiringTests { [Fact] public void DevelopmentHost_ResolvesUnsupportedRuntimeServices() { using var factory = new UnsupportedRuntimeWebApplicationFactory(); using var scope = factory.Services.CreateScope(); scope.ServiceProvider.GetRequiredService().Should().BeOfType(); scope.ServiceProvider.GetRequiredService().Should().BeOfType(); scope.ServiceProvider.GetRequiredService().Should().BeOfType(); scope.ServiceProvider.GetRequiredService().Should().BeOfType(); scope.ServiceProvider.GetRequiredService().Should().BeOfType(); factory.HasJobSchedulerHostedService.Should().BeFalse(); } [Fact] public async Task DevelopmentHost_JobsEndpoint_ReturnsNotImplemented() { using var factory = new UnsupportedRuntimeWebApplicationFactory(); using var client = factory.CreateClient(); var response = await client.GetAsync("/jobs/definitions"); var body = await response.Content.ReadAsStringAsync(); response.StatusCode.Should().Be(System.Net.HttpStatusCode.NotImplemented); body.Should().Contain("NOT_IMPLEMENTED"); body.Should().Contain("durable backend implementation"); } [Fact] public async Task DevelopmentHost_SourceSyncEndpoint_ReturnsNotImplemented() { using var factory = new UnsupportedRuntimeWebApplicationFactory(); using var client = factory.CreateClient(); using var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/advisory-sources/nvd/sync"); request.Headers.Add(Program.TenantHeaderName, "tenant-a"); var response = await client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); response.StatusCode.Should().Be(System.Net.HttpStatusCode.NotImplemented); body.Should().Contain("NOT_IMPLEMENTED"); body.Should().Contain("durable backend implementation"); } [Fact] public async Task DevelopmentHost_BatchSourceSyncEndpoint_ReturnsNotImplemented() { using var factory = new UnsupportedRuntimeWebApplicationFactory(); using var client = factory.CreateClient(); using var request = new HttpRequestMessage(HttpMethod.Post, "/api/v1/advisory-sources/sync"); request.Headers.Add(Program.TenantHeaderName, "tenant-a"); var response = await client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); response.StatusCode.Should().Be(System.Net.HttpStatusCode.NotImplemented); body.Should().Contain("NOT_IMPLEMENTED"); body.Should().Contain("durable backend implementation"); } [Fact] public async Task DevelopmentHost_InternalOrchestratorEndpoint_ReturnsNotImplemented() { using var factory = new UnsupportedRuntimeWebApplicationFactory(); using var client = factory.CreateClient(); using var request = new HttpRequestMessage( HttpMethod.Get, $"/internal/orch/commands?connectorId=nvd&runId={Guid.NewGuid()}"); request.Headers.Add(Program.TenantHeaderName, "tenant-a"); var response = await client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); response.StatusCode.Should().Be(System.Net.HttpStatusCode.NotImplemented); body.Should().Contain("NOT_IMPLEMENTED"); body.Should().Contain("orchestrator registry"); } [Fact] public async Task DevelopmentHost_ConfigSeededMirrorEndpoints_IgnoreConfiguredDomains() { using var temp = new TemporaryDirectory(); var exportId = "20251019T120000Z"; var domainRoot = Path.Combine(temp.Path, exportId, "mirror", "primary"); Directory.CreateDirectory(domainRoot); await File.WriteAllTextAsync( Path.Combine(temp.Path, exportId, "mirror", "index.json"), """{"schemaVersion":1,"domains":[{"id":"primary"}]}"""); await File.WriteAllTextAsync( Path.Combine(domainRoot, "manifest.json"), """{"domainId":"primary"}"""); using var factory = new UnsupportedRuntimeWebApplicationFactory(new Dictionary { ["CONCELIER_MIRROR__ENABLED"] = "true", ["CONCELIER_MIRROR__EXPORTROOT"] = temp.Path, ["CONCELIER_MIRROR__ACTIVEEXPORTID"] = exportId, ["CONCELIER_MIRROR__DOMAINS__0__ID"] = "primary", ["CONCELIER_MIRROR__DOMAINS__0__REQUIREAUTHENTICATION"] = "false", ["CONCELIER_MIRROR__MAXINDEXREQUESTSPERHOUR"] = "5", }); using var client = factory.CreateClient(); using var indexRequest = new HttpRequestMessage(HttpMethod.Get, "/concelier/exports/index.json"); indexRequest.Headers.Add(Program.TenantHeaderName, "tenant-a"); var indexResponse = await client.SendAsync(indexRequest); using var manifestRequest = new HttpRequestMessage(HttpMethod.Get, "/concelier/exports/mirror/primary/manifest.json"); manifestRequest.Headers.Add(Program.TenantHeaderName, "tenant-a"); var manifestResponse = await client.SendAsync(manifestRequest); indexResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.NotFound); manifestResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.NotFound); } [Fact] public async Task DevelopmentHost_MirrorImportEndpoints_ImportBundleAndExposeMirrorArtifacts() { using var source = new TemporaryDirectory(); using var exportRoot = new TemporaryDirectory(); var exportId = "mirror-import-proof"; var bundleJson = """ { "schemaVersion": 1, "generatedAt": "2026-04-18T00:00:00Z", "domainId": "primary", "displayName": "Primary", "exportFormat": "JSON", "sourceIds": ["nvd"], "advisories": [ { "id": "CVE-2026-0001" } ] } """; var bundlePath = Path.Combine(source.Path, "bundle.json"); await File.WriteAllTextAsync(bundlePath, bundleJson); var bundleDigest = Convert.ToHexString(SHA256.HashData(await File.ReadAllBytesAsync(bundlePath))).ToLowerInvariant(); var manifestJson = $$""" { "domainId": "primary", "displayName": "Primary", "generatedAt": "2026-04-18T00:00:00Z", "exports": [ { "key": "primary", "exportId": "primary", "format": "JSON", "artifactSizeBytes": {{new FileInfo(bundlePath).Length}}, "artifactDigest": "sha256:{{bundleDigest}}" } ] } """; await File.WriteAllTextAsync(Path.Combine(source.Path, "manifest.json"), manifestJson); using var factory = new UnsupportedRuntimeWebApplicationFactory(new Dictionary { ["CONCELIER_MIRROR__ENABLED"] = "true", ["CONCELIER_MIRROR__EXPORTROOT"] = exportRoot.Path, ["CONCELIER_MIRROR__IMPORTROOT"] = source.Path, ["CONCELIER_MIRROR__ACTIVEEXPORTID"] = exportId, }); using var client = factory.CreateClient(); using var importRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/advisory-sources/mirror/import") { Content = JsonContent.Create(new { bundlePath = source.Path }) }; importRequest.Headers.Add(Program.TenantHeaderName, "tenant-a"); var importResponse = await client.SendAsync(importRequest); var importBody = await importResponse.Content.ReadAsStringAsync(); using var statusRequest = new HttpRequestMessage(HttpMethod.Get, "/api/v1/advisory-sources/mirror/import/status"); statusRequest.Headers.Add(Program.TenantHeaderName, "tenant-a"); var statusResponse = await client.SendAsync(statusRequest); var statusBody = await statusResponse.Content.ReadAsStringAsync(); using var manifestRequest = new HttpRequestMessage(HttpMethod.Get, "/concelier/exports/mirror/primary/manifest.json"); manifestRequest.Headers.Add(Program.TenantHeaderName, "tenant-a"); var manifestResponse = await client.SendAsync(manifestRequest); var manifestBody = await manifestResponse.Content.ReadAsStringAsync(); importResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.OK, importBody); importBody.Should().Contain("completed"); statusResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.OK, statusBody); statusBody.Should().Contain("\"hasImport\":true"); statusBody.Should().Contain("\"status\":\"completed\""); statusBody.Should().Contain("\"domainId\":\"primary\""); statusBody.Should().Contain("Detached JWS signature was not found"); manifestResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.OK, manifestBody); using var manifestDocument = JsonDocument.Parse(manifestBody); manifestDocument.RootElement.GetProperty("domainId").GetString().Should().Be("primary"); } [Fact] public async Task DevelopmentHost_MirrorImportEndpoints_RejectChecksumMismatch() { using var source = new TemporaryDirectory(); using var exportRoot = new TemporaryDirectory(); var bundlePath = Path.Combine(source.Path, "bundle.json"); await File.WriteAllTextAsync( bundlePath, """ { "schemaVersion": 1, "generatedAt": "2026-04-18T00:00:00Z", "domainId": "primary", "displayName": "Primary", "exportFormat": "JSON", "sourceIds": ["nvd"], "advisories": [] } """); var bundleLength = new FileInfo(bundlePath).Length; await File.WriteAllTextAsync( Path.Combine(source.Path, "manifest.json"), $$""" { "domainId": "primary", "displayName": "Primary", "generatedAt": "2026-04-18T00:00:00Z", "exports": [ { "key": "primary", "exportId": "primary", "format": "JSON", "artifactSizeBytes": {{bundleLength}}, "artifactDigest": "sha256:deadbeef" } ] } """); using var factory = new UnsupportedRuntimeWebApplicationFactory(new Dictionary { ["CONCELIER_MIRROR__ENABLED"] = "true", ["CONCELIER_MIRROR__EXPORTROOT"] = exportRoot.Path, ["CONCELIER_MIRROR__IMPORTROOT"] = source.Path, ["CONCELIER_MIRROR__ACTIVEEXPORTID"] = "mirror-import-failure", }); using var client = factory.CreateClient(); using var importRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/advisory-sources/mirror/import") { Content = JsonContent.Create(new { bundlePath = source.Path }) }; importRequest.Headers.Add(Program.TenantHeaderName, "tenant-a"); var importResponse = await client.SendAsync(importRequest); var importBody = await importResponse.Content.ReadAsStringAsync(); using var statusRequest = new HttpRequestMessage(HttpMethod.Get, "/api/v1/advisory-sources/mirror/import/status"); statusRequest.Headers.Add(Program.TenantHeaderName, "tenant-a"); var statusResponse = await client.SendAsync(statusRequest); var statusBody = await statusResponse.Content.ReadAsStringAsync(); importResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest, importBody); importBody.Should().Contain("\"status\":\"failed\""); importBody.Should().Contain("digest mismatch"); statusResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.OK, statusBody); statusBody.Should().Contain("\"status\":\"failed\""); statusBody.Should().Contain("digest mismatch"); } [Fact] public async Task DevelopmentHost_MirrorImportEndpoints_RejectPathsOutsideAllowlistedImportRoot() { using var source = new TemporaryDirectory(); using var importRoot = new TemporaryDirectory(); using var exportRoot = new TemporaryDirectory(); await File.WriteAllTextAsync( Path.Combine(source.Path, "bundle.json"), """ { "schemaVersion": 1, "generatedAt": "2026-04-18T00:00:00Z", "domainId": "primary", "displayName": "Primary", "exportFormat": "JSON", "sourceIds": ["nvd"], "advisories": [] } """); await File.WriteAllTextAsync( Path.Combine(source.Path, "manifest.json"), """ { "domainId": "primary", "displayName": "Primary", "generatedAt": "2026-04-18T00:00:00Z", "exports": [ { "key": "primary", "exportId": "primary", "format": "JSON", "artifactSizeBytes": 120, "artifactDigest": "sha256:deadbeef" } ] } """); using var factory = new UnsupportedRuntimeWebApplicationFactory(new Dictionary { ["CONCELIER_MIRROR__ENABLED"] = "true", ["CONCELIER_MIRROR__EXPORTROOT"] = exportRoot.Path, ["CONCELIER_MIRROR__IMPORTROOT"] = importRoot.Path, ["CONCELIER_MIRROR__ACTIVEEXPORTID"] = "mirror-import-allowlist", }); using var client = factory.CreateClient(); using var importRequest = new HttpRequestMessage(HttpMethod.Post, "/api/v1/advisory-sources/mirror/import") { Content = JsonContent.Create(new { bundlePath = source.Path }) }; importRequest.Headers.Add(Program.TenantHeaderName, "tenant-a"); var importResponse = await client.SendAsync(importRequest); var importBody = await importResponse.Content.ReadAsStringAsync(); importResponse.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest, importBody); importBody.Should().Contain("\"status\":\"failed\""); importBody.Should().Contain("must stay within the configured mirror import root"); } private sealed class UnsupportedRuntimeWebApplicationFactory : WebApplicationFactory { private readonly Dictionary _previousEnvironment = new(StringComparer.OrdinalIgnoreCase); public bool HasJobSchedulerHostedService { get; private set; } public UnsupportedRuntimeWebApplicationFactory(IReadOnlyDictionary? environmentOverrides = null) { SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__CONNECTIONSTRING", "Host=localhost;Port=5432;Database=concelier_test;Username=postgres;Password=postgres"); SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__ENABLED", "true"); SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__COMMANDTIMEOUTSECONDS", "30"); SetEnvironmentVariable("CONCELIER_POSTGRESSTORAGE__SCHEMANAME", "vuln"); SetEnvironmentVariable("CONCELIER_POSTGRES_DSN", "Host=localhost;Port=5432;Database=concelier_test;Username=postgres;Password=postgres"); SetEnvironmentVariable("CONCELIER_SKIP_OPTIONS_VALIDATION", "1"); SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLED", "false"); SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLELOGGING", "false"); SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLETRACING", "false"); SetEnvironmentVariable("CONCELIER_TELEMETRY__ENABLEMETRICS", "false"); SetEnvironmentVariable("CONCELIER_AUTHORITY__ENABLED", "false"); SetEnvironmentVariable("CONCELIER_AUTHORITY__REQUIREDSCOPES__0", "concelier.jobs.trigger"); SetEnvironmentVariable("DOTNET_ENVIRONMENT", "Production"); SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Production"); if (environmentOverrides is not null) { foreach (var entry in environmentOverrides) { SetEnvironmentVariable(entry.Key, entry.Value); } } } protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.UseEnvironment("Production"); builder.ConfigureServices(services => { HasJobSchedulerHostedService = services.Any(descriptor => descriptor.ServiceType == typeof(IHostedService) && descriptor.ImplementationType == typeof(JobSchedulerHostedService)); services.AddHttpContextAccessor(); services.AddAuthentication("Test") .AddScheme("Test", _ => { }) .AddScheme("StellaOpsBearer", _ => { }); services.AddAuthorization(options => { options.AddPolicy("Concelier.Sources.Manage", policy => policy.RequireAssertion(_ => true)); options.AddPolicy("Concelier.Advisories.Read", policy => policy.RequireAssertion(_ => true)); }); services.TryAddSingleton>(_ => () => Guid.Parse("11111111-1111-1111-1111-111111111111")); services.RemoveAll(); services.RemoveAll(); services.RemoveAll(); services.TryAddSingleton(Mock.Of()); services.TryAddSingleton(Mock.Of()); services.TryAddSingleton(Mock.Of()); services.TryAddSingleton(CreateFeedSnapshotCoordinator()); services.RemoveAll(); services.AddSingleton(); services.RemoveAll(); services.AddSingleton(); services.RemoveAll(); }); } protected override void Dispose(bool disposing) { if (disposing) { foreach (var entry in _previousEnvironment) { Environment.SetEnvironmentVariable(entry.Key, entry.Value); } } base.Dispose(disposing); } private void SetEnvironmentVariable(string name, string? value) { _previousEnvironment[name] = Environment.GetEnvironmentVariable(name); Environment.SetEnvironmentVariable(name, value); } private static IFeedSnapshotCoordinator CreateFeedSnapshotCoordinator() { var mock = new Mock(); mock.SetupGet(x => x.RegisteredSources).Returns(Array.Empty()); return mock.Object; } } private sealed class InMemoryMirrorDomainStore : IMirrorDomainStore { private readonly object _sync = new(); private readonly Dictionary _domains = new(StringComparer.OrdinalIgnoreCase); public IReadOnlyList GetAllDomains() { lock (_sync) { return _domains.Values.Select(Clone).ToArray(); } } public MirrorDomainRecord? GetDomain(string domainId) { lock (_sync) { return _domains.TryGetValue(domainId, out var domain) ? Clone(domain) : null; } } public Task SaveDomainAsync(MirrorDomainRecord domain, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); lock (_sync) { _domains[domain.Id] = Clone(domain); } return Task.CompletedTask; } public Task DeleteDomainAsync(string domainId, CancellationToken ct = default) { ct.ThrowIfCancellationRequested(); lock (_sync) { _domains.Remove(domainId); } return Task.CompletedTask; } private static MirrorDomainRecord Clone(MirrorDomainRecord domain) => new() { Id = domain.Id, DisplayName = domain.DisplayName, SourceIds = [.. domain.SourceIds], ExportFormat = domain.ExportFormat, RequireAuthentication = domain.RequireAuthentication, MaxIndexRequestsPerHour = domain.MaxIndexRequestsPerHour, MaxDownloadRequestsPerHour = domain.MaxDownloadRequestsPerHour, SigningEnabled = domain.SigningEnabled, SigningAlgorithm = domain.SigningAlgorithm, SigningKeyId = domain.SigningKeyId, Exports = domain.Exports .Select(export => new MirrorExportRecord { Key = export.Key, Format = export.Format, Filters = new Dictionary(export.Filters, StringComparer.Ordinal), }) .ToList(), CreatedAt = domain.CreatedAt, UpdatedAt = domain.UpdatedAt, LastGeneratedAt = domain.LastGeneratedAt, LastGenerateTriggeredAt = domain.LastGenerateTriggeredAt, BundleSizeBytes = domain.BundleSizeBytes, AdvisoryCount = domain.AdvisoryCount, }; } private sealed class InMemoryMirrorBundleImportStore : IMirrorBundleImportStore { private MirrorImportStatusRecord? _status; public MirrorImportStatusRecord? GetLatestStatus() => _status; public void SetStatus(MirrorImportStatusRecord status) => _status = status; } private sealed class TemporaryDirectory : IDisposable { public TemporaryDirectory() { Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "concelier-mirror-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(Path); } public string Path { get; } public void Dispose() { try { if (Directory.Exists(Path)) { Directory.Delete(Path, recursive: true); } } catch (IOException) { } catch (UnauthorizedAccessException) { } } } private sealed class AlwaysAllowAuthHandler : AuthenticationHandler { public AlwaysAllowAuthHandler( IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder) { } protected override Task HandleAuthenticateAsync() { var scopes = new[] { StellaOpsScopes.ConcelierJobsTrigger, StellaOpsScopes.AdvisoryRead, StellaOpsScopes.IntegrationWrite, StellaOpsScopes.IntegrationOperate, }; var identity = new ClaimsIdentity( [ new Claim(ClaimTypes.NameIdentifier, "unsupported-runtime"), new Claim(ClaimTypes.Name, "unsupported-runtime"), new Claim(StellaOpsClaimTypes.Tenant, "tenant-a"), new Claim(StellaOpsClaimTypes.Scope, string.Join(' ', scopes)), new Claim(StellaOpsClaimTypes.ScopeItem, StellaOpsScopes.ConcelierJobsTrigger), new Claim(StellaOpsClaimTypes.ScopeItem, StellaOpsScopes.AdvisoryRead), new Claim(StellaOpsClaimTypes.ScopeItem, StellaOpsScopes.IntegrationWrite), new Claim(StellaOpsClaimTypes.ScopeItem, StellaOpsScopes.IntegrationOperate), ], Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); return Task.FromResult(AuthenticateResult.Success(ticket)); } } }